11d3aed33SMarcel Moolenaar /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
33728855aSPedro F. Giffuni *
47ca4fa83SMarcel Moolenaar * Copyright (c) 2002, 2005-2009 Marcel Moolenaar
51d3aed33SMarcel Moolenaar * All rights reserved.
61d3aed33SMarcel Moolenaar *
71d3aed33SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without
81d3aed33SMarcel Moolenaar * modification, are permitted provided that the following conditions
91d3aed33SMarcel Moolenaar * are met:
101d3aed33SMarcel Moolenaar *
111d3aed33SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright
121d3aed33SMarcel Moolenaar * notice, this list of conditions and the following disclaimer.
131d3aed33SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright
141d3aed33SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the
151d3aed33SMarcel Moolenaar * documentation and/or other materials provided with the distribution.
161d3aed33SMarcel Moolenaar *
171d3aed33SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
181d3aed33SMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
191d3aed33SMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
201d3aed33SMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
211d3aed33SMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
221d3aed33SMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231d3aed33SMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241d3aed33SMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251d3aed33SMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
261d3aed33SMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271d3aed33SMarcel Moolenaar */
281d3aed33SMarcel Moolenaar
291d3aed33SMarcel Moolenaar #include <sys/param.h>
301d3aed33SMarcel Moolenaar #include <sys/bio.h>
311d3aed33SMarcel Moolenaar #include <sys/endian.h>
321d3aed33SMarcel Moolenaar #include <sys/kernel.h>
331d3aed33SMarcel Moolenaar #include <sys/kobj.h>
341d3aed33SMarcel Moolenaar #include <sys/limits.h>
351d3aed33SMarcel Moolenaar #include <sys/lock.h>
361d3aed33SMarcel Moolenaar #include <sys/malloc.h>
371d3aed33SMarcel Moolenaar #include <sys/mutex.h>
381d3aed33SMarcel Moolenaar #include <sys/queue.h>
391d3aed33SMarcel Moolenaar #include <sys/sbuf.h>
406e81b75aSAndrey V. Elsukov #include <sys/sysctl.h>
411d3aed33SMarcel Moolenaar #include <sys/systm.h>
421d3aed33SMarcel Moolenaar #include <sys/uuid.h>
431d3aed33SMarcel Moolenaar #include <geom/geom.h>
441d3aed33SMarcel Moolenaar #include <geom/geom_ctl.h>
454ffca444SMarcel Moolenaar #include <geom/geom_int.h>
461d3aed33SMarcel Moolenaar #include <geom/part/g_part.h>
471d3aed33SMarcel Moolenaar
481d3aed33SMarcel Moolenaar #include "g_part_if.h"
491d3aed33SMarcel Moolenaar
501d3aed33SMarcel Moolenaar static kobj_method_t g_part_null_methods[] = {
511d3aed33SMarcel Moolenaar { 0, 0 }
521d3aed33SMarcel Moolenaar };
531d3aed33SMarcel Moolenaar
541d3aed33SMarcel Moolenaar static struct g_part_scheme g_part_null_scheme = {
554ffca444SMarcel Moolenaar "(none)",
561d3aed33SMarcel Moolenaar g_part_null_methods,
571d3aed33SMarcel Moolenaar sizeof(struct g_part_table),
581d3aed33SMarcel Moolenaar };
591d3aed33SMarcel Moolenaar
604ffca444SMarcel Moolenaar TAILQ_HEAD(, g_part_scheme) g_part_schemes =
614ffca444SMarcel Moolenaar TAILQ_HEAD_INITIALIZER(g_part_schemes);
621d3aed33SMarcel Moolenaar
631d3aed33SMarcel Moolenaar struct g_part_alias_list {
641d3aed33SMarcel Moolenaar const char *lexeme;
651d3aed33SMarcel Moolenaar enum g_part_alias alias;
661d3aed33SMarcel Moolenaar } g_part_alias_list[G_PART_ALIAS_COUNT] = {
67b42712a8SConrad Meyer { "apple-apfs", G_PART_ALIAS_APPLE_APFS },
68f1317430SRui Paulo { "apple-boot", G_PART_ALIAS_APPLE_BOOT },
694fb4ebe0SAndrey V. Elsukov { "apple-core-storage", G_PART_ALIAS_APPLE_CORE_STORAGE },
7089ea4965SRui Paulo { "apple-hfs", G_PART_ALIAS_APPLE_HFS },
71f1317430SRui Paulo { "apple-label", G_PART_ALIAS_APPLE_LABEL },
72f1317430SRui Paulo { "apple-raid", G_PART_ALIAS_APPLE_RAID },
73f1317430SRui Paulo { "apple-raid-offline", G_PART_ALIAS_APPLE_RAID_OFFLINE },
74f1317430SRui Paulo { "apple-tv-recovery", G_PART_ALIAS_APPLE_TV_RECOVERY },
75f1317430SRui Paulo { "apple-ufs", G_PART_ALIAS_APPLE_UFS },
76cb1480f8SConrad Meyer { "apple-zfs", G_PART_ALIAS_APPLE_ZFS },
7788007f61SAndrey V. Elsukov { "bios-boot", G_PART_ALIAS_BIOS_BOOT },
789c0c355fSAllan Jude { "chromeos-firmware", G_PART_ALIAS_CHROMEOS_FIRMWARE },
799c0c355fSAllan Jude { "chromeos-kernel", G_PART_ALIAS_CHROMEOS_KERNEL },
809c0c355fSAllan Jude { "chromeos-reserved", G_PART_ALIAS_CHROMEOS_RESERVED },
819c0c355fSAllan Jude { "chromeos-root", G_PART_ALIAS_CHROMEOS_ROOT },
829c0c355fSAllan Jude { "dragonfly-ccd", G_PART_ALIAS_DFBSD_CCD },
839c0c355fSAllan Jude { "dragonfly-hammer", G_PART_ALIAS_DFBSD_HAMMER },
849c0c355fSAllan Jude { "dragonfly-hammer2", G_PART_ALIAS_DFBSD_HAMMER2 },
859c0c355fSAllan Jude { "dragonfly-label32", G_PART_ALIAS_DFBSD },
869c0c355fSAllan Jude { "dragonfly-label64", G_PART_ALIAS_DFBSD64 },
879c0c355fSAllan Jude { "dragonfly-legacy", G_PART_ALIAS_DFBSD_LEGACY },
889c0c355fSAllan Jude { "dragonfly-swap", G_PART_ALIAS_DFBSD_SWAP },
899c0c355fSAllan Jude { "dragonfly-ufs", G_PART_ALIAS_DFBSD_UFS },
909c0c355fSAllan Jude { "dragonfly-vinum", G_PART_ALIAS_DFBSD_VINUM },
9188007f61SAndrey V. Elsukov { "ebr", G_PART_ALIAS_EBR },
92d287f590SMarcel Moolenaar { "efi", G_PART_ALIAS_EFI },
9310f29053SGavin Atkinson { "fat16", G_PART_ALIAS_MS_FAT16 },
9488007f61SAndrey V. Elsukov { "fat32", G_PART_ALIAS_MS_FAT32 },
95b525a10aSEd Maste { "fat32lba", G_PART_ALIAS_MS_FAT32LBA },
96d287f590SMarcel Moolenaar { "freebsd", G_PART_ALIAS_FREEBSD },
97f352a0d4SJohn Baldwin { "freebsd-boot", G_PART_ALIAS_FREEBSD_BOOT },
98f24a8224SMarcel Moolenaar { "freebsd-nandfs", G_PART_ALIAS_FREEBSD_NANDFS },
99d287f590SMarcel Moolenaar { "freebsd-swap", G_PART_ALIAS_FREEBSD_SWAP },
100d287f590SMarcel Moolenaar { "freebsd-ufs", G_PART_ALIAS_FREEBSD_UFS },
101d287f590SMarcel Moolenaar { "freebsd-vinum", G_PART_ALIAS_FREEBSD_VINUM },
102a1fedf91SMarcel Moolenaar { "freebsd-zfs", G_PART_ALIAS_FREEBSD_ZFS },
1039c296a21SEd Maste { "hifive-fsbl", G_PART_ALIAS_HIFIVE_FSBL },
1049c296a21SEd Maste { "hifive-bbl", G_PART_ALIAS_HIFIVE_BBL },
105f1317430SRui Paulo { "linux-data", G_PART_ALIAS_LINUX_DATA },
106f1317430SRui Paulo { "linux-lvm", G_PART_ALIAS_LINUX_LVM },
107f1317430SRui Paulo { "linux-raid", G_PART_ALIAS_LINUX_RAID },
108f1317430SRui Paulo { "linux-swap", G_PART_ALIAS_LINUX_SWAP },
10988007f61SAndrey V. Elsukov { "mbr", G_PART_ALIAS_MBR },
11033f7a412SRui Paulo { "ms-basic-data", G_PART_ALIAS_MS_BASIC_DATA },
11133f7a412SRui Paulo { "ms-ldm-data", G_PART_ALIAS_MS_LDM_DATA },
11233f7a412SRui Paulo { "ms-ldm-metadata", G_PART_ALIAS_MS_LDM_METADATA },
1139c0c355fSAllan Jude { "ms-recovery", G_PART_ALIAS_MS_RECOVERY },
11433f7a412SRui Paulo { "ms-reserved", G_PART_ALIAS_MS_RESERVED },
1159c0c355fSAllan Jude { "ms-spaces", G_PART_ALIAS_MS_SPACES },
11633f7a412SRui Paulo { "netbsd-ccd", G_PART_ALIAS_NETBSD_CCD },
11733f7a412SRui Paulo { "netbsd-cgd", G_PART_ALIAS_NETBSD_CGD },
11833f7a412SRui Paulo { "netbsd-ffs", G_PART_ALIAS_NETBSD_FFS },
11933f7a412SRui Paulo { "netbsd-lfs", G_PART_ALIAS_NETBSD_LFS },
12033f7a412SRui Paulo { "netbsd-raid", G_PART_ALIAS_NETBSD_RAID },
12133f7a412SRui Paulo { "netbsd-swap", G_PART_ALIAS_NETBSD_SWAP },
1229c0c355fSAllan Jude { "ntfs", G_PART_ALIAS_MS_NTFS },
1239c0c355fSAllan Jude { "openbsd-data", G_PART_ALIAS_OPENBSD_DATA },
1249c0c355fSAllan Jude { "prep-boot", G_PART_ALIAS_PREP_BOOT },
125cb1480f8SConrad Meyer { "solaris-boot", G_PART_ALIAS_SOLARIS_BOOT },
126cb1480f8SConrad Meyer { "solaris-root", G_PART_ALIAS_SOLARIS_ROOT },
127cb1480f8SConrad Meyer { "solaris-swap", G_PART_ALIAS_SOLARIS_SWAP },
128cb1480f8SConrad Meyer { "solaris-backup", G_PART_ALIAS_SOLARIS_BACKUP },
129cb1480f8SConrad Meyer { "solaris-var", G_PART_ALIAS_SOLARIS_VAR },
130cb1480f8SConrad Meyer { "solaris-home", G_PART_ALIAS_SOLARIS_HOME },
131cb1480f8SConrad Meyer { "solaris-altsec", G_PART_ALIAS_SOLARIS_ALTSEC },
132cb1480f8SConrad Meyer { "solaris-reserved", G_PART_ALIAS_SOLARIS_RESERVED },
133b162fc3fSJessica Clarke { "u-boot-env", G_PART_ALIAS_U_BOOT_ENV },
1349c0c355fSAllan Jude { "vmware-reserved", G_PART_ALIAS_VMRESERVED },
135b20e4de3SDmitry Morozovsky { "vmware-vmfs", G_PART_ALIAS_VMFS },
136b20e4de3SDmitry Morozovsky { "vmware-vmkdiag", G_PART_ALIAS_VMKDIAG },
1375cc596c4SDmitry Morozovsky { "vmware-vsanhdr", G_PART_ALIAS_VMVSANHDR },
1381d3aed33SMarcel Moolenaar };
1391d3aed33SMarcel Moolenaar
1406e81b75aSAndrey V. Elsukov SYSCTL_DECL(_kern_geom);
1417029da5cSPawel Biernacki SYSCTL_NODE(_kern_geom, OID_AUTO, part, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
1426472ac3dSEd Schouten "GEOM_PART stuff");
143cea05ed9SEugene Grosbein u_int geom_part_check_integrity = 1;
144422783e3SAndrey V. Elsukov SYSCTL_UINT(_kern_geom_part, OID_AUTO, check_integrity,
145cea05ed9SEugene Grosbein CTLFLAG_RWTUN, &geom_part_check_integrity, 1,
146422783e3SAndrey V. Elsukov "Enable integrity checking");
14701ad653aSMariusz Zaborski static u_int auto_resize = 1;
14801ad653aSMariusz Zaborski SYSCTL_UINT(_kern_geom_part, OID_AUTO, auto_resize,
149c27fb0b5SMariusz Zaborski CTLFLAG_RWTUN, &auto_resize, 1,
15001ad653aSMariusz Zaborski "Enable auto resize");
151ef03f57dSKyle Evans static u_int allow_nesting = 0;
152ef03f57dSKyle Evans SYSCTL_UINT(_kern_geom_part, OID_AUTO, allow_nesting,
153ef03f57dSKyle Evans CTLFLAG_RWTUN, &allow_nesting, 0,
154ef03f57dSKyle Evans "Allow additional levels of nesting");
1552006d590SEdward Tomasz Napierala char g_part_separator[MAXPATHLEN] = "";
1562006d590SEdward Tomasz Napierala SYSCTL_STRING(_kern_geom_part, OID_AUTO, separator,
1572006d590SEdward Tomasz Napierala CTLFLAG_RDTUN, &g_part_separator, sizeof(g_part_separator),
1582006d590SEdward Tomasz Napierala "Partition name separator");
1596e81b75aSAndrey V. Elsukov
1601d3aed33SMarcel Moolenaar /*
1611d3aed33SMarcel Moolenaar * The GEOM partitioning class.
1621d3aed33SMarcel Moolenaar */
1631d3aed33SMarcel Moolenaar static g_ctl_req_t g_part_ctlreq;
1641d3aed33SMarcel Moolenaar static g_ctl_destroy_geom_t g_part_destroy_geom;
1654ffca444SMarcel Moolenaar static g_fini_t g_part_fini;
1664ffca444SMarcel Moolenaar static g_init_t g_part_init;
1671d3aed33SMarcel Moolenaar static g_taste_t g_part_taste;
1681d3aed33SMarcel Moolenaar
1691d3aed33SMarcel Moolenaar static g_access_t g_part_access;
1701d3aed33SMarcel Moolenaar static g_dumpconf_t g_part_dumpconf;
1711d3aed33SMarcel Moolenaar static g_orphan_t g_part_orphan;
1721d3aed33SMarcel Moolenaar static g_spoiled_t g_part_spoiled;
1731d3aed33SMarcel Moolenaar static g_start_t g_part_start;
174884c8e4fSAndrey V. Elsukov static g_resize_t g_part_resize;
17573f49e9eSWarner Losh static g_ioctl_t g_part_ioctl;
1761d3aed33SMarcel Moolenaar
1771d3aed33SMarcel Moolenaar static struct g_class g_part_class = {
1781d3aed33SMarcel Moolenaar .name = "PART",
1791d3aed33SMarcel Moolenaar .version = G_VERSION,
1801d3aed33SMarcel Moolenaar /* Class methods. */
1811d3aed33SMarcel Moolenaar .ctlreq = g_part_ctlreq,
1821d3aed33SMarcel Moolenaar .destroy_geom = g_part_destroy_geom,
1834ffca444SMarcel Moolenaar .fini = g_part_fini,
1844ffca444SMarcel Moolenaar .init = g_part_init,
1851d3aed33SMarcel Moolenaar .taste = g_part_taste,
1861d3aed33SMarcel Moolenaar /* Geom methods. */
1871d3aed33SMarcel Moolenaar .access = g_part_access,
1881d3aed33SMarcel Moolenaar .dumpconf = g_part_dumpconf,
1891d3aed33SMarcel Moolenaar .orphan = g_part_orphan,
1901d3aed33SMarcel Moolenaar .spoiled = g_part_spoiled,
1911d3aed33SMarcel Moolenaar .start = g_part_start,
19273f49e9eSWarner Losh .resize = g_part_resize,
19373f49e9eSWarner Losh .ioctl = g_part_ioctl,
1941d3aed33SMarcel Moolenaar };
1951d3aed33SMarcel Moolenaar
1961d3aed33SMarcel Moolenaar DECLARE_GEOM_CLASS(g_part_class, g_part);
1975284aff5SAndrey V. Elsukov MODULE_VERSION(g_part, 0);
1981d3aed33SMarcel Moolenaar
1991d3aed33SMarcel Moolenaar /*
2001d3aed33SMarcel Moolenaar * Support functions.
2011d3aed33SMarcel Moolenaar */
2021d3aed33SMarcel Moolenaar
2031d3aed33SMarcel Moolenaar static void g_part_wither(struct g_geom *, int);
2041d3aed33SMarcel Moolenaar
2051d3aed33SMarcel Moolenaar const char *
g_part_alias_name(enum g_part_alias alias)2061d3aed33SMarcel Moolenaar g_part_alias_name(enum g_part_alias alias)
2071d3aed33SMarcel Moolenaar {
2081d3aed33SMarcel Moolenaar int i;
2091d3aed33SMarcel Moolenaar
2101d3aed33SMarcel Moolenaar for (i = 0; i < G_PART_ALIAS_COUNT; i++) {
2111d3aed33SMarcel Moolenaar if (g_part_alias_list[i].alias != alias)
2121d3aed33SMarcel Moolenaar continue;
2131d3aed33SMarcel Moolenaar return (g_part_alias_list[i].lexeme);
2141d3aed33SMarcel Moolenaar }
2151d3aed33SMarcel Moolenaar
2161d3aed33SMarcel Moolenaar return (NULL);
2171d3aed33SMarcel Moolenaar }
2181d3aed33SMarcel Moolenaar
2190081f96eSMarcel Moolenaar void
g_part_geometry_heads(off_t blocks,u_int sectors,off_t * bestchs,u_int * bestheads)2200081f96eSMarcel Moolenaar g_part_geometry_heads(off_t blocks, u_int sectors, off_t *bestchs,
2210081f96eSMarcel Moolenaar u_int *bestheads)
2220081f96eSMarcel Moolenaar {
2230081f96eSMarcel Moolenaar static u_int candidate_heads[] = { 1, 2, 16, 32, 64, 128, 255, 0 };
2240081f96eSMarcel Moolenaar off_t chs, cylinders;
2250081f96eSMarcel Moolenaar u_int heads;
2260081f96eSMarcel Moolenaar int idx;
2270081f96eSMarcel Moolenaar
2280081f96eSMarcel Moolenaar *bestchs = 0;
2290081f96eSMarcel Moolenaar *bestheads = 0;
2300081f96eSMarcel Moolenaar for (idx = 0; candidate_heads[idx] != 0; idx++) {
2310081f96eSMarcel Moolenaar heads = candidate_heads[idx];
2320081f96eSMarcel Moolenaar cylinders = blocks / heads / sectors;
2330081f96eSMarcel Moolenaar if (cylinders < heads || cylinders < sectors)
2340081f96eSMarcel Moolenaar break;
2350081f96eSMarcel Moolenaar if (cylinders > 1023)
2360081f96eSMarcel Moolenaar continue;
2370081f96eSMarcel Moolenaar chs = cylinders * heads * sectors;
2380081f96eSMarcel Moolenaar if (chs > *bestchs || (chs == *bestchs && *bestheads == 1)) {
2390081f96eSMarcel Moolenaar *bestchs = chs;
2400081f96eSMarcel Moolenaar *bestheads = heads;
2410081f96eSMarcel Moolenaar }
2420081f96eSMarcel Moolenaar }
2430081f96eSMarcel Moolenaar }
2440081f96eSMarcel Moolenaar
2450081f96eSMarcel Moolenaar static void
g_part_geometry(struct g_part_table * table,struct g_consumer * cp,off_t blocks)2460081f96eSMarcel Moolenaar g_part_geometry(struct g_part_table *table, struct g_consumer *cp,
2470081f96eSMarcel Moolenaar off_t blocks)
2480081f96eSMarcel Moolenaar {
2490081f96eSMarcel Moolenaar static u_int candidate_sectors[] = { 1, 9, 17, 33, 63, 0 };
2500081f96eSMarcel Moolenaar off_t chs, bestchs;
2510081f96eSMarcel Moolenaar u_int heads, sectors;
2520081f96eSMarcel Moolenaar int idx;
2530081f96eSMarcel Moolenaar
2543d556594SMarcel Moolenaar if (g_getattr("GEOM::fwsectors", cp, §ors) != 0 || sectors == 0 ||
2553d556594SMarcel Moolenaar g_getattr("GEOM::fwheads", cp, &heads) != 0 || heads == 0) {
2560081f96eSMarcel Moolenaar table->gpt_fixgeom = 0;
2570081f96eSMarcel Moolenaar table->gpt_heads = 0;
2580081f96eSMarcel Moolenaar table->gpt_sectors = 0;
2590081f96eSMarcel Moolenaar bestchs = 0;
2600081f96eSMarcel Moolenaar for (idx = 0; candidate_sectors[idx] != 0; idx++) {
2610081f96eSMarcel Moolenaar sectors = candidate_sectors[idx];
2620081f96eSMarcel Moolenaar g_part_geometry_heads(blocks, sectors, &chs, &heads);
2630081f96eSMarcel Moolenaar if (chs == 0)
2640081f96eSMarcel Moolenaar continue;
2650081f96eSMarcel Moolenaar /*
2660081f96eSMarcel Moolenaar * Prefer a geometry with sectors > 1, but only if
26723f6856fSEd Maste * it doesn't bump down the number of heads to 1.
2680081f96eSMarcel Moolenaar */
2690081f96eSMarcel Moolenaar if (chs > bestchs || (chs == bestchs && heads > 1 &&
2700081f96eSMarcel Moolenaar table->gpt_sectors == 1)) {
2710081f96eSMarcel Moolenaar bestchs = chs;
2720081f96eSMarcel Moolenaar table->gpt_heads = heads;
2730081f96eSMarcel Moolenaar table->gpt_sectors = sectors;
2740081f96eSMarcel Moolenaar }
2750081f96eSMarcel Moolenaar }
2760081f96eSMarcel Moolenaar /*
2770081f96eSMarcel Moolenaar * If we didn't find a geometry at all, then the disk is
2780081f96eSMarcel Moolenaar * too big. This means we can use the maximum number of
2790081f96eSMarcel Moolenaar * heads and sectors.
2800081f96eSMarcel Moolenaar */
2810081f96eSMarcel Moolenaar if (bestchs == 0) {
2820081f96eSMarcel Moolenaar table->gpt_heads = 255;
2830081f96eSMarcel Moolenaar table->gpt_sectors = 63;
2840081f96eSMarcel Moolenaar }
2850081f96eSMarcel Moolenaar } else {
2860081f96eSMarcel Moolenaar table->gpt_fixgeom = 1;
2870081f96eSMarcel Moolenaar table->gpt_heads = heads;
2880081f96eSMarcel Moolenaar table->gpt_sectors = sectors;
2890081f96eSMarcel Moolenaar }
2900081f96eSMarcel Moolenaar }
2910081f96eSMarcel Moolenaar
29283406320SAlan Somers static void
g_part_get_physpath_done(struct bio * bp)29383406320SAlan Somers g_part_get_physpath_done(struct bio *bp)
29483406320SAlan Somers {
29583406320SAlan Somers struct g_geom *gp;
29683406320SAlan Somers struct g_part_entry *entry;
29783406320SAlan Somers struct g_part_table *table;
29883406320SAlan Somers struct g_provider *pp;
29983406320SAlan Somers struct bio *pbp;
30083406320SAlan Somers
30183406320SAlan Somers pbp = bp->bio_parent;
30283406320SAlan Somers pp = pbp->bio_to;
30383406320SAlan Somers gp = pp->geom;
30483406320SAlan Somers table = gp->softc;
30583406320SAlan Somers entry = pp->private;
30683406320SAlan Somers
30783406320SAlan Somers if (bp->bio_error == 0) {
30883406320SAlan Somers char *end;
30983406320SAlan Somers size_t len, remainder;
31083406320SAlan Somers len = strlcat(bp->bio_data, "/", bp->bio_length);
31183406320SAlan Somers if (len < bp->bio_length) {
31283406320SAlan Somers end = bp->bio_data + len;
31383406320SAlan Somers remainder = bp->bio_length - len;
31483406320SAlan Somers G_PART_NAME(table, entry, end, remainder);
31583406320SAlan Somers }
31683406320SAlan Somers }
31783406320SAlan Somers g_std_done(bp);
31883406320SAlan Somers }
31983406320SAlan Somers
320d0c8ecb8SAndrey V. Elsukov #define DPRINTF(...) if (bootverbose) { \
321d0c8ecb8SAndrey V. Elsukov printf("GEOM_PART: " __VA_ARGS__); \
322d0c8ecb8SAndrey V. Elsukov }
323d0c8ecb8SAndrey V. Elsukov
324c63e8fe2SAndrey V. Elsukov static int
g_part_check_integrity(struct g_part_table * table,struct g_consumer * cp)325c63e8fe2SAndrey V. Elsukov g_part_check_integrity(struct g_part_table *table, struct g_consumer *cp)
326c63e8fe2SAndrey V. Elsukov {
327c63e8fe2SAndrey V. Elsukov struct g_part_entry *e1, *e2;
328c63e8fe2SAndrey V. Elsukov struct g_provider *pp;
32938c64884SAndrey V. Elsukov off_t offset;
330d0c8ecb8SAndrey V. Elsukov int failed;
331c63e8fe2SAndrey V. Elsukov
332d0c8ecb8SAndrey V. Elsukov failed = 0;
333c63e8fe2SAndrey V. Elsukov pp = cp->provider;
334d0c8ecb8SAndrey V. Elsukov if (table->gpt_last < table->gpt_first) {
335d0c8ecb8SAndrey V. Elsukov DPRINTF("last LBA is below first LBA: %jd < %jd\n",
336d0c8ecb8SAndrey V. Elsukov (intmax_t)table->gpt_last, (intmax_t)table->gpt_first);
337d0c8ecb8SAndrey V. Elsukov failed++;
338d0c8ecb8SAndrey V. Elsukov }
339d0c8ecb8SAndrey V. Elsukov if (table->gpt_last > pp->mediasize / pp->sectorsize - 1) {
340d0c8ecb8SAndrey V. Elsukov DPRINTF("last LBA extends beyond mediasize: "
341d0c8ecb8SAndrey V. Elsukov "%jd > %jd\n", (intmax_t)table->gpt_last,
342d0c8ecb8SAndrey V. Elsukov (intmax_t)pp->mediasize / pp->sectorsize - 1);
343d0c8ecb8SAndrey V. Elsukov failed++;
344d0c8ecb8SAndrey V. Elsukov }
345c63e8fe2SAndrey V. Elsukov LIST_FOREACH(e1, &table->gpt_entry, gpe_entry) {
346c63e8fe2SAndrey V. Elsukov if (e1->gpe_deleted || e1->gpe_internal)
347c63e8fe2SAndrey V. Elsukov continue;
348d0c8ecb8SAndrey V. Elsukov if (e1->gpe_start < table->gpt_first) {
349d0c8ecb8SAndrey V. Elsukov DPRINTF("partition %d has start offset below first "
350d0c8ecb8SAndrey V. Elsukov "LBA: %jd < %jd\n", e1->gpe_index,
351d0c8ecb8SAndrey V. Elsukov (intmax_t)e1->gpe_start,
352d0c8ecb8SAndrey V. Elsukov (intmax_t)table->gpt_first);
353d0c8ecb8SAndrey V. Elsukov failed++;
354d0c8ecb8SAndrey V. Elsukov }
355d0c8ecb8SAndrey V. Elsukov if (e1->gpe_start > table->gpt_last) {
356d0c8ecb8SAndrey V. Elsukov DPRINTF("partition %d has start offset beyond last "
357d0c8ecb8SAndrey V. Elsukov "LBA: %jd > %jd\n", e1->gpe_index,
358d0c8ecb8SAndrey V. Elsukov (intmax_t)e1->gpe_start,
359d0c8ecb8SAndrey V. Elsukov (intmax_t)table->gpt_last);
360d0c8ecb8SAndrey V. Elsukov failed++;
361d0c8ecb8SAndrey V. Elsukov }
362d0c8ecb8SAndrey V. Elsukov if (e1->gpe_end < e1->gpe_start) {
363d0c8ecb8SAndrey V. Elsukov DPRINTF("partition %d has end offset below start "
364d0c8ecb8SAndrey V. Elsukov "offset: %jd < %jd\n", e1->gpe_index,
365d0c8ecb8SAndrey V. Elsukov (intmax_t)e1->gpe_end,
366d0c8ecb8SAndrey V. Elsukov (intmax_t)e1->gpe_start);
367d0c8ecb8SAndrey V. Elsukov failed++;
368d0c8ecb8SAndrey V. Elsukov }
369d0c8ecb8SAndrey V. Elsukov if (e1->gpe_end > table->gpt_last) {
370d0c8ecb8SAndrey V. Elsukov DPRINTF("partition %d has end offset beyond last "
371d0c8ecb8SAndrey V. Elsukov "LBA: %jd > %jd\n", e1->gpe_index,
372d0c8ecb8SAndrey V. Elsukov (intmax_t)e1->gpe_end,
373d0c8ecb8SAndrey V. Elsukov (intmax_t)table->gpt_last);
374d0c8ecb8SAndrey V. Elsukov failed++;
375d0c8ecb8SAndrey V. Elsukov }
37638c64884SAndrey V. Elsukov if (pp->stripesize > 0) {
37738c64884SAndrey V. Elsukov offset = e1->gpe_start * pp->sectorsize;
37838c64884SAndrey V. Elsukov if (e1->gpe_offset > offset)
37938c64884SAndrey V. Elsukov offset = e1->gpe_offset;
38038c64884SAndrey V. Elsukov if ((offset + pp->stripeoffset) % pp->stripesize) {
381da6c24e1SAndrey V. Elsukov DPRINTF("partition %d on (%s, %s) is not "
3826d305ab0SEugene Grosbein "aligned on %ju bytes\n", e1->gpe_index,
383da6c24e1SAndrey V. Elsukov pp->name, table->gpt_scheme->name,
3846d305ab0SEugene Grosbein (uintmax_t)pp->stripesize);
38538c64884SAndrey V. Elsukov /* Don't treat this as a critical failure */
38638c64884SAndrey V. Elsukov }
38738c64884SAndrey V. Elsukov }
388c63e8fe2SAndrey V. Elsukov e2 = e1;
389c63e8fe2SAndrey V. Elsukov while ((e2 = LIST_NEXT(e2, gpe_entry)) != NULL) {
390c63e8fe2SAndrey V. Elsukov if (e2->gpe_deleted || e2->gpe_internal)
391c63e8fe2SAndrey V. Elsukov continue;
392c63e8fe2SAndrey V. Elsukov if (e1->gpe_start >= e2->gpe_start &&
393d0c8ecb8SAndrey V. Elsukov e1->gpe_start <= e2->gpe_end) {
394d0c8ecb8SAndrey V. Elsukov DPRINTF("partition %d has start offset inside "
395d0c8ecb8SAndrey V. Elsukov "partition %d: start[%d] %jd >= start[%d] "
396d0c8ecb8SAndrey V. Elsukov "%jd <= end[%d] %jd\n",
397d0c8ecb8SAndrey V. Elsukov e1->gpe_index, e2->gpe_index,
398d0c8ecb8SAndrey V. Elsukov e2->gpe_index, (intmax_t)e2->gpe_start,
399d0c8ecb8SAndrey V. Elsukov e1->gpe_index, (intmax_t)e1->gpe_start,
400d0c8ecb8SAndrey V. Elsukov e2->gpe_index, (intmax_t)e2->gpe_end);
401d0c8ecb8SAndrey V. Elsukov failed++;
402d0c8ecb8SAndrey V. Elsukov }
403c63e8fe2SAndrey V. Elsukov if (e1->gpe_end >= e2->gpe_start &&
404d0c8ecb8SAndrey V. Elsukov e1->gpe_end <= e2->gpe_end) {
405d0c8ecb8SAndrey V. Elsukov DPRINTF("partition %d has end offset inside "
406d0c8ecb8SAndrey V. Elsukov "partition %d: start[%d] %jd >= end[%d] "
407d0c8ecb8SAndrey V. Elsukov "%jd <= end[%d] %jd\n",
408d0c8ecb8SAndrey V. Elsukov e1->gpe_index, e2->gpe_index,
409d0c8ecb8SAndrey V. Elsukov e2->gpe_index, (intmax_t)e2->gpe_start,
410d0c8ecb8SAndrey V. Elsukov e1->gpe_index, (intmax_t)e1->gpe_end,
411d0c8ecb8SAndrey V. Elsukov e2->gpe_index, (intmax_t)e2->gpe_end);
412d0c8ecb8SAndrey V. Elsukov failed++;
413d0c8ecb8SAndrey V. Elsukov }
414c63e8fe2SAndrey V. Elsukov if (e1->gpe_start < e2->gpe_start &&
415d0c8ecb8SAndrey V. Elsukov e1->gpe_end > e2->gpe_end) {
416d0c8ecb8SAndrey V. Elsukov DPRINTF("partition %d contains partition %d: "
417d0c8ecb8SAndrey V. Elsukov "start[%d] %jd > start[%d] %jd, end[%d] "
418d0c8ecb8SAndrey V. Elsukov "%jd < end[%d] %jd\n",
419d0c8ecb8SAndrey V. Elsukov e1->gpe_index, e2->gpe_index,
420d0c8ecb8SAndrey V. Elsukov e1->gpe_index, (intmax_t)e1->gpe_start,
421d0c8ecb8SAndrey V. Elsukov e2->gpe_index, (intmax_t)e2->gpe_start,
422d0c8ecb8SAndrey V. Elsukov e2->gpe_index, (intmax_t)e2->gpe_end,
423d0c8ecb8SAndrey V. Elsukov e1->gpe_index, (intmax_t)e1->gpe_end);
424d0c8ecb8SAndrey V. Elsukov failed++;
425c63e8fe2SAndrey V. Elsukov }
426c63e8fe2SAndrey V. Elsukov }
427b6c4978fSAndrey V. Elsukov }
428d0c8ecb8SAndrey V. Elsukov if (failed != 0) {
429d0c8ecb8SAndrey V. Elsukov printf("GEOM_PART: integrity check failed (%s, %s)\n",
430d0c8ecb8SAndrey V. Elsukov pp->name, table->gpt_scheme->name);
431cea05ed9SEugene Grosbein if (geom_part_check_integrity != 0)
432c63e8fe2SAndrey V. Elsukov return (EINVAL);
433d0c8ecb8SAndrey V. Elsukov table->gpt_corrupt = 1;
434c63e8fe2SAndrey V. Elsukov }
435d0c8ecb8SAndrey V. Elsukov return (0);
436d0c8ecb8SAndrey V. Elsukov }
437d0c8ecb8SAndrey V. Elsukov #undef DPRINTF
438c63e8fe2SAndrey V. Elsukov
4391d3aed33SMarcel Moolenaar struct g_part_entry *
g_part_new_entry(struct g_part_table * table,int index,quad_t start,quad_t end)4401d3aed33SMarcel Moolenaar g_part_new_entry(struct g_part_table *table, int index, quad_t start,
4411d3aed33SMarcel Moolenaar quad_t end)
4421d3aed33SMarcel Moolenaar {
4431d3aed33SMarcel Moolenaar struct g_part_entry *entry, *last;
4441d3aed33SMarcel Moolenaar
4451d3aed33SMarcel Moolenaar last = NULL;
4461d3aed33SMarcel Moolenaar LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
4471d3aed33SMarcel Moolenaar if (entry->gpe_index == index)
4481d3aed33SMarcel Moolenaar break;
4491d3aed33SMarcel Moolenaar if (entry->gpe_index > index) {
4501d3aed33SMarcel Moolenaar entry = NULL;
4511d3aed33SMarcel Moolenaar break;
4521d3aed33SMarcel Moolenaar }
4531d3aed33SMarcel Moolenaar last = entry;
4541d3aed33SMarcel Moolenaar }
4551d3aed33SMarcel Moolenaar if (entry == NULL) {
4561d3aed33SMarcel Moolenaar entry = g_malloc(table->gpt_scheme->gps_entrysz,
4571d3aed33SMarcel Moolenaar M_WAITOK | M_ZERO);
4581d3aed33SMarcel Moolenaar entry->gpe_index = index;
4591d3aed33SMarcel Moolenaar if (last == NULL)
4601d3aed33SMarcel Moolenaar LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry);
4611d3aed33SMarcel Moolenaar else
4621d3aed33SMarcel Moolenaar LIST_INSERT_AFTER(last, entry, gpe_entry);
463665557a4SMarcel Moolenaar } else
464665557a4SMarcel Moolenaar entry->gpe_offset = 0;
4651d3aed33SMarcel Moolenaar entry->gpe_start = start;
4661d3aed33SMarcel Moolenaar entry->gpe_end = end;
4671d3aed33SMarcel Moolenaar return (entry);
4681d3aed33SMarcel Moolenaar }
4691d3aed33SMarcel Moolenaar
4701d3aed33SMarcel Moolenaar static void
g_part_new_provider(struct g_geom * gp,struct g_part_table * table,struct g_part_entry * entry)4711d3aed33SMarcel Moolenaar g_part_new_provider(struct g_geom *gp, struct g_part_table *table,
4721d3aed33SMarcel Moolenaar struct g_part_entry *entry)
4731d3aed33SMarcel Moolenaar {
4741d3aed33SMarcel Moolenaar struct g_consumer *cp;
4751d3aed33SMarcel Moolenaar struct g_provider *pp;
4765d7d1329SWarner Losh struct g_geom_alias *gap;
477665557a4SMarcel Moolenaar off_t offset;
4781d3aed33SMarcel Moolenaar
4791d3aed33SMarcel Moolenaar cp = LIST_FIRST(&gp->consumer);
4801d3aed33SMarcel Moolenaar pp = cp->provider;
4811d3aed33SMarcel Moolenaar
482665557a4SMarcel Moolenaar offset = entry->gpe_start * pp->sectorsize;
483665557a4SMarcel Moolenaar if (entry->gpe_offset < offset)
484665557a4SMarcel Moolenaar entry->gpe_offset = offset;
4851d3aed33SMarcel Moolenaar
4861d3aed33SMarcel Moolenaar if (entry->gpe_pp == NULL) {
487b71dc875SConrad Meyer entry->gpe_pp = G_PART_NEW_PROVIDER(table, gp, entry, gp->name);
488ae1cce52SWarner Losh /*
489ae1cce52SWarner Losh * If our parent provider had any aliases, then copy them to our
490ae1cce52SWarner Losh * provider so when geom DEV tastes things later, they will be
491ae1cce52SWarner Losh * there for it to create the aliases with those name used in
492ae1cce52SWarner Losh * place of the geom's name we use to create the provider. The
493ae1cce52SWarner Losh * kobj interface that generates names makes this awkward.
494ae1cce52SWarner Losh */
495b71dc875SConrad Meyer LIST_FOREACH(gap, &pp->aliases, ga_next)
496b71dc875SConrad Meyer G_PART_ADD_ALIAS(table, entry->gpe_pp, entry, gap->ga_alias);
49740ea77a0SAlexander Motin entry->gpe_pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
4981d3aed33SMarcel Moolenaar entry->gpe_pp->private = entry; /* Close the circle. */
4991d3aed33SMarcel Moolenaar }
5001d3aed33SMarcel Moolenaar entry->gpe_pp->index = entry->gpe_index - 1; /* index is 1-based. */
5011d3aed33SMarcel Moolenaar entry->gpe_pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) *
5021d3aed33SMarcel Moolenaar pp->sectorsize;
503665557a4SMarcel Moolenaar entry->gpe_pp->mediasize -= entry->gpe_offset - offset;
5041d3aed33SMarcel Moolenaar entry->gpe_pp->sectorsize = pp->sectorsize;
5051d3aed33SMarcel Moolenaar entry->gpe_pp->stripesize = pp->stripesize;
5060c8fd0c8SAlexander Motin entry->gpe_pp->stripeoffset = pp->stripeoffset + entry->gpe_offset;
5070c8fd0c8SAlexander Motin if (pp->stripesize > 0)
5080c8fd0c8SAlexander Motin entry->gpe_pp->stripeoffset %= pp->stripesize;
509db7bfaa8SKonstantin Belousov entry->gpe_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED;
5101d3aed33SMarcel Moolenaar g_error_provider(entry->gpe_pp, 0);
5111d3aed33SMarcel Moolenaar }
5121d3aed33SMarcel Moolenaar
51355514bdfSAndrey V. Elsukov static struct g_geom*
g_part_find_geom(const char * name)51455514bdfSAndrey V. Elsukov g_part_find_geom(const char *name)
51555514bdfSAndrey V. Elsukov {
51655514bdfSAndrey V. Elsukov struct g_geom *gp;
51755514bdfSAndrey V. Elsukov LIST_FOREACH(gp, &g_part_class.geom, geom) {
5185523c82cSAlexander Motin if ((gp->flags & G_GEOM_WITHER) == 0 &&
5195523c82cSAlexander Motin strcmp(name, gp->name) == 0)
52055514bdfSAndrey V. Elsukov break;
52155514bdfSAndrey V. Elsukov }
52255514bdfSAndrey V. Elsukov return (gp);
52355514bdfSAndrey V. Elsukov }
52455514bdfSAndrey V. Elsukov
5251d3aed33SMarcel Moolenaar static int
g_part_parm_geom(struct gctl_req * req,const char * name,struct g_geom ** v)5268107ecf8SPawel Jakub Dawidek g_part_parm_geom(struct gctl_req *req, const char *name, struct g_geom **v)
5271d3aed33SMarcel Moolenaar {
5281d3aed33SMarcel Moolenaar struct g_geom *gp;
5298107ecf8SPawel Jakub Dawidek const char *gname;
5301d3aed33SMarcel Moolenaar
5318107ecf8SPawel Jakub Dawidek gname = gctl_get_asciiparam(req, name);
5328107ecf8SPawel Jakub Dawidek if (gname == NULL)
5338107ecf8SPawel Jakub Dawidek return (ENOATTR);
53421bf062eSAndrey V. Elsukov if (strncmp(gname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
53521bf062eSAndrey V. Elsukov gname += sizeof(_PATH_DEV) - 1;
53655514bdfSAndrey V. Elsukov gp = g_part_find_geom(gname);
5378107ecf8SPawel Jakub Dawidek if (gp == NULL) {
5388107ecf8SPawel Jakub Dawidek gctl_error(req, "%d %s '%s'", EINVAL, name, gname);
5391d3aed33SMarcel Moolenaar return (EINVAL);
5408107ecf8SPawel Jakub Dawidek }
5411d3aed33SMarcel Moolenaar *v = gp;
5421d3aed33SMarcel Moolenaar return (0);
5431d3aed33SMarcel Moolenaar }
5441d3aed33SMarcel Moolenaar
5451d3aed33SMarcel Moolenaar static int
g_part_parm_provider(struct gctl_req * req,const char * name,struct g_provider ** v)5468107ecf8SPawel Jakub Dawidek g_part_parm_provider(struct gctl_req *req, const char *name,
5478107ecf8SPawel Jakub Dawidek struct g_provider **v)
5481d3aed33SMarcel Moolenaar {
5491d3aed33SMarcel Moolenaar struct g_provider *pp;
5508107ecf8SPawel Jakub Dawidek const char *pname;
5511d3aed33SMarcel Moolenaar
5528107ecf8SPawel Jakub Dawidek pname = gctl_get_asciiparam(req, name);
5538107ecf8SPawel Jakub Dawidek if (pname == NULL)
5548107ecf8SPawel Jakub Dawidek return (ENOATTR);
55521bf062eSAndrey V. Elsukov if (strncmp(pname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
55621bf062eSAndrey V. Elsukov pname += sizeof(_PATH_DEV) - 1;
5578107ecf8SPawel Jakub Dawidek pp = g_provider_by_name(pname);
5588107ecf8SPawel Jakub Dawidek if (pp == NULL) {
5598107ecf8SPawel Jakub Dawidek gctl_error(req, "%d %s '%s'", EINVAL, name, pname);
5601d3aed33SMarcel Moolenaar return (EINVAL);
5618107ecf8SPawel Jakub Dawidek }
5621d3aed33SMarcel Moolenaar *v = pp;
5631d3aed33SMarcel Moolenaar return (0);
5641d3aed33SMarcel Moolenaar }
5651d3aed33SMarcel Moolenaar
5661d3aed33SMarcel Moolenaar static int
g_part_parm_quad(struct gctl_req * req,const char * name,quad_t * v)5678107ecf8SPawel Jakub Dawidek g_part_parm_quad(struct gctl_req *req, const char *name, quad_t *v)
5681d3aed33SMarcel Moolenaar {
5698107ecf8SPawel Jakub Dawidek const char *p;
5701d3aed33SMarcel Moolenaar char *x;
5711d3aed33SMarcel Moolenaar quad_t q;
5721d3aed33SMarcel Moolenaar
5738107ecf8SPawel Jakub Dawidek p = gctl_get_asciiparam(req, name);
5748107ecf8SPawel Jakub Dawidek if (p == NULL)
5758107ecf8SPawel Jakub Dawidek return (ENOATTR);
5761d3aed33SMarcel Moolenaar q = strtoq(p, &x, 0);
5778107ecf8SPawel Jakub Dawidek if (*x != '\0' || q < 0) {
5788107ecf8SPawel Jakub Dawidek gctl_error(req, "%d %s '%s'", EINVAL, name, p);
5791d3aed33SMarcel Moolenaar return (EINVAL);
5808107ecf8SPawel Jakub Dawidek }
5811d3aed33SMarcel Moolenaar *v = q;
5821d3aed33SMarcel Moolenaar return (0);
5831d3aed33SMarcel Moolenaar }
5841d3aed33SMarcel Moolenaar
5851d3aed33SMarcel Moolenaar static int
g_part_parm_scheme(struct gctl_req * req,const char * name,struct g_part_scheme ** v)5868107ecf8SPawel Jakub Dawidek g_part_parm_scheme(struct gctl_req *req, const char *name,
5878107ecf8SPawel Jakub Dawidek struct g_part_scheme **v)
5881d3aed33SMarcel Moolenaar {
5894ffca444SMarcel Moolenaar struct g_part_scheme *s;
5908107ecf8SPawel Jakub Dawidek const char *p;
5911d3aed33SMarcel Moolenaar
5928107ecf8SPawel Jakub Dawidek p = gctl_get_asciiparam(req, name);
5938107ecf8SPawel Jakub Dawidek if (p == NULL)
5948107ecf8SPawel Jakub Dawidek return (ENOATTR);
5954ffca444SMarcel Moolenaar TAILQ_FOREACH(s, &g_part_schemes, scheme_list) {
5964ffca444SMarcel Moolenaar if (s == &g_part_null_scheme)
5971d3aed33SMarcel Moolenaar continue;
5984ffca444SMarcel Moolenaar if (!strcasecmp(s->name, p))
5991d3aed33SMarcel Moolenaar break;
6001d3aed33SMarcel Moolenaar }
6018107ecf8SPawel Jakub Dawidek if (s == NULL) {
6028107ecf8SPawel Jakub Dawidek gctl_error(req, "%d %s '%s'", EINVAL, name, p);
6031d3aed33SMarcel Moolenaar return (EINVAL);
6048107ecf8SPawel Jakub Dawidek }
6051d3aed33SMarcel Moolenaar *v = s;
6061d3aed33SMarcel Moolenaar return (0);
6071d3aed33SMarcel Moolenaar }
6081d3aed33SMarcel Moolenaar
6091d3aed33SMarcel Moolenaar static int
g_part_parm_str(struct gctl_req * req,const char * name,const char ** v)6108107ecf8SPawel Jakub Dawidek g_part_parm_str(struct gctl_req *req, const char *name, const char **v)
6111d3aed33SMarcel Moolenaar {
6128107ecf8SPawel Jakub Dawidek const char *p;
6131d3aed33SMarcel Moolenaar
6148107ecf8SPawel Jakub Dawidek p = gctl_get_asciiparam(req, name);
6158107ecf8SPawel Jakub Dawidek if (p == NULL)
6168107ecf8SPawel Jakub Dawidek return (ENOATTR);
6178107ecf8SPawel Jakub Dawidek /* An empty label is always valid. */
6188107ecf8SPawel Jakub Dawidek if (strcmp(name, "label") != 0 && p[0] == '\0') {
6198107ecf8SPawel Jakub Dawidek gctl_error(req, "%d %s '%s'", EINVAL, name, p);
6201d3aed33SMarcel Moolenaar return (EINVAL);
6218107ecf8SPawel Jakub Dawidek }
6221d3aed33SMarcel Moolenaar *v = p;
6231d3aed33SMarcel Moolenaar return (0);
6241d3aed33SMarcel Moolenaar }
6251d3aed33SMarcel Moolenaar
6261d3aed33SMarcel Moolenaar static int
g_part_parm_intmax(struct gctl_req * req,const char * name,u_int * v)6278107ecf8SPawel Jakub Dawidek g_part_parm_intmax(struct gctl_req *req, const char *name, u_int *v)
6281d3aed33SMarcel Moolenaar {
6298107ecf8SPawel Jakub Dawidek const intmax_t *p;
6308107ecf8SPawel Jakub Dawidek int size;
6311d3aed33SMarcel Moolenaar
6328107ecf8SPawel Jakub Dawidek p = gctl_get_param(req, name, &size);
6338107ecf8SPawel Jakub Dawidek if (p == NULL)
6348107ecf8SPawel Jakub Dawidek return (ENOATTR);
6358107ecf8SPawel Jakub Dawidek if (size != sizeof(*p) || *p < 0 || *p > INT_MAX) {
6368107ecf8SPawel Jakub Dawidek gctl_error(req, "%d %s '%jd'", EINVAL, name, *p);
6371d3aed33SMarcel Moolenaar return (EINVAL);
6388107ecf8SPawel Jakub Dawidek }
6398107ecf8SPawel Jakub Dawidek *v = (u_int)*p;
6408107ecf8SPawel Jakub Dawidek return (0);
6418107ecf8SPawel Jakub Dawidek }
6428107ecf8SPawel Jakub Dawidek
6438107ecf8SPawel Jakub Dawidek static int
g_part_parm_uint32(struct gctl_req * req,const char * name,u_int * v)6448107ecf8SPawel Jakub Dawidek g_part_parm_uint32(struct gctl_req *req, const char *name, u_int *v)
6458107ecf8SPawel Jakub Dawidek {
6468107ecf8SPawel Jakub Dawidek const uint32_t *p;
6478107ecf8SPawel Jakub Dawidek int size;
6488107ecf8SPawel Jakub Dawidek
6498107ecf8SPawel Jakub Dawidek p = gctl_get_param(req, name, &size);
6508107ecf8SPawel Jakub Dawidek if (p == NULL)
6518107ecf8SPawel Jakub Dawidek return (ENOATTR);
6528107ecf8SPawel Jakub Dawidek if (size != sizeof(*p) || *p > INT_MAX) {
6538107ecf8SPawel Jakub Dawidek gctl_error(req, "%d %s '%u'", EINVAL, name, (unsigned int)*p);
6548107ecf8SPawel Jakub Dawidek return (EINVAL);
6558107ecf8SPawel Jakub Dawidek }
6568107ecf8SPawel Jakub Dawidek *v = (u_int)*p;
6578107ecf8SPawel Jakub Dawidek return (0);
6588107ecf8SPawel Jakub Dawidek }
6598107ecf8SPawel Jakub Dawidek
6608107ecf8SPawel Jakub Dawidek static int
g_part_parm_bootcode(struct gctl_req * req,const char * name,const void ** v,unsigned int * s)6618107ecf8SPawel Jakub Dawidek g_part_parm_bootcode(struct gctl_req *req, const char *name, const void **v,
6628107ecf8SPawel Jakub Dawidek unsigned int *s)
6638107ecf8SPawel Jakub Dawidek {
6648107ecf8SPawel Jakub Dawidek const void *p;
6658107ecf8SPawel Jakub Dawidek int size;
6668107ecf8SPawel Jakub Dawidek
6678107ecf8SPawel Jakub Dawidek p = gctl_get_param(req, name, &size);
6688107ecf8SPawel Jakub Dawidek if (p == NULL)
6698107ecf8SPawel Jakub Dawidek return (ENOATTR);
6708107ecf8SPawel Jakub Dawidek *v = p;
6718107ecf8SPawel Jakub Dawidek *s = size;
6721d3aed33SMarcel Moolenaar return (0);
6731d3aed33SMarcel Moolenaar }
6741d3aed33SMarcel Moolenaar
6751d3aed33SMarcel Moolenaar static int
g_part_probe(struct g_geom * gp,struct g_consumer * cp,int depth)6761d3aed33SMarcel Moolenaar g_part_probe(struct g_geom *gp, struct g_consumer *cp, int depth)
6771d3aed33SMarcel Moolenaar {
6784ffca444SMarcel Moolenaar struct g_part_scheme *iter, *scheme;
6791d3aed33SMarcel Moolenaar struct g_part_table *table;
6801d3aed33SMarcel Moolenaar int pri, probe;
6811d3aed33SMarcel Moolenaar
6821d3aed33SMarcel Moolenaar table = gp->softc;
6834ffca444SMarcel Moolenaar scheme = (table != NULL) ? table->gpt_scheme : NULL;
6844ffca444SMarcel Moolenaar pri = (scheme != NULL) ? G_PART_PROBE(table, cp) : INT_MIN;
6851d3aed33SMarcel Moolenaar if (pri == 0)
6861d3aed33SMarcel Moolenaar goto done;
6871d3aed33SMarcel Moolenaar if (pri > 0) { /* error */
6884ffca444SMarcel Moolenaar scheme = NULL;
6891d3aed33SMarcel Moolenaar pri = INT_MIN;
6901d3aed33SMarcel Moolenaar }
6911d3aed33SMarcel Moolenaar
6924ffca444SMarcel Moolenaar TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) {
6934ffca444SMarcel Moolenaar if (iter == &g_part_null_scheme)
6941d3aed33SMarcel Moolenaar continue;
6954ffca444SMarcel Moolenaar table = (void *)kobj_create((kobj_class_t)iter, M_GEOM,
6961d3aed33SMarcel Moolenaar M_WAITOK);
6971d3aed33SMarcel Moolenaar table->gpt_gp = gp;
6984ffca444SMarcel Moolenaar table->gpt_scheme = iter;
6991d3aed33SMarcel Moolenaar table->gpt_depth = depth;
7001d3aed33SMarcel Moolenaar probe = G_PART_PROBE(table, cp);
7011d3aed33SMarcel Moolenaar if (probe <= 0 && probe > pri) {
7021d3aed33SMarcel Moolenaar pri = probe;
7034ffca444SMarcel Moolenaar scheme = iter;
7041d3aed33SMarcel Moolenaar if (gp->softc != NULL)
7051d3aed33SMarcel Moolenaar kobj_delete((kobj_t)gp->softc, M_GEOM);
7061d3aed33SMarcel Moolenaar gp->softc = table;
7071d3aed33SMarcel Moolenaar if (pri == 0)
7081d3aed33SMarcel Moolenaar goto done;
7091d3aed33SMarcel Moolenaar } else
7101d3aed33SMarcel Moolenaar kobj_delete((kobj_t)table, M_GEOM);
7111d3aed33SMarcel Moolenaar }
7121d3aed33SMarcel Moolenaar
7131d3aed33SMarcel Moolenaar done:
7144ffca444SMarcel Moolenaar return ((scheme == NULL) ? ENXIO : 0);
7151d3aed33SMarcel Moolenaar }
7161d3aed33SMarcel Moolenaar
7171d3aed33SMarcel Moolenaar /*
7181d3aed33SMarcel Moolenaar * Control request functions.
7191d3aed33SMarcel Moolenaar */
7201d3aed33SMarcel Moolenaar
7211d3aed33SMarcel Moolenaar static int
g_part_ctl_add(struct gctl_req * req,struct g_part_parms * gpp)7221d3aed33SMarcel Moolenaar g_part_ctl_add(struct gctl_req *req, struct g_part_parms *gpp)
7231d3aed33SMarcel Moolenaar {
7241d3aed33SMarcel Moolenaar struct g_geom *gp;
7251d3aed33SMarcel Moolenaar struct g_provider *pp;
7261d3aed33SMarcel Moolenaar struct g_part_entry *delent, *last, *entry;
7271d3aed33SMarcel Moolenaar struct g_part_table *table;
7285100f9e9SMarcel Moolenaar struct sbuf *sb;
7291d3aed33SMarcel Moolenaar quad_t end;
7301d3aed33SMarcel Moolenaar unsigned int index;
7311d3aed33SMarcel Moolenaar int error;
7321d3aed33SMarcel Moolenaar
7331d3aed33SMarcel Moolenaar gp = gpp->gpp_geom;
7341d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
7351d3aed33SMarcel Moolenaar g_topology_assert();
7361d3aed33SMarcel Moolenaar
7371d3aed33SMarcel Moolenaar pp = LIST_FIRST(&gp->consumer)->provider;
7381d3aed33SMarcel Moolenaar table = gp->softc;
7391d3aed33SMarcel Moolenaar end = gpp->gpp_start + gpp->gpp_size - 1;
7401d3aed33SMarcel Moolenaar
7411d3aed33SMarcel Moolenaar if (gpp->gpp_start < table->gpt_first ||
7421d3aed33SMarcel Moolenaar gpp->gpp_start > table->gpt_last) {
7431d3aed33SMarcel Moolenaar gctl_error(req, "%d start '%jd'", EINVAL,
7441d3aed33SMarcel Moolenaar (intmax_t)gpp->gpp_start);
7451d3aed33SMarcel Moolenaar return (EINVAL);
7461d3aed33SMarcel Moolenaar }
7471d3aed33SMarcel Moolenaar if (end < gpp->gpp_start || end > table->gpt_last) {
7481d3aed33SMarcel Moolenaar gctl_error(req, "%d size '%jd'", EINVAL,
7491d3aed33SMarcel Moolenaar (intmax_t)gpp->gpp_size);
7501d3aed33SMarcel Moolenaar return (EINVAL);
7511d3aed33SMarcel Moolenaar }
7521d3aed33SMarcel Moolenaar if (gpp->gpp_index > table->gpt_entries) {
7531d3aed33SMarcel Moolenaar gctl_error(req, "%d index '%d'", EINVAL, gpp->gpp_index);
7541d3aed33SMarcel Moolenaar return (EINVAL);
7551d3aed33SMarcel Moolenaar }
7561d3aed33SMarcel Moolenaar
7571d3aed33SMarcel Moolenaar delent = last = NULL;
7581d3aed33SMarcel Moolenaar index = (gpp->gpp_index > 0) ? gpp->gpp_index : 1;
7591d3aed33SMarcel Moolenaar LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
7601d3aed33SMarcel Moolenaar if (entry->gpe_deleted) {
7611d3aed33SMarcel Moolenaar if (entry->gpe_index == index)
7621d3aed33SMarcel Moolenaar delent = entry;
7631d3aed33SMarcel Moolenaar continue;
7641d3aed33SMarcel Moolenaar }
7654275d83aSMarcel Moolenaar if (entry->gpe_index == index)
7661d3aed33SMarcel Moolenaar index = entry->gpe_index + 1;
7674275d83aSMarcel Moolenaar if (entry->gpe_index < index)
7681d3aed33SMarcel Moolenaar last = entry;
7695aaa8fefSMarcel Moolenaar if (entry->gpe_internal)
7705aaa8fefSMarcel Moolenaar continue;
7711d3aed33SMarcel Moolenaar if (gpp->gpp_start >= entry->gpe_start &&
7721d3aed33SMarcel Moolenaar gpp->gpp_start <= entry->gpe_end) {
7731d3aed33SMarcel Moolenaar gctl_error(req, "%d start '%jd'", ENOSPC,
7741d3aed33SMarcel Moolenaar (intmax_t)gpp->gpp_start);
7751d3aed33SMarcel Moolenaar return (ENOSPC);
7761d3aed33SMarcel Moolenaar }
7771d3aed33SMarcel Moolenaar if (end >= entry->gpe_start && end <= entry->gpe_end) {
7781d3aed33SMarcel Moolenaar gctl_error(req, "%d end '%jd'", ENOSPC, (intmax_t)end);
7791d3aed33SMarcel Moolenaar return (ENOSPC);
7801d3aed33SMarcel Moolenaar }
7811d3aed33SMarcel Moolenaar if (gpp->gpp_start < entry->gpe_start && end > entry->gpe_end) {
7821d3aed33SMarcel Moolenaar gctl_error(req, "%d size '%jd'", ENOSPC,
7831d3aed33SMarcel Moolenaar (intmax_t)gpp->gpp_size);
7841d3aed33SMarcel Moolenaar return (ENOSPC);
7851d3aed33SMarcel Moolenaar }
7861d3aed33SMarcel Moolenaar }
7871d3aed33SMarcel Moolenaar if (gpp->gpp_index > 0 && index != gpp->gpp_index) {
7881d3aed33SMarcel Moolenaar gctl_error(req, "%d index '%d'", EEXIST, gpp->gpp_index);
7891d3aed33SMarcel Moolenaar return (EEXIST);
7901d3aed33SMarcel Moolenaar }
79187f44706SMarcel Moolenaar if (index > table->gpt_entries) {
79287f44706SMarcel Moolenaar gctl_error(req, "%d index '%d'", ENOSPC, index);
79387f44706SMarcel Moolenaar return (ENOSPC);
79487f44706SMarcel Moolenaar }
7951d3aed33SMarcel Moolenaar
7961d3aed33SMarcel Moolenaar entry = (delent == NULL) ? g_malloc(table->gpt_scheme->gps_entrysz,
7971d3aed33SMarcel Moolenaar M_WAITOK | M_ZERO) : delent;
7981d3aed33SMarcel Moolenaar entry->gpe_index = index;
7991d3aed33SMarcel Moolenaar entry->gpe_start = gpp->gpp_start;
8001d3aed33SMarcel Moolenaar entry->gpe_end = end;
8011d3aed33SMarcel Moolenaar error = G_PART_ADD(table, entry, gpp);
8021d3aed33SMarcel Moolenaar if (error) {
8031d3aed33SMarcel Moolenaar gctl_error(req, "%d", error);
8041d3aed33SMarcel Moolenaar if (delent == NULL)
8051d3aed33SMarcel Moolenaar g_free(entry);
8061d3aed33SMarcel Moolenaar return (error);
8071d3aed33SMarcel Moolenaar }
8081d3aed33SMarcel Moolenaar if (delent == NULL) {
8091d3aed33SMarcel Moolenaar if (last == NULL)
8101d3aed33SMarcel Moolenaar LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry);
8111d3aed33SMarcel Moolenaar else
8121d3aed33SMarcel Moolenaar LIST_INSERT_AFTER(last, entry, gpe_entry);
8131d3aed33SMarcel Moolenaar entry->gpe_created = 1;
8141d3aed33SMarcel Moolenaar } else {
8151d3aed33SMarcel Moolenaar entry->gpe_deleted = 0;
8161d3aed33SMarcel Moolenaar entry->gpe_modified = 1;
8171d3aed33SMarcel Moolenaar }
8181d3aed33SMarcel Moolenaar g_part_new_provider(gp, table, entry);
8195100f9e9SMarcel Moolenaar
8205100f9e9SMarcel Moolenaar /* Provide feedback if so requested. */
8215100f9e9SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
8222616144eSDag-Erling Smørgrav sb = sbuf_new_auto();
8236ad9a99fSMarcel Moolenaar G_PART_FULLNAME(table, entry, sb, gp->name);
82438c64884SAndrey V. Elsukov if (pp->stripesize > 0 && entry->gpe_pp->stripeoffset != 0)
82538c64884SAndrey V. Elsukov sbuf_printf(sb, " added, but partition is not "
8266d305ab0SEugene Grosbein "aligned on %ju bytes\n", (uintmax_t)pp->stripesize);
82738c64884SAndrey V. Elsukov else
8286ad9a99fSMarcel Moolenaar sbuf_cat(sb, " added\n");
82933a558c7SMarcel Moolenaar sbuf_finish(sb);
8305100f9e9SMarcel Moolenaar gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
8315100f9e9SMarcel Moolenaar sbuf_delete(sb);
8325100f9e9SMarcel Moolenaar }
8331d3aed33SMarcel Moolenaar return (0);
8341d3aed33SMarcel Moolenaar }
8351d3aed33SMarcel Moolenaar
8361d3aed33SMarcel Moolenaar static int
g_part_ctl_bootcode(struct gctl_req * req,struct g_part_parms * gpp)8374d32fcb4SMarcel Moolenaar g_part_ctl_bootcode(struct gctl_req *req, struct g_part_parms *gpp)
8384d32fcb4SMarcel Moolenaar {
8394d32fcb4SMarcel Moolenaar struct g_geom *gp;
8404d32fcb4SMarcel Moolenaar struct g_part_table *table;
8414d32fcb4SMarcel Moolenaar struct sbuf *sb;
8424d32fcb4SMarcel Moolenaar int error, sz;
8434d32fcb4SMarcel Moolenaar
8444d32fcb4SMarcel Moolenaar gp = gpp->gpp_geom;
8454d32fcb4SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
8464d32fcb4SMarcel Moolenaar g_topology_assert();
8474d32fcb4SMarcel Moolenaar
8484d32fcb4SMarcel Moolenaar table = gp->softc;
8494d32fcb4SMarcel Moolenaar sz = table->gpt_scheme->gps_bootcodesz;
8504d32fcb4SMarcel Moolenaar if (sz == 0) {
8514d32fcb4SMarcel Moolenaar error = ENODEV;
8524d32fcb4SMarcel Moolenaar goto fail;
8534d32fcb4SMarcel Moolenaar }
85466477112SMarcel Moolenaar if (gpp->gpp_codesize > sz) {
85566477112SMarcel Moolenaar error = EFBIG;
8564d32fcb4SMarcel Moolenaar goto fail;
8574d32fcb4SMarcel Moolenaar }
8584d32fcb4SMarcel Moolenaar
8594d32fcb4SMarcel Moolenaar error = G_PART_BOOTCODE(table, gpp);
8604d32fcb4SMarcel Moolenaar if (error)
8614d32fcb4SMarcel Moolenaar goto fail;
8624d32fcb4SMarcel Moolenaar
8634d32fcb4SMarcel Moolenaar /* Provide feedback if so requested. */
8644d32fcb4SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
8652616144eSDag-Erling Smørgrav sb = sbuf_new_auto();
8662f4e9a09SPawel Jakub Dawidek sbuf_printf(sb, "bootcode written to %s\n", gp->name);
8674d32fcb4SMarcel Moolenaar sbuf_finish(sb);
8684d32fcb4SMarcel Moolenaar gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
8694d32fcb4SMarcel Moolenaar sbuf_delete(sb);
8704d32fcb4SMarcel Moolenaar }
8714d32fcb4SMarcel Moolenaar return (0);
8724d32fcb4SMarcel Moolenaar
8734d32fcb4SMarcel Moolenaar fail:
8744d32fcb4SMarcel Moolenaar gctl_error(req, "%d", error);
8754d32fcb4SMarcel Moolenaar return (error);
8764d32fcb4SMarcel Moolenaar }
8774d32fcb4SMarcel Moolenaar
8784d32fcb4SMarcel Moolenaar static int
g_part_ctl_commit(struct gctl_req * req,struct g_part_parms * gpp)8791d3aed33SMarcel Moolenaar g_part_ctl_commit(struct gctl_req *req, struct g_part_parms *gpp)
8801d3aed33SMarcel Moolenaar {
8811d3aed33SMarcel Moolenaar struct g_consumer *cp;
8821d3aed33SMarcel Moolenaar struct g_geom *gp;
8831d3aed33SMarcel Moolenaar struct g_provider *pp;
8841d3aed33SMarcel Moolenaar struct g_part_entry *entry, *tmp;
8851d3aed33SMarcel Moolenaar struct g_part_table *table;
8861d3aed33SMarcel Moolenaar char *buf;
8871d3aed33SMarcel Moolenaar int error, i;
8881d3aed33SMarcel Moolenaar
8891d3aed33SMarcel Moolenaar gp = gpp->gpp_geom;
8901d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
8911d3aed33SMarcel Moolenaar g_topology_assert();
8921d3aed33SMarcel Moolenaar
8931d3aed33SMarcel Moolenaar table = gp->softc;
8941d3aed33SMarcel Moolenaar if (!table->gpt_opened) {
8951d3aed33SMarcel Moolenaar gctl_error(req, "%d", EPERM);
8961d3aed33SMarcel Moolenaar return (EPERM);
8971d3aed33SMarcel Moolenaar }
8981d3aed33SMarcel Moolenaar
89959c532c5SMarcel Moolenaar g_topology_unlock();
90059c532c5SMarcel Moolenaar
9011d3aed33SMarcel Moolenaar cp = LIST_FIRST(&gp->consumer);
9021d3aed33SMarcel Moolenaar if ((table->gpt_smhead | table->gpt_smtail) != 0) {
9031d3aed33SMarcel Moolenaar pp = cp->provider;
9041d3aed33SMarcel Moolenaar buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
9051d3aed33SMarcel Moolenaar while (table->gpt_smhead != 0) {
9061d3aed33SMarcel Moolenaar i = ffs(table->gpt_smhead) - 1;
9071d3aed33SMarcel Moolenaar error = g_write_data(cp, i * pp->sectorsize, buf,
9081d3aed33SMarcel Moolenaar pp->sectorsize);
9091d3aed33SMarcel Moolenaar if (error) {
9101d3aed33SMarcel Moolenaar g_free(buf);
9111d3aed33SMarcel Moolenaar goto fail;
9121d3aed33SMarcel Moolenaar }
9131d3aed33SMarcel Moolenaar table->gpt_smhead &= ~(1 << i);
9141d3aed33SMarcel Moolenaar }
9151d3aed33SMarcel Moolenaar while (table->gpt_smtail != 0) {
9161d3aed33SMarcel Moolenaar i = ffs(table->gpt_smtail) - 1;
9171d3aed33SMarcel Moolenaar error = g_write_data(cp, pp->mediasize - (i + 1) *
9181d3aed33SMarcel Moolenaar pp->sectorsize, buf, pp->sectorsize);
9191d3aed33SMarcel Moolenaar if (error) {
9201d3aed33SMarcel Moolenaar g_free(buf);
9211d3aed33SMarcel Moolenaar goto fail;
9221d3aed33SMarcel Moolenaar }
9231d3aed33SMarcel Moolenaar table->gpt_smtail &= ~(1 << i);
9241d3aed33SMarcel Moolenaar }
9251d3aed33SMarcel Moolenaar g_free(buf);
9261d3aed33SMarcel Moolenaar }
9271d3aed33SMarcel Moolenaar
9281d3aed33SMarcel Moolenaar if (table->gpt_scheme == &g_part_null_scheme) {
92959c532c5SMarcel Moolenaar g_topology_lock();
9301d3aed33SMarcel Moolenaar g_access(cp, -1, -1, -1);
9311d3aed33SMarcel Moolenaar g_part_wither(gp, ENXIO);
9321d3aed33SMarcel Moolenaar return (0);
9331d3aed33SMarcel Moolenaar }
9341d3aed33SMarcel Moolenaar
9351d3aed33SMarcel Moolenaar error = G_PART_WRITE(table, cp);
9361d3aed33SMarcel Moolenaar if (error)
9371d3aed33SMarcel Moolenaar goto fail;
9381d3aed33SMarcel Moolenaar
9391d3aed33SMarcel Moolenaar LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
9401d3aed33SMarcel Moolenaar if (!entry->gpe_deleted) {
9412ae0afa8SMarcelo Araujo /* Notify consumers that provider might be changed. */
9422ae0afa8SMarcelo Araujo if (entry->gpe_modified && (
9434323355eSMarcelo Araujo entry->gpe_pp->acw + entry->gpe_pp->ace +
9444323355eSMarcelo Araujo entry->gpe_pp->acr) == 0)
9457f5f84f0SMarcelo Araujo g_media_changed(entry->gpe_pp, M_NOWAIT);
9461d3aed33SMarcel Moolenaar entry->gpe_created = 0;
9471d3aed33SMarcel Moolenaar entry->gpe_modified = 0;
9481d3aed33SMarcel Moolenaar continue;
9491d3aed33SMarcel Moolenaar }
9501d3aed33SMarcel Moolenaar LIST_REMOVE(entry, gpe_entry);
9511d3aed33SMarcel Moolenaar g_free(entry);
9521d3aed33SMarcel Moolenaar }
9531d3aed33SMarcel Moolenaar table->gpt_created = 0;
9541d3aed33SMarcel Moolenaar table->gpt_opened = 0;
95559c532c5SMarcel Moolenaar
95659c532c5SMarcel Moolenaar g_topology_lock();
9571d3aed33SMarcel Moolenaar g_access(cp, -1, -1, -1);
9581d3aed33SMarcel Moolenaar return (0);
9591d3aed33SMarcel Moolenaar
9601d3aed33SMarcel Moolenaar fail:
96159c532c5SMarcel Moolenaar g_topology_lock();
9621d3aed33SMarcel Moolenaar gctl_error(req, "%d", error);
9631d3aed33SMarcel Moolenaar return (error);
9641d3aed33SMarcel Moolenaar }
9651d3aed33SMarcel Moolenaar
9661d3aed33SMarcel Moolenaar static int
g_part_ctl_create(struct gctl_req * req,struct g_part_parms * gpp)9671d3aed33SMarcel Moolenaar g_part_ctl_create(struct gctl_req *req, struct g_part_parms *gpp)
9681d3aed33SMarcel Moolenaar {
9691d3aed33SMarcel Moolenaar struct g_consumer *cp;
9701d3aed33SMarcel Moolenaar struct g_geom *gp;
9711d3aed33SMarcel Moolenaar struct g_provider *pp;
9721d3aed33SMarcel Moolenaar struct g_part_scheme *scheme;
9731d3aed33SMarcel Moolenaar struct g_part_table *null, *table;
9745100f9e9SMarcel Moolenaar struct sbuf *sb;
9751d3aed33SMarcel Moolenaar int attr, error;
9761d3aed33SMarcel Moolenaar
9771d3aed33SMarcel Moolenaar pp = gpp->gpp_provider;
9781d3aed33SMarcel Moolenaar scheme = gpp->gpp_scheme;
9791d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name));
9801d3aed33SMarcel Moolenaar g_topology_assert();
9811d3aed33SMarcel Moolenaar
9821d3aed33SMarcel Moolenaar /* Check that there isn't already a g_part geom on the provider. */
98355514bdfSAndrey V. Elsukov gp = g_part_find_geom(pp->name);
98455514bdfSAndrey V. Elsukov if (gp != NULL) {
9851d3aed33SMarcel Moolenaar null = gp->softc;
9861d3aed33SMarcel Moolenaar if (null->gpt_scheme != &g_part_null_scheme) {
9871d3aed33SMarcel Moolenaar gctl_error(req, "%d geom '%s'", EEXIST, pp->name);
9881d3aed33SMarcel Moolenaar return (EEXIST);
9891d3aed33SMarcel Moolenaar }
9901d3aed33SMarcel Moolenaar } else
9911d3aed33SMarcel Moolenaar null = NULL;
9921d3aed33SMarcel Moolenaar
9931d3aed33SMarcel Moolenaar if ((gpp->gpp_parms & G_PART_PARM_ENTRIES) &&
9941d3aed33SMarcel Moolenaar (gpp->gpp_entries < scheme->gps_minent ||
9951d3aed33SMarcel Moolenaar gpp->gpp_entries > scheme->gps_maxent)) {
9961d3aed33SMarcel Moolenaar gctl_error(req, "%d entries '%d'", EINVAL, gpp->gpp_entries);
9971d3aed33SMarcel Moolenaar return (EINVAL);
9981d3aed33SMarcel Moolenaar }
9991d3aed33SMarcel Moolenaar
10001d3aed33SMarcel Moolenaar if (null == NULL)
10011d3aed33SMarcel Moolenaar gp = g_new_geomf(&g_part_class, "%s", pp->name);
10021d3aed33SMarcel Moolenaar gp->softc = kobj_create((kobj_class_t)gpp->gpp_scheme, M_GEOM,
10031d3aed33SMarcel Moolenaar M_WAITOK);
10041d3aed33SMarcel Moolenaar table = gp->softc;
10051d3aed33SMarcel Moolenaar table->gpt_gp = gp;
10061d3aed33SMarcel Moolenaar table->gpt_scheme = gpp->gpp_scheme;
10071d3aed33SMarcel Moolenaar table->gpt_entries = (gpp->gpp_parms & G_PART_PARM_ENTRIES) ?
1008*09c999b1SWarner Losh gpp->gpp_entries : scheme->gps_defent;
10091d3aed33SMarcel Moolenaar LIST_INIT(&table->gpt_entry);
10101d3aed33SMarcel Moolenaar if (null == NULL) {
10111d3aed33SMarcel Moolenaar cp = g_new_consumer(gp);
101240ea77a0SAlexander Motin cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
10131d3aed33SMarcel Moolenaar error = g_attach(cp, pp);
10141d3aed33SMarcel Moolenaar if (error == 0)
10151d3aed33SMarcel Moolenaar error = g_access(cp, 1, 1, 1);
10161d3aed33SMarcel Moolenaar if (error != 0) {
10171d3aed33SMarcel Moolenaar g_part_wither(gp, error);
10181d3aed33SMarcel Moolenaar gctl_error(req, "%d geom '%s'", error, pp->name);
10191d3aed33SMarcel Moolenaar return (error);
10201d3aed33SMarcel Moolenaar }
10211d3aed33SMarcel Moolenaar table->gpt_opened = 1;
10221d3aed33SMarcel Moolenaar } else {
10231d3aed33SMarcel Moolenaar cp = LIST_FIRST(&gp->consumer);
10241d3aed33SMarcel Moolenaar table->gpt_opened = null->gpt_opened;
10251d3aed33SMarcel Moolenaar table->gpt_smhead = null->gpt_smhead;
10261d3aed33SMarcel Moolenaar table->gpt_smtail = null->gpt_smtail;
10271d3aed33SMarcel Moolenaar }
10281d3aed33SMarcel Moolenaar
10291d3aed33SMarcel Moolenaar g_topology_unlock();
10301d3aed33SMarcel Moolenaar
10310081f96eSMarcel Moolenaar /* Make sure the provider has media. */
10320081f96eSMarcel Moolenaar if (pp->mediasize == 0 || pp->sectorsize == 0) {
10330081f96eSMarcel Moolenaar error = ENODEV;
10340081f96eSMarcel Moolenaar goto fail;
10350081f96eSMarcel Moolenaar }
10360081f96eSMarcel Moolenaar
10371d3aed33SMarcel Moolenaar /* Make sure we can nest and if so, determine our depth. */
10381d3aed33SMarcel Moolenaar error = g_getattr("PART::isleaf", cp, &attr);
10391d3aed33SMarcel Moolenaar if (!error && attr) {
10401d3aed33SMarcel Moolenaar error = ENODEV;
10411d3aed33SMarcel Moolenaar goto fail;
10421d3aed33SMarcel Moolenaar }
10431d3aed33SMarcel Moolenaar error = g_getattr("PART::depth", cp, &attr);
10441d3aed33SMarcel Moolenaar table->gpt_depth = (!error) ? attr + 1 : 0;
10451d3aed33SMarcel Moolenaar
10460081f96eSMarcel Moolenaar /*
10470081f96eSMarcel Moolenaar * Synthesize a disk geometry. Some partitioning schemes
10480081f96eSMarcel Moolenaar * depend on it and since some file systems need it even
10490081f96eSMarcel Moolenaar * when the partitition scheme doesn't, we do it here in
10500081f96eSMarcel Moolenaar * scheme-independent code.
10510081f96eSMarcel Moolenaar */
10520081f96eSMarcel Moolenaar g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
10530081f96eSMarcel Moolenaar
10541d3aed33SMarcel Moolenaar error = G_PART_CREATE(table, gpp);
10551d3aed33SMarcel Moolenaar if (error)
10561d3aed33SMarcel Moolenaar goto fail;
10571d3aed33SMarcel Moolenaar
10581d3aed33SMarcel Moolenaar g_topology_lock();
10591d3aed33SMarcel Moolenaar
10601d3aed33SMarcel Moolenaar table->gpt_created = 1;
10611d3aed33SMarcel Moolenaar if (null != NULL)
10621d3aed33SMarcel Moolenaar kobj_delete((kobj_t)null, M_GEOM);
10635100f9e9SMarcel Moolenaar
106435fe9df0SMarcel Moolenaar /*
106535fe9df0SMarcel Moolenaar * Support automatic commit by filling in the gpp_geom
106635fe9df0SMarcel Moolenaar * parameter.
106735fe9df0SMarcel Moolenaar */
106835fe9df0SMarcel Moolenaar gpp->gpp_parms |= G_PART_PARM_GEOM;
106935fe9df0SMarcel Moolenaar gpp->gpp_geom = gp;
107035fe9df0SMarcel Moolenaar
10715100f9e9SMarcel Moolenaar /* Provide feedback if so requested. */
10725100f9e9SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
10732616144eSDag-Erling Smørgrav sb = sbuf_new_auto();
10745100f9e9SMarcel Moolenaar sbuf_printf(sb, "%s created\n", gp->name);
107533a558c7SMarcel Moolenaar sbuf_finish(sb);
10765100f9e9SMarcel Moolenaar gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
10775100f9e9SMarcel Moolenaar sbuf_delete(sb);
10785100f9e9SMarcel Moolenaar }
10791d3aed33SMarcel Moolenaar return (0);
10801d3aed33SMarcel Moolenaar
10811d3aed33SMarcel Moolenaar fail:
10821d3aed33SMarcel Moolenaar g_topology_lock();
10831d3aed33SMarcel Moolenaar if (null == NULL) {
10841d3aed33SMarcel Moolenaar g_access(cp, -1, -1, -1);
10851d3aed33SMarcel Moolenaar g_part_wither(gp, error);
10861d3aed33SMarcel Moolenaar } else {
10871d3aed33SMarcel Moolenaar kobj_delete((kobj_t)gp->softc, M_GEOM);
10881d3aed33SMarcel Moolenaar gp->softc = null;
10891d3aed33SMarcel Moolenaar }
10901d3aed33SMarcel Moolenaar gctl_error(req, "%d provider", error);
10911d3aed33SMarcel Moolenaar return (error);
10921d3aed33SMarcel Moolenaar }
10931d3aed33SMarcel Moolenaar
10941d3aed33SMarcel Moolenaar static int
g_part_ctl_delete(struct gctl_req * req,struct g_part_parms * gpp)10951d3aed33SMarcel Moolenaar g_part_ctl_delete(struct gctl_req *req, struct g_part_parms *gpp)
10961d3aed33SMarcel Moolenaar {
10971d3aed33SMarcel Moolenaar struct g_geom *gp;
10981d3aed33SMarcel Moolenaar struct g_provider *pp;
10991d3aed33SMarcel Moolenaar struct g_part_entry *entry;
11001d3aed33SMarcel Moolenaar struct g_part_table *table;
11015100f9e9SMarcel Moolenaar struct sbuf *sb;
11021d3aed33SMarcel Moolenaar
11031d3aed33SMarcel Moolenaar gp = gpp->gpp_geom;
11041d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
11051d3aed33SMarcel Moolenaar g_topology_assert();
11061d3aed33SMarcel Moolenaar
11071d3aed33SMarcel Moolenaar table = gp->softc;
11081d3aed33SMarcel Moolenaar
11091d3aed33SMarcel Moolenaar LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
111004a814efSMarcel Moolenaar if (entry->gpe_deleted || entry->gpe_internal)
11111d3aed33SMarcel Moolenaar continue;
11121d3aed33SMarcel Moolenaar if (entry->gpe_index == gpp->gpp_index)
11131d3aed33SMarcel Moolenaar break;
11141d3aed33SMarcel Moolenaar }
11151d3aed33SMarcel Moolenaar if (entry == NULL) {
11161d3aed33SMarcel Moolenaar gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
11171d3aed33SMarcel Moolenaar return (ENOENT);
11181d3aed33SMarcel Moolenaar }
11191d3aed33SMarcel Moolenaar
11201d3aed33SMarcel Moolenaar pp = entry->gpe_pp;
11215aaa8fefSMarcel Moolenaar if (pp != NULL) {
11221d3aed33SMarcel Moolenaar if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) {
11231d3aed33SMarcel Moolenaar gctl_error(req, "%d", EBUSY);
11241d3aed33SMarcel Moolenaar return (EBUSY);
11251d3aed33SMarcel Moolenaar }
11261d3aed33SMarcel Moolenaar
11271d3aed33SMarcel Moolenaar pp->private = NULL;
11281d3aed33SMarcel Moolenaar entry->gpe_pp = NULL;
11295aaa8fefSMarcel Moolenaar }
11305aaa8fefSMarcel Moolenaar
11315aaa8fefSMarcel Moolenaar if (pp != NULL)
11321d3aed33SMarcel Moolenaar g_wither_provider(pp, ENXIO);
11335100f9e9SMarcel Moolenaar
11345100f9e9SMarcel Moolenaar /* Provide feedback if so requested. */
11355100f9e9SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
11362616144eSDag-Erling Smørgrav sb = sbuf_new_auto();
11376ad9a99fSMarcel Moolenaar G_PART_FULLNAME(table, entry, sb, gp->name);
11386ad9a99fSMarcel Moolenaar sbuf_cat(sb, " deleted\n");
113933a558c7SMarcel Moolenaar sbuf_finish(sb);
11405100f9e9SMarcel Moolenaar gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
11415100f9e9SMarcel Moolenaar sbuf_delete(sb);
11425100f9e9SMarcel Moolenaar }
1143733a9e27SAndrey V. Elsukov
1144733a9e27SAndrey V. Elsukov if (entry->gpe_created) {
1145733a9e27SAndrey V. Elsukov LIST_REMOVE(entry, gpe_entry);
1146733a9e27SAndrey V. Elsukov g_free(entry);
1147733a9e27SAndrey V. Elsukov } else {
1148733a9e27SAndrey V. Elsukov entry->gpe_modified = 0;
1149733a9e27SAndrey V. Elsukov entry->gpe_deleted = 1;
1150733a9e27SAndrey V. Elsukov }
11511d3aed33SMarcel Moolenaar return (0);
11521d3aed33SMarcel Moolenaar }
11531d3aed33SMarcel Moolenaar
11541d3aed33SMarcel Moolenaar static int
g_part_ctl_destroy(struct gctl_req * req,struct g_part_parms * gpp)11551d3aed33SMarcel Moolenaar g_part_ctl_destroy(struct gctl_req *req, struct g_part_parms *gpp)
11561d3aed33SMarcel Moolenaar {
11576f702278SMarcel Moolenaar struct g_consumer *cp;
11581d3aed33SMarcel Moolenaar struct g_geom *gp;
11596f702278SMarcel Moolenaar struct g_provider *pp;
1160e7926a37SAndrey V. Elsukov struct g_part_entry *entry, *tmp;
11611d3aed33SMarcel Moolenaar struct g_part_table *null, *table;
11625100f9e9SMarcel Moolenaar struct sbuf *sb;
11631d3aed33SMarcel Moolenaar int error;
11641d3aed33SMarcel Moolenaar
11651d3aed33SMarcel Moolenaar gp = gpp->gpp_geom;
11661d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
11671d3aed33SMarcel Moolenaar g_topology_assert();
11681d3aed33SMarcel Moolenaar
11691d3aed33SMarcel Moolenaar table = gp->softc;
1170e7926a37SAndrey V. Elsukov /* Check for busy providers. */
11711d3aed33SMarcel Moolenaar LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1172d6bbbeebSMarcel Moolenaar if (entry->gpe_deleted || entry->gpe_internal)
11731d3aed33SMarcel Moolenaar continue;
1174e7926a37SAndrey V. Elsukov if (gpp->gpp_force) {
1175e7926a37SAndrey V. Elsukov pp = entry->gpe_pp;
1176e7926a37SAndrey V. Elsukov if (pp == NULL)
1177e7926a37SAndrey V. Elsukov continue;
1178e7926a37SAndrey V. Elsukov if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0)
1179e7926a37SAndrey V. Elsukov continue;
1180e7926a37SAndrey V. Elsukov }
11811d3aed33SMarcel Moolenaar gctl_error(req, "%d", EBUSY);
11821d3aed33SMarcel Moolenaar return (EBUSY);
11831d3aed33SMarcel Moolenaar }
11841d3aed33SMarcel Moolenaar
1185e7926a37SAndrey V. Elsukov if (gpp->gpp_force) {
1186e7926a37SAndrey V. Elsukov /* Destroy all providers. */
1187e7926a37SAndrey V. Elsukov LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
1188e7926a37SAndrey V. Elsukov pp = entry->gpe_pp;
1189e7926a37SAndrey V. Elsukov if (pp != NULL) {
1190e7926a37SAndrey V. Elsukov pp->private = NULL;
1191e7926a37SAndrey V. Elsukov g_wither_provider(pp, ENXIO);
1192e7926a37SAndrey V. Elsukov }
1193e7926a37SAndrey V. Elsukov LIST_REMOVE(entry, gpe_entry);
1194e7926a37SAndrey V. Elsukov g_free(entry);
1195e7926a37SAndrey V. Elsukov }
1196e7926a37SAndrey V. Elsukov }
1197e7926a37SAndrey V. Elsukov
11981d3aed33SMarcel Moolenaar error = G_PART_DESTROY(table, gpp);
11991d3aed33SMarcel Moolenaar if (error) {
12001d3aed33SMarcel Moolenaar gctl_error(req, "%d", error);
12011d3aed33SMarcel Moolenaar return (error);
12021d3aed33SMarcel Moolenaar }
12031d3aed33SMarcel Moolenaar
12041d3aed33SMarcel Moolenaar gp->softc = kobj_create((kobj_class_t)&g_part_null_scheme, M_GEOM,
12051d3aed33SMarcel Moolenaar M_WAITOK);
12061d3aed33SMarcel Moolenaar null = gp->softc;
12071d3aed33SMarcel Moolenaar null->gpt_gp = gp;
12081d3aed33SMarcel Moolenaar null->gpt_scheme = &g_part_null_scheme;
12091d3aed33SMarcel Moolenaar LIST_INIT(&null->gpt_entry);
12106f702278SMarcel Moolenaar
12116f702278SMarcel Moolenaar cp = LIST_FIRST(&gp->consumer);
12126f702278SMarcel Moolenaar pp = cp->provider;
12136f702278SMarcel Moolenaar null->gpt_last = pp->mediasize / pp->sectorsize - 1;
12146f702278SMarcel Moolenaar
12151d3aed33SMarcel Moolenaar null->gpt_depth = table->gpt_depth;
12161d3aed33SMarcel Moolenaar null->gpt_opened = table->gpt_opened;
12171d3aed33SMarcel Moolenaar null->gpt_smhead = table->gpt_smhead;
12181d3aed33SMarcel Moolenaar null->gpt_smtail = table->gpt_smtail;
12191d3aed33SMarcel Moolenaar
12201d3aed33SMarcel Moolenaar while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
12211d3aed33SMarcel Moolenaar LIST_REMOVE(entry, gpe_entry);
12221d3aed33SMarcel Moolenaar g_free(entry);
12231d3aed33SMarcel Moolenaar }
12241d3aed33SMarcel Moolenaar kobj_delete((kobj_t)table, M_GEOM);
12251d3aed33SMarcel Moolenaar
12265100f9e9SMarcel Moolenaar /* Provide feedback if so requested. */
12275100f9e9SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
12282616144eSDag-Erling Smørgrav sb = sbuf_new_auto();
12295100f9e9SMarcel Moolenaar sbuf_printf(sb, "%s destroyed\n", gp->name);
123033a558c7SMarcel Moolenaar sbuf_finish(sb);
12315100f9e9SMarcel Moolenaar gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
12325100f9e9SMarcel Moolenaar sbuf_delete(sb);
12335100f9e9SMarcel Moolenaar }
12341d3aed33SMarcel Moolenaar return (0);
12351d3aed33SMarcel Moolenaar }
12361d3aed33SMarcel Moolenaar
12371d3aed33SMarcel Moolenaar static int
g_part_ctl_modify(struct gctl_req * req,struct g_part_parms * gpp)12381d3aed33SMarcel Moolenaar g_part_ctl_modify(struct gctl_req *req, struct g_part_parms *gpp)
12391d3aed33SMarcel Moolenaar {
12401d3aed33SMarcel Moolenaar struct g_geom *gp;
12411d3aed33SMarcel Moolenaar struct g_part_entry *entry;
12421d3aed33SMarcel Moolenaar struct g_part_table *table;
12435100f9e9SMarcel Moolenaar struct sbuf *sb;
12441d3aed33SMarcel Moolenaar int error;
12451d3aed33SMarcel Moolenaar
12461d3aed33SMarcel Moolenaar gp = gpp->gpp_geom;
12471d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
12481d3aed33SMarcel Moolenaar g_topology_assert();
12491d3aed33SMarcel Moolenaar
12501d3aed33SMarcel Moolenaar table = gp->softc;
12511d3aed33SMarcel Moolenaar
12521d3aed33SMarcel Moolenaar LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
125304a814efSMarcel Moolenaar if (entry->gpe_deleted || entry->gpe_internal)
12541d3aed33SMarcel Moolenaar continue;
12551d3aed33SMarcel Moolenaar if (entry->gpe_index == gpp->gpp_index)
12561d3aed33SMarcel Moolenaar break;
12571d3aed33SMarcel Moolenaar }
12581d3aed33SMarcel Moolenaar if (entry == NULL) {
12591d3aed33SMarcel Moolenaar gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
12601d3aed33SMarcel Moolenaar return (ENOENT);
12611d3aed33SMarcel Moolenaar }
12621d3aed33SMarcel Moolenaar
12631d3aed33SMarcel Moolenaar error = G_PART_MODIFY(table, entry, gpp);
12641d3aed33SMarcel Moolenaar if (error) {
12651d3aed33SMarcel Moolenaar gctl_error(req, "%d", error);
12661d3aed33SMarcel Moolenaar return (error);
12671d3aed33SMarcel Moolenaar }
12681d3aed33SMarcel Moolenaar
12691d3aed33SMarcel Moolenaar if (!entry->gpe_created)
12701d3aed33SMarcel Moolenaar entry->gpe_modified = 1;
12715100f9e9SMarcel Moolenaar
12725100f9e9SMarcel Moolenaar /* Provide feedback if so requested. */
12735100f9e9SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
12742616144eSDag-Erling Smørgrav sb = sbuf_new_auto();
12756ad9a99fSMarcel Moolenaar G_PART_FULLNAME(table, entry, sb, gp->name);
12766ad9a99fSMarcel Moolenaar sbuf_cat(sb, " modified\n");
127733a558c7SMarcel Moolenaar sbuf_finish(sb);
12785100f9e9SMarcel Moolenaar gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
12795100f9e9SMarcel Moolenaar sbuf_delete(sb);
12805100f9e9SMarcel Moolenaar }
12811d3aed33SMarcel Moolenaar return (0);
12821d3aed33SMarcel Moolenaar }
12831d3aed33SMarcel Moolenaar
12841d3aed33SMarcel Moolenaar static int
g_part_ctl_move(struct gctl_req * req,struct g_part_parms * gpp)12851d3aed33SMarcel Moolenaar g_part_ctl_move(struct gctl_req *req, struct g_part_parms *gpp)
12861d3aed33SMarcel Moolenaar {
12871d3aed33SMarcel Moolenaar gctl_error(req, "%d verb 'move'", ENOSYS);
12881d3aed33SMarcel Moolenaar return (ENOSYS);
12891d3aed33SMarcel Moolenaar }
12901d3aed33SMarcel Moolenaar
12911d3aed33SMarcel Moolenaar static int
g_part_ctl_recover(struct gctl_req * req,struct g_part_parms * gpp)12921d3aed33SMarcel Moolenaar g_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp)
12931d3aed33SMarcel Moolenaar {
1294e7926a37SAndrey V. Elsukov struct g_part_table *table;
1295e7926a37SAndrey V. Elsukov struct g_geom *gp;
1296e7926a37SAndrey V. Elsukov struct sbuf *sb;
1297e7926a37SAndrey V. Elsukov int error, recovered;
1298e7926a37SAndrey V. Elsukov
1299e7926a37SAndrey V. Elsukov gp = gpp->gpp_geom;
1300e7926a37SAndrey V. Elsukov G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1301e7926a37SAndrey V. Elsukov g_topology_assert();
1302e7926a37SAndrey V. Elsukov table = gp->softc;
1303e7926a37SAndrey V. Elsukov error = recovered = 0;
1304e7926a37SAndrey V. Elsukov
1305e7926a37SAndrey V. Elsukov if (table->gpt_corrupt) {
1306e7926a37SAndrey V. Elsukov error = G_PART_RECOVER(table);
13077b540236SAndrey V. Elsukov if (error == 0)
13087b540236SAndrey V. Elsukov error = g_part_check_integrity(table,
13097b540236SAndrey V. Elsukov LIST_FIRST(&gp->consumer));
1310e7926a37SAndrey V. Elsukov if (error) {
1311e7926a37SAndrey V. Elsukov gctl_error(req, "%d recovering '%s' failed",
1312e7926a37SAndrey V. Elsukov error, gp->name);
1313e7926a37SAndrey V. Elsukov return (error);
1314e7926a37SAndrey V. Elsukov }
1315e7926a37SAndrey V. Elsukov recovered = 1;
1316e7926a37SAndrey V. Elsukov }
1317e7926a37SAndrey V. Elsukov /* Provide feedback if so requested. */
1318e7926a37SAndrey V. Elsukov if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1319e7926a37SAndrey V. Elsukov sb = sbuf_new_auto();
1320e7926a37SAndrey V. Elsukov if (recovered)
1321e7926a37SAndrey V. Elsukov sbuf_printf(sb, "%s recovered\n", gp->name);
1322e7926a37SAndrey V. Elsukov else
1323e7926a37SAndrey V. Elsukov sbuf_printf(sb, "%s recovering is not needed\n",
1324e7926a37SAndrey V. Elsukov gp->name);
1325e7926a37SAndrey V. Elsukov sbuf_finish(sb);
1326e7926a37SAndrey V. Elsukov gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1327e7926a37SAndrey V. Elsukov sbuf_delete(sb);
1328e7926a37SAndrey V. Elsukov }
1329e7926a37SAndrey V. Elsukov return (0);
13301d3aed33SMarcel Moolenaar }
13311d3aed33SMarcel Moolenaar
13321d3aed33SMarcel Moolenaar static int
g_part_ctl_resize(struct gctl_req * req,struct g_part_parms * gpp)13331d3aed33SMarcel Moolenaar g_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp)
13341d3aed33SMarcel Moolenaar {
13353f71c319SMarcel Moolenaar struct g_geom *gp;
13363f71c319SMarcel Moolenaar struct g_provider *pp;
13373f71c319SMarcel Moolenaar struct g_part_entry *pe, *entry;
13383f71c319SMarcel Moolenaar struct g_part_table *table;
13393f71c319SMarcel Moolenaar struct sbuf *sb;
13403f71c319SMarcel Moolenaar quad_t end;
13413f71c319SMarcel Moolenaar int error;
1342a1cf7f75SEdward Tomasz Napierala off_t mediasize;
13433f71c319SMarcel Moolenaar
13443f71c319SMarcel Moolenaar gp = gpp->gpp_geom;
13453f71c319SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
13463f71c319SMarcel Moolenaar g_topology_assert();
13473f71c319SMarcel Moolenaar table = gp->softc;
13483f71c319SMarcel Moolenaar
13493f71c319SMarcel Moolenaar /* check gpp_index */
13503f71c319SMarcel Moolenaar LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
13513f71c319SMarcel Moolenaar if (entry->gpe_deleted || entry->gpe_internal)
13523f71c319SMarcel Moolenaar continue;
13533f71c319SMarcel Moolenaar if (entry->gpe_index == gpp->gpp_index)
13543f71c319SMarcel Moolenaar break;
13553f71c319SMarcel Moolenaar }
13563f71c319SMarcel Moolenaar if (entry == NULL) {
13573f71c319SMarcel Moolenaar gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
13583f71c319SMarcel Moolenaar return (ENOENT);
13593f71c319SMarcel Moolenaar }
13603f71c319SMarcel Moolenaar
13613f71c319SMarcel Moolenaar /* check gpp_size */
13623f71c319SMarcel Moolenaar end = entry->gpe_start + gpp->gpp_size - 1;
13633f71c319SMarcel Moolenaar if (gpp->gpp_size < 1 || end > table->gpt_last) {
13643f71c319SMarcel Moolenaar gctl_error(req, "%d size '%jd'", EINVAL,
13653f71c319SMarcel Moolenaar (intmax_t)gpp->gpp_size);
13663f71c319SMarcel Moolenaar return (EINVAL);
13673f71c319SMarcel Moolenaar }
13683f71c319SMarcel Moolenaar
13693f71c319SMarcel Moolenaar LIST_FOREACH(pe, &table->gpt_entry, gpe_entry) {
13703f71c319SMarcel Moolenaar if (pe->gpe_deleted || pe->gpe_internal || pe == entry)
13713f71c319SMarcel Moolenaar continue;
13723f71c319SMarcel Moolenaar if (end >= pe->gpe_start && end <= pe->gpe_end) {
13733f71c319SMarcel Moolenaar gctl_error(req, "%d end '%jd'", ENOSPC,
13743f71c319SMarcel Moolenaar (intmax_t)end);
13753f71c319SMarcel Moolenaar return (ENOSPC);
13763f71c319SMarcel Moolenaar }
13773f71c319SMarcel Moolenaar if (entry->gpe_start < pe->gpe_start && end > pe->gpe_end) {
13783f71c319SMarcel Moolenaar gctl_error(req, "%d size '%jd'", ENOSPC,
13793f71c319SMarcel Moolenaar (intmax_t)gpp->gpp_size);
13803f71c319SMarcel Moolenaar return (ENOSPC);
13813f71c319SMarcel Moolenaar }
13823f71c319SMarcel Moolenaar }
13833f71c319SMarcel Moolenaar
13843f71c319SMarcel Moolenaar pp = entry->gpe_pp;
1385c4c88d47SAlexander Motin if ((g_debugflags & G_F_FOOTSHOOTING) == 0 &&
13863f71c319SMarcel Moolenaar (pp->acr > 0 || pp->acw > 0 || pp->ace > 0)) {
1387a1cf7f75SEdward Tomasz Napierala if (entry->gpe_end - entry->gpe_start + 1 > gpp->gpp_size) {
1388a1cf7f75SEdward Tomasz Napierala /* Deny shrinking of an opened partition. */
13893f71c319SMarcel Moolenaar gctl_error(req, "%d", EBUSY);
13903f71c319SMarcel Moolenaar return (EBUSY);
13913f71c319SMarcel Moolenaar }
1392a1cf7f75SEdward Tomasz Napierala }
13933f71c319SMarcel Moolenaar
13943f71c319SMarcel Moolenaar error = G_PART_RESIZE(table, entry, gpp);
13953f71c319SMarcel Moolenaar if (error) {
1396c778397fSAndrey V. Elsukov gctl_error(req, "%d%s", error, error != EBUSY ? "":
1397c778397fSAndrey V. Elsukov " resizing will lead to unexpected shrinking"
1398c778397fSAndrey V. Elsukov " due to alignment");
13993f71c319SMarcel Moolenaar return (error);
14003f71c319SMarcel Moolenaar }
14013f71c319SMarcel Moolenaar
14023f71c319SMarcel Moolenaar if (!entry->gpe_created)
14033f71c319SMarcel Moolenaar entry->gpe_modified = 1;
14043f71c319SMarcel Moolenaar
14053f71c319SMarcel Moolenaar /* update mediasize of changed provider */
1406a1cf7f75SEdward Tomasz Napierala mediasize = (entry->gpe_end - entry->gpe_start + 1) *
14073f71c319SMarcel Moolenaar pp->sectorsize;
1408a1cf7f75SEdward Tomasz Napierala g_resize_provider(pp, mediasize);
14093f71c319SMarcel Moolenaar
14103f71c319SMarcel Moolenaar /* Provide feedback if so requested. */
14113f71c319SMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
14123f71c319SMarcel Moolenaar sb = sbuf_new_auto();
14133f71c319SMarcel Moolenaar G_PART_FULLNAME(table, entry, sb, gp->name);
14143f71c319SMarcel Moolenaar sbuf_cat(sb, " resized\n");
14153f71c319SMarcel Moolenaar sbuf_finish(sb);
14163f71c319SMarcel Moolenaar gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
14173f71c319SMarcel Moolenaar sbuf_delete(sb);
14183f71c319SMarcel Moolenaar }
14193f71c319SMarcel Moolenaar return (0);
14201d3aed33SMarcel Moolenaar }
14211d3aed33SMarcel Moolenaar
14221d3aed33SMarcel Moolenaar static int
g_part_ctl_setunset(struct gctl_req * req,struct g_part_parms * gpp,unsigned int set)1423f6aa3fccSMarcel Moolenaar g_part_ctl_setunset(struct gctl_req *req, struct g_part_parms *gpp,
1424f6aa3fccSMarcel Moolenaar unsigned int set)
1425f6aa3fccSMarcel Moolenaar {
1426f6aa3fccSMarcel Moolenaar struct g_geom *gp;
1427f6aa3fccSMarcel Moolenaar struct g_part_entry *entry;
1428f6aa3fccSMarcel Moolenaar struct g_part_table *table;
1429f6aa3fccSMarcel Moolenaar struct sbuf *sb;
1430f6aa3fccSMarcel Moolenaar int error;
1431f6aa3fccSMarcel Moolenaar
1432f6aa3fccSMarcel Moolenaar gp = gpp->gpp_geom;
1433f6aa3fccSMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1434f6aa3fccSMarcel Moolenaar g_topology_assert();
1435f6aa3fccSMarcel Moolenaar
1436f6aa3fccSMarcel Moolenaar table = gp->softc;
1437f6aa3fccSMarcel Moolenaar
14383bd22a9cSMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_INDEX) {
1439f6aa3fccSMarcel Moolenaar LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1440f6aa3fccSMarcel Moolenaar if (entry->gpe_deleted || entry->gpe_internal)
1441f6aa3fccSMarcel Moolenaar continue;
1442f6aa3fccSMarcel Moolenaar if (entry->gpe_index == gpp->gpp_index)
1443f6aa3fccSMarcel Moolenaar break;
1444f6aa3fccSMarcel Moolenaar }
1445f6aa3fccSMarcel Moolenaar if (entry == NULL) {
14463bd22a9cSMarcel Moolenaar gctl_error(req, "%d index '%d'", ENOENT,
14473bd22a9cSMarcel Moolenaar gpp->gpp_index);
1448f6aa3fccSMarcel Moolenaar return (ENOENT);
1449f6aa3fccSMarcel Moolenaar }
14503bd22a9cSMarcel Moolenaar } else
14513bd22a9cSMarcel Moolenaar entry = NULL;
1452f6aa3fccSMarcel Moolenaar
1453f6aa3fccSMarcel Moolenaar error = G_PART_SETUNSET(table, entry, gpp->gpp_attrib, set);
1454f6aa3fccSMarcel Moolenaar if (error) {
1455f6aa3fccSMarcel Moolenaar gctl_error(req, "%d attrib '%s'", error, gpp->gpp_attrib);
1456f6aa3fccSMarcel Moolenaar return (error);
1457f6aa3fccSMarcel Moolenaar }
1458f6aa3fccSMarcel Moolenaar
1459f6aa3fccSMarcel Moolenaar /* Provide feedback if so requested. */
1460f6aa3fccSMarcel Moolenaar if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
14612616144eSDag-Erling Smørgrav sb = sbuf_new_auto();
14622738b715SPawel Jakub Dawidek sbuf_printf(sb, "%s %sset on ", gpp->gpp_attrib,
14636ad9a99fSMarcel Moolenaar (set) ? "" : "un");
14643bd22a9cSMarcel Moolenaar if (entry)
14652738b715SPawel Jakub Dawidek G_PART_FULLNAME(table, entry, sb, gp->name);
14663bd22a9cSMarcel Moolenaar else
14673bd22a9cSMarcel Moolenaar sbuf_cat(sb, gp->name);
14683bd22a9cSMarcel Moolenaar sbuf_cat(sb, "\n");
1469f6aa3fccSMarcel Moolenaar sbuf_finish(sb);
1470f6aa3fccSMarcel Moolenaar gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1471f6aa3fccSMarcel Moolenaar sbuf_delete(sb);
1472f6aa3fccSMarcel Moolenaar }
1473f6aa3fccSMarcel Moolenaar return (0);
1474f6aa3fccSMarcel Moolenaar }
1475f6aa3fccSMarcel Moolenaar
1476f6aa3fccSMarcel Moolenaar static int
g_part_ctl_undo(struct gctl_req * req,struct g_part_parms * gpp)14771d3aed33SMarcel Moolenaar g_part_ctl_undo(struct gctl_req *req, struct g_part_parms *gpp)
14781d3aed33SMarcel Moolenaar {
14791d3aed33SMarcel Moolenaar struct g_consumer *cp;
14801d3aed33SMarcel Moolenaar struct g_provider *pp;
14811d3aed33SMarcel Moolenaar struct g_geom *gp;
14821d3aed33SMarcel Moolenaar struct g_part_entry *entry, *tmp;
14831d3aed33SMarcel Moolenaar struct g_part_table *table;
14841d3aed33SMarcel Moolenaar int error, reprobe;
14851d3aed33SMarcel Moolenaar
14861d3aed33SMarcel Moolenaar gp = gpp->gpp_geom;
14871d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
14881d3aed33SMarcel Moolenaar g_topology_assert();
14891d3aed33SMarcel Moolenaar
14901d3aed33SMarcel Moolenaar table = gp->softc;
14911d3aed33SMarcel Moolenaar if (!table->gpt_opened) {
14921d3aed33SMarcel Moolenaar gctl_error(req, "%d", EPERM);
14931d3aed33SMarcel Moolenaar return (EPERM);
14941d3aed33SMarcel Moolenaar }
14951d3aed33SMarcel Moolenaar
14961d3aed33SMarcel Moolenaar cp = LIST_FIRST(&gp->consumer);
14971d3aed33SMarcel Moolenaar LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
14981d3aed33SMarcel Moolenaar entry->gpe_modified = 0;
14991d3aed33SMarcel Moolenaar if (entry->gpe_created) {
15001d3aed33SMarcel Moolenaar pp = entry->gpe_pp;
15015aaa8fefSMarcel Moolenaar if (pp != NULL) {
15021d3aed33SMarcel Moolenaar pp->private = NULL;
15031d3aed33SMarcel Moolenaar entry->gpe_pp = NULL;
15041d3aed33SMarcel Moolenaar g_wither_provider(pp, ENXIO);
15055aaa8fefSMarcel Moolenaar }
15061d3aed33SMarcel Moolenaar entry->gpe_deleted = 1;
15071d3aed33SMarcel Moolenaar }
15081d3aed33SMarcel Moolenaar if (entry->gpe_deleted) {
15091d3aed33SMarcel Moolenaar LIST_REMOVE(entry, gpe_entry);
15101d3aed33SMarcel Moolenaar g_free(entry);
15111d3aed33SMarcel Moolenaar }
15121d3aed33SMarcel Moolenaar }
15131d3aed33SMarcel Moolenaar
15141d3aed33SMarcel Moolenaar g_topology_unlock();
15151d3aed33SMarcel Moolenaar
15161d3aed33SMarcel Moolenaar reprobe = (table->gpt_scheme == &g_part_null_scheme ||
15171d3aed33SMarcel Moolenaar table->gpt_created) ? 1 : 0;
15181d3aed33SMarcel Moolenaar
15191d3aed33SMarcel Moolenaar if (reprobe) {
15206f702278SMarcel Moolenaar LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
15216f702278SMarcel Moolenaar if (entry->gpe_internal)
15226f702278SMarcel Moolenaar continue;
15231d3aed33SMarcel Moolenaar error = EBUSY;
15241d3aed33SMarcel Moolenaar goto fail;
15251d3aed33SMarcel Moolenaar }
15266f702278SMarcel Moolenaar while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
15276f702278SMarcel Moolenaar LIST_REMOVE(entry, gpe_entry);
15286f702278SMarcel Moolenaar g_free(entry);
15296f702278SMarcel Moolenaar }
15301d3aed33SMarcel Moolenaar error = g_part_probe(gp, cp, table->gpt_depth);
1531c8dffc52SMarcel Moolenaar if (error) {
1532c8dffc52SMarcel Moolenaar g_topology_lock();
1533c8dffc52SMarcel Moolenaar g_access(cp, -1, -1, -1);
1534c8dffc52SMarcel Moolenaar g_part_wither(gp, error);
1535c8dffc52SMarcel Moolenaar return (0);
1536c8dffc52SMarcel Moolenaar }
15371d3aed33SMarcel Moolenaar table = gp->softc;
1538c74f160cSMarcel Moolenaar
1539c74f160cSMarcel Moolenaar /*
1540c74f160cSMarcel Moolenaar * Synthesize a disk geometry. Some partitioning schemes
1541c74f160cSMarcel Moolenaar * depend on it and since some file systems need it even
1542c74f160cSMarcel Moolenaar * when the partitition scheme doesn't, we do it here in
1543c74f160cSMarcel Moolenaar * scheme-independent code.
1544c74f160cSMarcel Moolenaar */
1545c74f160cSMarcel Moolenaar pp = cp->provider;
1546c74f160cSMarcel Moolenaar g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
15471d3aed33SMarcel Moolenaar }
15481d3aed33SMarcel Moolenaar
15491d3aed33SMarcel Moolenaar error = G_PART_READ(table, cp);
15501d3aed33SMarcel Moolenaar if (error)
15511d3aed33SMarcel Moolenaar goto fail;
1552c63e8fe2SAndrey V. Elsukov error = g_part_check_integrity(table, cp);
1553c63e8fe2SAndrey V. Elsukov if (error)
1554c63e8fe2SAndrey V. Elsukov goto fail;
15551d3aed33SMarcel Moolenaar
15561d3aed33SMarcel Moolenaar g_topology_lock();
15575aaa8fefSMarcel Moolenaar LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
15585aaa8fefSMarcel Moolenaar if (!entry->gpe_internal)
15591d3aed33SMarcel Moolenaar g_part_new_provider(gp, table, entry);
15605aaa8fefSMarcel Moolenaar }
15611d3aed33SMarcel Moolenaar
15621d3aed33SMarcel Moolenaar table->gpt_opened = 0;
15631d3aed33SMarcel Moolenaar g_access(cp, -1, -1, -1);
15641d3aed33SMarcel Moolenaar return (0);
15651d3aed33SMarcel Moolenaar
15661d3aed33SMarcel Moolenaar fail:
15671d3aed33SMarcel Moolenaar g_topology_lock();
15681d3aed33SMarcel Moolenaar gctl_error(req, "%d", error);
15691d3aed33SMarcel Moolenaar return (error);
15701d3aed33SMarcel Moolenaar }
15711d3aed33SMarcel Moolenaar
15721d3aed33SMarcel Moolenaar static void
g_part_wither(struct g_geom * gp,int error)15731d3aed33SMarcel Moolenaar g_part_wither(struct g_geom *gp, int error)
15741d3aed33SMarcel Moolenaar {
15751d3aed33SMarcel Moolenaar struct g_part_entry *entry;
15761d3aed33SMarcel Moolenaar struct g_part_table *table;
157708a3b42fSJustin Hibbits struct g_provider *pp;
15781d3aed33SMarcel Moolenaar
15791d3aed33SMarcel Moolenaar table = gp->softc;
15801d3aed33SMarcel Moolenaar if (table != NULL) {
158108a3b42fSJustin Hibbits gp->softc = NULL;
15821d3aed33SMarcel Moolenaar while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
15831d3aed33SMarcel Moolenaar LIST_REMOVE(entry, gpe_entry);
158408a3b42fSJustin Hibbits pp = entry->gpe_pp;
158508a3b42fSJustin Hibbits entry->gpe_pp = NULL;
1586d793587fSJustin Hibbits if (pp != NULL) {
1587d793587fSJustin Hibbits pp->private = NULL;
158808a3b42fSJustin Hibbits g_wither_provider(pp, error);
1589d793587fSJustin Hibbits }
15901d3aed33SMarcel Moolenaar g_free(entry);
15911d3aed33SMarcel Moolenaar }
159208a3b42fSJustin Hibbits G_PART_DESTROY(table, NULL);
159308a3b42fSJustin Hibbits kobj_delete((kobj_t)table, M_GEOM);
15941d3aed33SMarcel Moolenaar }
15951d3aed33SMarcel Moolenaar g_wither_geom(gp, error);
15961d3aed33SMarcel Moolenaar }
15971d3aed33SMarcel Moolenaar
15981d3aed33SMarcel Moolenaar /*
15991d3aed33SMarcel Moolenaar * Class methods.
16001d3aed33SMarcel Moolenaar */
16011d3aed33SMarcel Moolenaar
16021d3aed33SMarcel Moolenaar static void
g_part_ctlreq(struct gctl_req * req,struct g_class * mp,const char * verb)16031d3aed33SMarcel Moolenaar g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb)
16041d3aed33SMarcel Moolenaar {
16051d3aed33SMarcel Moolenaar struct g_part_parms gpp;
16061d3aed33SMarcel Moolenaar struct g_part_table *table;
16071d3aed33SMarcel Moolenaar struct gctl_req_arg *ap;
16081d3aed33SMarcel Moolenaar enum g_part_ctl ctlreq;
16091d3aed33SMarcel Moolenaar unsigned int i, mparms, oparms, parm;
161035fe9df0SMarcel Moolenaar int auto_commit, close_on_error;
16118107ecf8SPawel Jakub Dawidek int error, modifies;
16121d3aed33SMarcel Moolenaar
16131d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb));
16141d3aed33SMarcel Moolenaar g_topology_assert();
16151d3aed33SMarcel Moolenaar
16161d3aed33SMarcel Moolenaar ctlreq = G_PART_CTL_NONE;
161735fe9df0SMarcel Moolenaar modifies = 1;
1618d287f590SMarcel Moolenaar mparms = 0;
1619d287f590SMarcel Moolenaar oparms = G_PART_PARM_FLAGS | G_PART_PARM_OUTPUT | G_PART_PARM_VERSION;
16201d3aed33SMarcel Moolenaar switch (*verb) {
16211d3aed33SMarcel Moolenaar case 'a':
16221d3aed33SMarcel Moolenaar if (!strcmp(verb, "add")) {
16231d3aed33SMarcel Moolenaar ctlreq = G_PART_CTL_ADD;
1624d287f590SMarcel Moolenaar mparms |= G_PART_PARM_GEOM | G_PART_PARM_SIZE |
16251d3aed33SMarcel Moolenaar G_PART_PARM_START | G_PART_PARM_TYPE;
1626d287f590SMarcel Moolenaar oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL;
16271d3aed33SMarcel Moolenaar }
16281d3aed33SMarcel Moolenaar break;
16294d32fcb4SMarcel Moolenaar case 'b':
16304d32fcb4SMarcel Moolenaar if (!strcmp(verb, "bootcode")) {
16314d32fcb4SMarcel Moolenaar ctlreq = G_PART_CTL_BOOTCODE;
16324d32fcb4SMarcel Moolenaar mparms |= G_PART_PARM_GEOM | G_PART_PARM_BOOTCODE;
1633cdd2df88SDag-Erling Smørgrav oparms |= G_PART_PARM_SKIP_DSN;
16344d32fcb4SMarcel Moolenaar }
16354d32fcb4SMarcel Moolenaar break;
16361d3aed33SMarcel Moolenaar case 'c':
16371d3aed33SMarcel Moolenaar if (!strcmp(verb, "commit")) {
16381d3aed33SMarcel Moolenaar ctlreq = G_PART_CTL_COMMIT;
1639d287f590SMarcel Moolenaar mparms |= G_PART_PARM_GEOM;
164035fe9df0SMarcel Moolenaar modifies = 0;
16411d3aed33SMarcel Moolenaar } else if (!strcmp(verb, "create")) {
16421d3aed33SMarcel Moolenaar ctlreq = G_PART_CTL_CREATE;
1643d287f590SMarcel Moolenaar mparms |= G_PART_PARM_PROVIDER | G_PART_PARM_SCHEME;
1644d287f590SMarcel Moolenaar oparms |= G_PART_PARM_ENTRIES;
16451d3aed33SMarcel Moolenaar }
16461d3aed33SMarcel Moolenaar break;
16471d3aed33SMarcel Moolenaar case 'd':
16481d3aed33SMarcel Moolenaar if (!strcmp(verb, "delete")) {
16491d3aed33SMarcel Moolenaar ctlreq = G_PART_CTL_DELETE;
1650d287f590SMarcel Moolenaar mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
16511d3aed33SMarcel Moolenaar } else if (!strcmp(verb, "destroy")) {
16521d3aed33SMarcel Moolenaar ctlreq = G_PART_CTL_DESTROY;
1653d287f590SMarcel Moolenaar mparms |= G_PART_PARM_GEOM;
1654e7926a37SAndrey V. Elsukov oparms |= G_PART_PARM_FORCE;
16551d3aed33SMarcel Moolenaar }
16561d3aed33SMarcel Moolenaar break;
16571d3aed33SMarcel Moolenaar case 'm':
16581d3aed33SMarcel Moolenaar if (!strcmp(verb, "modify")) {
16591d3aed33SMarcel Moolenaar ctlreq = G_PART_CTL_MODIFY;
1660d287f590SMarcel Moolenaar mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1661d287f590SMarcel Moolenaar oparms |= G_PART_PARM_LABEL | G_PART_PARM_TYPE;
16621d3aed33SMarcel Moolenaar } else if (!strcmp(verb, "move")) {
16631d3aed33SMarcel Moolenaar ctlreq = G_PART_CTL_MOVE;
1664d287f590SMarcel Moolenaar mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
16651d3aed33SMarcel Moolenaar }
16661d3aed33SMarcel Moolenaar break;
16671d3aed33SMarcel Moolenaar case 'r':
16681d3aed33SMarcel Moolenaar if (!strcmp(verb, "recover")) {
16691d3aed33SMarcel Moolenaar ctlreq = G_PART_CTL_RECOVER;
1670d287f590SMarcel Moolenaar mparms |= G_PART_PARM_GEOM;
16711d3aed33SMarcel Moolenaar } else if (!strcmp(verb, "resize")) {
16721d3aed33SMarcel Moolenaar ctlreq = G_PART_CTL_RESIZE;
16733f71c319SMarcel Moolenaar mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX |
16743f71c319SMarcel Moolenaar G_PART_PARM_SIZE;
16751d3aed33SMarcel Moolenaar }
16761d3aed33SMarcel Moolenaar break;
1677f6aa3fccSMarcel Moolenaar case 's':
1678f6aa3fccSMarcel Moolenaar if (!strcmp(verb, "set")) {
1679f6aa3fccSMarcel Moolenaar ctlreq = G_PART_CTL_SET;
16803bd22a9cSMarcel Moolenaar mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM;
16813bd22a9cSMarcel Moolenaar oparms |= G_PART_PARM_INDEX;
1682f6aa3fccSMarcel Moolenaar }
1683f6aa3fccSMarcel Moolenaar break;
16841d3aed33SMarcel Moolenaar case 'u':
16851d3aed33SMarcel Moolenaar if (!strcmp(verb, "undo")) {
16861d3aed33SMarcel Moolenaar ctlreq = G_PART_CTL_UNDO;
1687d287f590SMarcel Moolenaar mparms |= G_PART_PARM_GEOM;
168835fe9df0SMarcel Moolenaar modifies = 0;
1689f6aa3fccSMarcel Moolenaar } else if (!strcmp(verb, "unset")) {
1690f6aa3fccSMarcel Moolenaar ctlreq = G_PART_CTL_UNSET;
16913bd22a9cSMarcel Moolenaar mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM;
16923bd22a9cSMarcel Moolenaar oparms |= G_PART_PARM_INDEX;
16931d3aed33SMarcel Moolenaar }
16941d3aed33SMarcel Moolenaar break;
16951d3aed33SMarcel Moolenaar }
16961d3aed33SMarcel Moolenaar if (ctlreq == G_PART_CTL_NONE) {
16971d3aed33SMarcel Moolenaar gctl_error(req, "%d verb '%s'", EINVAL, verb);
16981d3aed33SMarcel Moolenaar return;
16991d3aed33SMarcel Moolenaar }
17001d3aed33SMarcel Moolenaar
17011d3aed33SMarcel Moolenaar bzero(&gpp, sizeof(gpp));
17021d3aed33SMarcel Moolenaar for (i = 0; i < req->narg; i++) {
17031d3aed33SMarcel Moolenaar ap = &req->arg[i];
17041d3aed33SMarcel Moolenaar parm = 0;
17051d3aed33SMarcel Moolenaar switch (ap->name[0]) {
1706f6aa3fccSMarcel Moolenaar case 'a':
1707946e2f35SPawel Jakub Dawidek if (!strcmp(ap->name, "arg0")) {
1708946e2f35SPawel Jakub Dawidek parm = mparms &
1709946e2f35SPawel Jakub Dawidek (G_PART_PARM_GEOM | G_PART_PARM_PROVIDER);
1710946e2f35SPawel Jakub Dawidek }
1711f6aa3fccSMarcel Moolenaar if (!strcmp(ap->name, "attrib"))
1712f6aa3fccSMarcel Moolenaar parm = G_PART_PARM_ATTRIB;
1713f6aa3fccSMarcel Moolenaar break;
17144d32fcb4SMarcel Moolenaar case 'b':
17154d32fcb4SMarcel Moolenaar if (!strcmp(ap->name, "bootcode"))
17164d32fcb4SMarcel Moolenaar parm = G_PART_PARM_BOOTCODE;
17174d32fcb4SMarcel Moolenaar break;
17181d3aed33SMarcel Moolenaar case 'c':
17191d3aed33SMarcel Moolenaar if (!strcmp(ap->name, "class"))
17201d3aed33SMarcel Moolenaar continue;
17211d3aed33SMarcel Moolenaar break;
17221d3aed33SMarcel Moolenaar case 'e':
17231d3aed33SMarcel Moolenaar if (!strcmp(ap->name, "entries"))
17241d3aed33SMarcel Moolenaar parm = G_PART_PARM_ENTRIES;
17251d3aed33SMarcel Moolenaar break;
17261d3aed33SMarcel Moolenaar case 'f':
17271d3aed33SMarcel Moolenaar if (!strcmp(ap->name, "flags"))
17281d3aed33SMarcel Moolenaar parm = G_PART_PARM_FLAGS;
1729e7926a37SAndrey V. Elsukov else if (!strcmp(ap->name, "force"))
1730e7926a37SAndrey V. Elsukov parm = G_PART_PARM_FORCE;
17311d3aed33SMarcel Moolenaar break;
17321d3aed33SMarcel Moolenaar case 'i':
17331d3aed33SMarcel Moolenaar if (!strcmp(ap->name, "index"))
17341d3aed33SMarcel Moolenaar parm = G_PART_PARM_INDEX;
17351d3aed33SMarcel Moolenaar break;
17361d3aed33SMarcel Moolenaar case 'l':
17371d3aed33SMarcel Moolenaar if (!strcmp(ap->name, "label"))
17381d3aed33SMarcel Moolenaar parm = G_PART_PARM_LABEL;
17391d3aed33SMarcel Moolenaar break;
1740d287f590SMarcel Moolenaar case 'o':
1741d287f590SMarcel Moolenaar if (!strcmp(ap->name, "output"))
1742d287f590SMarcel Moolenaar parm = G_PART_PARM_OUTPUT;
1743d287f590SMarcel Moolenaar break;
17441d3aed33SMarcel Moolenaar case 's':
17451d3aed33SMarcel Moolenaar if (!strcmp(ap->name, "scheme"))
17461d3aed33SMarcel Moolenaar parm = G_PART_PARM_SCHEME;
17471d3aed33SMarcel Moolenaar else if (!strcmp(ap->name, "size"))
17481d3aed33SMarcel Moolenaar parm = G_PART_PARM_SIZE;
17491d3aed33SMarcel Moolenaar else if (!strcmp(ap->name, "start"))
17501d3aed33SMarcel Moolenaar parm = G_PART_PARM_START;
1751cdd2df88SDag-Erling Smørgrav else if (!strcmp(ap->name, "skip_dsn"))
1752cdd2df88SDag-Erling Smørgrav parm = G_PART_PARM_SKIP_DSN;
17531d3aed33SMarcel Moolenaar break;
17541d3aed33SMarcel Moolenaar case 't':
17551d3aed33SMarcel Moolenaar if (!strcmp(ap->name, "type"))
17561d3aed33SMarcel Moolenaar parm = G_PART_PARM_TYPE;
17571d3aed33SMarcel Moolenaar break;
17581d3aed33SMarcel Moolenaar case 'v':
17591d3aed33SMarcel Moolenaar if (!strcmp(ap->name, "verb"))
17601d3aed33SMarcel Moolenaar continue;
1761d287f590SMarcel Moolenaar else if (!strcmp(ap->name, "version"))
1762d287f590SMarcel Moolenaar parm = G_PART_PARM_VERSION;
17631d3aed33SMarcel Moolenaar break;
17641d3aed33SMarcel Moolenaar }
17651d3aed33SMarcel Moolenaar if ((parm & (mparms | oparms)) == 0) {
17661d3aed33SMarcel Moolenaar gctl_error(req, "%d param '%s'", EINVAL, ap->name);
17671d3aed33SMarcel Moolenaar return;
17681d3aed33SMarcel Moolenaar }
17691d3aed33SMarcel Moolenaar switch (parm) {
1770f6aa3fccSMarcel Moolenaar case G_PART_PARM_ATTRIB:
1771e7926a37SAndrey V. Elsukov error = g_part_parm_str(req, ap->name,
1772e7926a37SAndrey V. Elsukov &gpp.gpp_attrib);
1773f6aa3fccSMarcel Moolenaar break;
17744d32fcb4SMarcel Moolenaar case G_PART_PARM_BOOTCODE:
17758107ecf8SPawel Jakub Dawidek error = g_part_parm_bootcode(req, ap->name,
17768107ecf8SPawel Jakub Dawidek &gpp.gpp_codeptr, &gpp.gpp_codesize);
17774d32fcb4SMarcel Moolenaar break;
17781d3aed33SMarcel Moolenaar case G_PART_PARM_ENTRIES:
17798107ecf8SPawel Jakub Dawidek error = g_part_parm_intmax(req, ap->name,
17808107ecf8SPawel Jakub Dawidek &gpp.gpp_entries);
17811d3aed33SMarcel Moolenaar break;
17821d3aed33SMarcel Moolenaar case G_PART_PARM_FLAGS:
17838107ecf8SPawel Jakub Dawidek error = g_part_parm_str(req, ap->name, &gpp.gpp_flags);
17841d3aed33SMarcel Moolenaar break;
1785e7926a37SAndrey V. Elsukov case G_PART_PARM_FORCE:
1786e7926a37SAndrey V. Elsukov error = g_part_parm_uint32(req, ap->name,
1787e7926a37SAndrey V. Elsukov &gpp.gpp_force);
1788e7926a37SAndrey V. Elsukov break;
17891d3aed33SMarcel Moolenaar case G_PART_PARM_GEOM:
17908107ecf8SPawel Jakub Dawidek error = g_part_parm_geom(req, ap->name, &gpp.gpp_geom);
17911d3aed33SMarcel Moolenaar break;
17921d3aed33SMarcel Moolenaar case G_PART_PARM_INDEX:
1793e7926a37SAndrey V. Elsukov error = g_part_parm_intmax(req, ap->name,
1794e7926a37SAndrey V. Elsukov &gpp.gpp_index);
17951d3aed33SMarcel Moolenaar break;
17961d3aed33SMarcel Moolenaar case G_PART_PARM_LABEL:
17978107ecf8SPawel Jakub Dawidek error = g_part_parm_str(req, ap->name, &gpp.gpp_label);
17981d3aed33SMarcel Moolenaar break;
1799d287f590SMarcel Moolenaar case G_PART_PARM_OUTPUT:
1800d287f590SMarcel Moolenaar error = 0; /* Write-only parameter */
1801d287f590SMarcel Moolenaar break;
18021d3aed33SMarcel Moolenaar case G_PART_PARM_PROVIDER:
18038107ecf8SPawel Jakub Dawidek error = g_part_parm_provider(req, ap->name,
18048107ecf8SPawel Jakub Dawidek &gpp.gpp_provider);
18051d3aed33SMarcel Moolenaar break;
18061d3aed33SMarcel Moolenaar case G_PART_PARM_SCHEME:
18078107ecf8SPawel Jakub Dawidek error = g_part_parm_scheme(req, ap->name,
18088107ecf8SPawel Jakub Dawidek &gpp.gpp_scheme);
18091d3aed33SMarcel Moolenaar break;
18101d3aed33SMarcel Moolenaar case G_PART_PARM_SIZE:
18118107ecf8SPawel Jakub Dawidek error = g_part_parm_quad(req, ap->name, &gpp.gpp_size);
18121d3aed33SMarcel Moolenaar break;
1813cdd2df88SDag-Erling Smørgrav case G_PART_PARM_SKIP_DSN:
1814cdd2df88SDag-Erling Smørgrav error = g_part_parm_uint32(req, ap->name,
1815cdd2df88SDag-Erling Smørgrav &gpp.gpp_skip_dsn);
1816cdd2df88SDag-Erling Smørgrav break;
18171d3aed33SMarcel Moolenaar case G_PART_PARM_START:
1818e7926a37SAndrey V. Elsukov error = g_part_parm_quad(req, ap->name,
1819e7926a37SAndrey V. Elsukov &gpp.gpp_start);
18201d3aed33SMarcel Moolenaar break;
18211d3aed33SMarcel Moolenaar case G_PART_PARM_TYPE:
18228107ecf8SPawel Jakub Dawidek error = g_part_parm_str(req, ap->name, &gpp.gpp_type);
18231d3aed33SMarcel Moolenaar break;
1824d287f590SMarcel Moolenaar case G_PART_PARM_VERSION:
18258107ecf8SPawel Jakub Dawidek error = g_part_parm_uint32(req, ap->name,
18268107ecf8SPawel Jakub Dawidek &gpp.gpp_version);
1827d287f590SMarcel Moolenaar break;
18281d3aed33SMarcel Moolenaar default:
18291d3aed33SMarcel Moolenaar error = EDOOFUS;
18308107ecf8SPawel Jakub Dawidek gctl_error(req, "%d %s", error, ap->name);
18311d3aed33SMarcel Moolenaar break;
18321d3aed33SMarcel Moolenaar }
18338107ecf8SPawel Jakub Dawidek if (error != 0) {
18348107ecf8SPawel Jakub Dawidek if (error == ENOATTR) {
18358107ecf8SPawel Jakub Dawidek gctl_error(req, "%d param '%s'", error,
18368107ecf8SPawel Jakub Dawidek ap->name);
18378107ecf8SPawel Jakub Dawidek }
18381d3aed33SMarcel Moolenaar return;
18391d3aed33SMarcel Moolenaar }
18401d3aed33SMarcel Moolenaar gpp.gpp_parms |= parm;
18411d3aed33SMarcel Moolenaar }
18421d3aed33SMarcel Moolenaar if ((gpp.gpp_parms & mparms) != mparms) {
18431d3aed33SMarcel Moolenaar parm = mparms - (gpp.gpp_parms & mparms);
18441d3aed33SMarcel Moolenaar gctl_error(req, "%d param '%x'", ENOATTR, parm);
18451d3aed33SMarcel Moolenaar return;
18461d3aed33SMarcel Moolenaar }
18471d3aed33SMarcel Moolenaar
18481d3aed33SMarcel Moolenaar /* Obtain permissions if possible/necessary. */
184935fe9df0SMarcel Moolenaar close_on_error = 0;
18507ca4fa83SMarcel Moolenaar table = NULL;
18511d3aed33SMarcel Moolenaar if (modifies && (gpp.gpp_parms & G_PART_PARM_GEOM)) {
18521d3aed33SMarcel Moolenaar table = gpp.gpp_geom->softc;
1853e7926a37SAndrey V. Elsukov if (table != NULL && table->gpt_corrupt &&
1854e7926a37SAndrey V. Elsukov ctlreq != G_PART_CTL_DESTROY &&
1855b2b5d4c0SEugene Grosbein ctlreq != G_PART_CTL_RECOVER &&
1856b2b5d4c0SEugene Grosbein geom_part_check_integrity) {
1857e7926a37SAndrey V. Elsukov gctl_error(req, "%d table '%s' is corrupt",
1858e7926a37SAndrey V. Elsukov EPERM, gpp.gpp_geom->name);
1859e7926a37SAndrey V. Elsukov return;
1860e7926a37SAndrey V. Elsukov }
18611d3aed33SMarcel Moolenaar if (table != NULL && !table->gpt_opened) {
18621d3aed33SMarcel Moolenaar error = g_access(LIST_FIRST(&gpp.gpp_geom->consumer),
18631d3aed33SMarcel Moolenaar 1, 1, 1);
18641d3aed33SMarcel Moolenaar if (error) {
18651d3aed33SMarcel Moolenaar gctl_error(req, "%d geom '%s'", error,
18661d3aed33SMarcel Moolenaar gpp.gpp_geom->name);
18671d3aed33SMarcel Moolenaar return;
18681d3aed33SMarcel Moolenaar }
18691d3aed33SMarcel Moolenaar table->gpt_opened = 1;
187035fe9df0SMarcel Moolenaar close_on_error = 1;
18711d3aed33SMarcel Moolenaar }
18721d3aed33SMarcel Moolenaar }
18731d3aed33SMarcel Moolenaar
18747ca4fa83SMarcel Moolenaar /* Allow the scheme to check or modify the parameters. */
18757ca4fa83SMarcel Moolenaar if (table != NULL) {
18767ca4fa83SMarcel Moolenaar error = G_PART_PRECHECK(table, ctlreq, &gpp);
18777ca4fa83SMarcel Moolenaar if (error) {
18787ca4fa83SMarcel Moolenaar gctl_error(req, "%d pre-check failed", error);
18797ca4fa83SMarcel Moolenaar goto out;
18807ca4fa83SMarcel Moolenaar }
18817ca4fa83SMarcel Moolenaar } else
18821d3aed33SMarcel Moolenaar error = EDOOFUS; /* Prevent bogus uninit. warning. */
18837ca4fa83SMarcel Moolenaar
18841d3aed33SMarcel Moolenaar switch (ctlreq) {
18851d3aed33SMarcel Moolenaar case G_PART_CTL_NONE:
18861d3aed33SMarcel Moolenaar panic("%s", __func__);
18871d3aed33SMarcel Moolenaar case G_PART_CTL_ADD:
18881d3aed33SMarcel Moolenaar error = g_part_ctl_add(req, &gpp);
18891d3aed33SMarcel Moolenaar break;
18904d32fcb4SMarcel Moolenaar case G_PART_CTL_BOOTCODE:
18914d32fcb4SMarcel Moolenaar error = g_part_ctl_bootcode(req, &gpp);
18924d32fcb4SMarcel Moolenaar break;
18931d3aed33SMarcel Moolenaar case G_PART_CTL_COMMIT:
18941d3aed33SMarcel Moolenaar error = g_part_ctl_commit(req, &gpp);
18951d3aed33SMarcel Moolenaar break;
18961d3aed33SMarcel Moolenaar case G_PART_CTL_CREATE:
18971d3aed33SMarcel Moolenaar error = g_part_ctl_create(req, &gpp);
18981d3aed33SMarcel Moolenaar break;
18991d3aed33SMarcel Moolenaar case G_PART_CTL_DELETE:
19001d3aed33SMarcel Moolenaar error = g_part_ctl_delete(req, &gpp);
19011d3aed33SMarcel Moolenaar break;
19021d3aed33SMarcel Moolenaar case G_PART_CTL_DESTROY:
19031d3aed33SMarcel Moolenaar error = g_part_ctl_destroy(req, &gpp);
19041d3aed33SMarcel Moolenaar break;
19051d3aed33SMarcel Moolenaar case G_PART_CTL_MODIFY:
19061d3aed33SMarcel Moolenaar error = g_part_ctl_modify(req, &gpp);
19071d3aed33SMarcel Moolenaar break;
19081d3aed33SMarcel Moolenaar case G_PART_CTL_MOVE:
19091d3aed33SMarcel Moolenaar error = g_part_ctl_move(req, &gpp);
19101d3aed33SMarcel Moolenaar break;
19111d3aed33SMarcel Moolenaar case G_PART_CTL_RECOVER:
19121d3aed33SMarcel Moolenaar error = g_part_ctl_recover(req, &gpp);
19131d3aed33SMarcel Moolenaar break;
19141d3aed33SMarcel Moolenaar case G_PART_CTL_RESIZE:
19151d3aed33SMarcel Moolenaar error = g_part_ctl_resize(req, &gpp);
19161d3aed33SMarcel Moolenaar break;
1917f6aa3fccSMarcel Moolenaar case G_PART_CTL_SET:
1918f6aa3fccSMarcel Moolenaar error = g_part_ctl_setunset(req, &gpp, 1);
1919f6aa3fccSMarcel Moolenaar break;
19201d3aed33SMarcel Moolenaar case G_PART_CTL_UNDO:
19211d3aed33SMarcel Moolenaar error = g_part_ctl_undo(req, &gpp);
19221d3aed33SMarcel Moolenaar break;
1923f6aa3fccSMarcel Moolenaar case G_PART_CTL_UNSET:
1924f6aa3fccSMarcel Moolenaar error = g_part_ctl_setunset(req, &gpp, 0);
1925f6aa3fccSMarcel Moolenaar break;
19261d3aed33SMarcel Moolenaar }
192735fe9df0SMarcel Moolenaar
192835fe9df0SMarcel Moolenaar /* Implement automatic commit. */
192935fe9df0SMarcel Moolenaar if (!error) {
193035fe9df0SMarcel Moolenaar auto_commit = (modifies &&
193135fe9df0SMarcel Moolenaar (gpp.gpp_parms & G_PART_PARM_FLAGS) &&
193235fe9df0SMarcel Moolenaar strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0;
193335fe9df0SMarcel Moolenaar if (auto_commit) {
193442a783c1SRui Paulo KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, ("%s",
193542a783c1SRui Paulo __func__));
193635fe9df0SMarcel Moolenaar error = g_part_ctl_commit(req, &gpp);
193735fe9df0SMarcel Moolenaar }
193835fe9df0SMarcel Moolenaar }
193935fe9df0SMarcel Moolenaar
19407ca4fa83SMarcel Moolenaar out:
194135fe9df0SMarcel Moolenaar if (error && close_on_error) {
194235fe9df0SMarcel Moolenaar g_access(LIST_FIRST(&gpp.gpp_geom->consumer), -1, -1, -1);
194335fe9df0SMarcel Moolenaar table->gpt_opened = 0;
194435fe9df0SMarcel Moolenaar }
19451d3aed33SMarcel Moolenaar }
19461d3aed33SMarcel Moolenaar
19471d3aed33SMarcel Moolenaar static int
g_part_destroy_geom(struct gctl_req * req,struct g_class * mp,struct g_geom * gp)19481d3aed33SMarcel Moolenaar g_part_destroy_geom(struct gctl_req *req, struct g_class *mp,
19491d3aed33SMarcel Moolenaar struct g_geom *gp)
19501d3aed33SMarcel Moolenaar {
19511d3aed33SMarcel Moolenaar
19521d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name));
19531d3aed33SMarcel Moolenaar g_topology_assert();
19541d3aed33SMarcel Moolenaar
19551d3aed33SMarcel Moolenaar g_part_wither(gp, EINVAL);
19561d3aed33SMarcel Moolenaar return (0);
19571d3aed33SMarcel Moolenaar }
19581d3aed33SMarcel Moolenaar
19591d3aed33SMarcel Moolenaar static struct g_geom *
g_part_taste(struct g_class * mp,struct g_provider * pp,int flags __unused)19601d3aed33SMarcel Moolenaar g_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
19611d3aed33SMarcel Moolenaar {
19621d3aed33SMarcel Moolenaar struct g_consumer *cp;
19631d3aed33SMarcel Moolenaar struct g_geom *gp;
19641d3aed33SMarcel Moolenaar struct g_part_entry *entry;
19651d3aed33SMarcel Moolenaar struct g_part_table *table;
1966a455de09SMarcel Moolenaar struct root_hold_token *rht;
19671d3aed33SMarcel Moolenaar int attr, depth;
19681d3aed33SMarcel Moolenaar int error;
19691d3aed33SMarcel Moolenaar
19701d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name));
19711d3aed33SMarcel Moolenaar g_topology_assert();
19721d3aed33SMarcel Moolenaar
1973f8727e71SPawel Jakub Dawidek /* Skip providers that are already open for writing. */
1974f8727e71SPawel Jakub Dawidek if (pp->acw > 0)
1975f8727e71SPawel Jakub Dawidek return (NULL);
1976f8727e71SPawel Jakub Dawidek
19771d3aed33SMarcel Moolenaar /*
19781d3aed33SMarcel Moolenaar * Create a GEOM with consumer and hook it up to the provider.
19795d7d1329SWarner Losh * With that we become part of the topology. Obtain read access
19801d3aed33SMarcel Moolenaar * to the provider.
19811d3aed33SMarcel Moolenaar */
19821d3aed33SMarcel Moolenaar gp = g_new_geomf(mp, "%s", pp->name);
19831d3aed33SMarcel Moolenaar cp = g_new_consumer(gp);
198440ea77a0SAlexander Motin cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
19851d3aed33SMarcel Moolenaar error = g_attach(cp, pp);
19861d3aed33SMarcel Moolenaar if (error == 0)
19871d3aed33SMarcel Moolenaar error = g_access(cp, 1, 0, 0);
19881d3aed33SMarcel Moolenaar if (error != 0) {
1989a90c9dfeSAndriy Gapon if (cp->provider)
1990a90c9dfeSAndriy Gapon g_detach(cp);
1991a90c9dfeSAndriy Gapon g_destroy_consumer(cp);
1992a90c9dfeSAndriy Gapon g_destroy_geom(gp);
19931d3aed33SMarcel Moolenaar return (NULL);
19941d3aed33SMarcel Moolenaar }
19951d3aed33SMarcel Moolenaar
1996853a10a5SAndrew Thompson rht = root_mount_hold(mp->name);
19971d3aed33SMarcel Moolenaar g_topology_unlock();
19981d3aed33SMarcel Moolenaar
19990081f96eSMarcel Moolenaar /*
20000081f96eSMarcel Moolenaar * Short-circuit the whole probing galore when there's no
20010081f96eSMarcel Moolenaar * media present.
20020081f96eSMarcel Moolenaar */
20030081f96eSMarcel Moolenaar if (pp->mediasize == 0 || pp->sectorsize == 0) {
20040081f96eSMarcel Moolenaar error = ENODEV;
20050081f96eSMarcel Moolenaar goto fail;
20060081f96eSMarcel Moolenaar }
20070081f96eSMarcel Moolenaar
20081d3aed33SMarcel Moolenaar /* Make sure we can nest and if so, determine our depth. */
20091d3aed33SMarcel Moolenaar error = g_getattr("PART::isleaf", cp, &attr);
20101d3aed33SMarcel Moolenaar if (!error && attr) {
20111d3aed33SMarcel Moolenaar error = ENODEV;
20121d3aed33SMarcel Moolenaar goto fail;
20131d3aed33SMarcel Moolenaar }
20141d3aed33SMarcel Moolenaar error = g_getattr("PART::depth", cp, &attr);
20151d3aed33SMarcel Moolenaar depth = (!error) ? attr + 1 : 0;
20161d3aed33SMarcel Moolenaar
20171d3aed33SMarcel Moolenaar error = g_part_probe(gp, cp, depth);
20181d3aed33SMarcel Moolenaar if (error)
20191d3aed33SMarcel Moolenaar goto fail;
20201d3aed33SMarcel Moolenaar
20211d3aed33SMarcel Moolenaar table = gp->softc;
20220081f96eSMarcel Moolenaar
20230081f96eSMarcel Moolenaar /*
20240081f96eSMarcel Moolenaar * Synthesize a disk geometry. Some partitioning schemes
20250081f96eSMarcel Moolenaar * depend on it and since some file systems need it even
20260081f96eSMarcel Moolenaar * when the partitition scheme doesn't, we do it here in
20270081f96eSMarcel Moolenaar * scheme-independent code.
20280081f96eSMarcel Moolenaar */
20290081f96eSMarcel Moolenaar g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
20300081f96eSMarcel Moolenaar
20311d3aed33SMarcel Moolenaar error = G_PART_READ(table, cp);
20321d3aed33SMarcel Moolenaar if (error)
20331d3aed33SMarcel Moolenaar goto fail;
2034c63e8fe2SAndrey V. Elsukov error = g_part_check_integrity(table, cp);
2035c63e8fe2SAndrey V. Elsukov if (error)
2036c63e8fe2SAndrey V. Elsukov goto fail;
20371d3aed33SMarcel Moolenaar
20381d3aed33SMarcel Moolenaar g_topology_lock();
20395aaa8fefSMarcel Moolenaar LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
20405aaa8fefSMarcel Moolenaar if (!entry->gpe_internal)
20411d3aed33SMarcel Moolenaar g_part_new_provider(gp, table, entry);
20425aaa8fefSMarcel Moolenaar }
20431d3aed33SMarcel Moolenaar
2044a455de09SMarcel Moolenaar root_mount_rel(rht);
20451d3aed33SMarcel Moolenaar g_access(cp, -1, 0, 0);
20461d3aed33SMarcel Moolenaar return (gp);
20471d3aed33SMarcel Moolenaar
20481d3aed33SMarcel Moolenaar fail:
20491d3aed33SMarcel Moolenaar g_topology_lock();
2050a455de09SMarcel Moolenaar root_mount_rel(rht);
20511d3aed33SMarcel Moolenaar g_access(cp, -1, 0, 0);
2052a90c9dfeSAndriy Gapon g_detach(cp);
2053a90c9dfeSAndriy Gapon g_destroy_consumer(cp);
2054a90c9dfeSAndriy Gapon g_destroy_geom(gp);
20551d3aed33SMarcel Moolenaar return (NULL);
20561d3aed33SMarcel Moolenaar }
20571d3aed33SMarcel Moolenaar
20581d3aed33SMarcel Moolenaar /*
20591d3aed33SMarcel Moolenaar * Geom methods.
20601d3aed33SMarcel Moolenaar */
20611d3aed33SMarcel Moolenaar
20621d3aed33SMarcel Moolenaar static int
g_part_access(struct g_provider * pp,int dr,int dw,int de)20631d3aed33SMarcel Moolenaar g_part_access(struct g_provider *pp, int dr, int dw, int de)
20641d3aed33SMarcel Moolenaar {
20651d3aed33SMarcel Moolenaar struct g_consumer *cp;
20661d3aed33SMarcel Moolenaar
20671d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr,
20681d3aed33SMarcel Moolenaar dw, de));
20691d3aed33SMarcel Moolenaar
20701d3aed33SMarcel Moolenaar cp = LIST_FIRST(&pp->geom->consumer);
20711d3aed33SMarcel Moolenaar
20721d3aed33SMarcel Moolenaar /* We always gain write-exclusive access. */
20731d3aed33SMarcel Moolenaar return (g_access(cp, dr, dw, dw + de));
20741d3aed33SMarcel Moolenaar }
20751d3aed33SMarcel Moolenaar
20761d3aed33SMarcel Moolenaar static void
g_part_dumpconf(struct sbuf * sb,const char * indent,struct g_geom * gp,struct g_consumer * cp,struct g_provider * pp)20771d3aed33SMarcel Moolenaar g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
20781d3aed33SMarcel Moolenaar struct g_consumer *cp, struct g_provider *pp)
20791d3aed33SMarcel Moolenaar {
20801d3aed33SMarcel Moolenaar char buf[64];
20811d3aed33SMarcel Moolenaar struct g_part_entry *entry;
20821d3aed33SMarcel Moolenaar struct g_part_table *table;
20831d3aed33SMarcel Moolenaar
208442a783c1SRui Paulo KASSERT(sb != NULL && gp != NULL, ("%s", __func__));
20851d3aed33SMarcel Moolenaar table = gp->softc;
20861d3aed33SMarcel Moolenaar
20871d3aed33SMarcel Moolenaar if (indent == NULL) {
208842a783c1SRui Paulo KASSERT(cp == NULL && pp != NULL, ("%s", __func__));
20891d3aed33SMarcel Moolenaar entry = pp->private;
20901d3aed33SMarcel Moolenaar if (entry == NULL)
20911d3aed33SMarcel Moolenaar return;
20921d3aed33SMarcel Moolenaar sbuf_printf(sb, " i %u o %ju ty %s", entry->gpe_index,
20931d3aed33SMarcel Moolenaar (uintmax_t)entry->gpe_offset,
20941d3aed33SMarcel Moolenaar G_PART_TYPE(table, entry, buf, sizeof(buf)));
20955db67052SMarcel Moolenaar /*
20965db67052SMarcel Moolenaar * libdisk compatibility quirk - the scheme dumps the
20975db67052SMarcel Moolenaar * slicer name and partition type in a way that is
20985db67052SMarcel Moolenaar * compatible with libdisk. When libdisk is not used
20995db67052SMarcel Moolenaar * anymore, this should go away.
21005db67052SMarcel Moolenaar */
21015db67052SMarcel Moolenaar G_PART_DUMPCONF(table, entry, sb, indent);
21021d3aed33SMarcel Moolenaar } else if (cp != NULL) { /* Consumer configuration. */
210342a783c1SRui Paulo KASSERT(pp == NULL, ("%s", __func__));
21041d3aed33SMarcel Moolenaar /* none */
21051d3aed33SMarcel Moolenaar } else if (pp != NULL) { /* Provider configuration. */
21061d3aed33SMarcel Moolenaar entry = pp->private;
21071d3aed33SMarcel Moolenaar if (entry == NULL)
21081d3aed33SMarcel Moolenaar return;
2109165651a5SMarcel Moolenaar sbuf_printf(sb, "%s<start>%ju</start>\n", indent,
2110165651a5SMarcel Moolenaar (uintmax_t)entry->gpe_start);
2111165651a5SMarcel Moolenaar sbuf_printf(sb, "%s<end>%ju</end>\n", indent,
2112165651a5SMarcel Moolenaar (uintmax_t)entry->gpe_end);
21131d3aed33SMarcel Moolenaar sbuf_printf(sb, "%s<index>%u</index>\n", indent,
21141d3aed33SMarcel Moolenaar entry->gpe_index);
21151d3aed33SMarcel Moolenaar sbuf_printf(sb, "%s<type>%s</type>\n", indent,
21161d3aed33SMarcel Moolenaar G_PART_TYPE(table, entry, buf, sizeof(buf)));
21171d3aed33SMarcel Moolenaar sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent,
21181d3aed33SMarcel Moolenaar (uintmax_t)entry->gpe_offset);
21191d3aed33SMarcel Moolenaar sbuf_printf(sb, "%s<length>%ju</length>\n", indent,
21201d3aed33SMarcel Moolenaar (uintmax_t)pp->mediasize);
21211d3aed33SMarcel Moolenaar G_PART_DUMPCONF(table, entry, sb, indent);
21221d3aed33SMarcel Moolenaar } else { /* Geom configuration. */
2123e8e1f544SMarcel Moolenaar sbuf_printf(sb, "%s<scheme>%s</scheme>\n", indent,
2124e8e1f544SMarcel Moolenaar table->gpt_scheme->name);
21251d3aed33SMarcel Moolenaar sbuf_printf(sb, "%s<entries>%u</entries>\n", indent,
21261d3aed33SMarcel Moolenaar table->gpt_entries);
21271d3aed33SMarcel Moolenaar sbuf_printf(sb, "%s<first>%ju</first>\n", indent,
21281d3aed33SMarcel Moolenaar (uintmax_t)table->gpt_first);
21291d3aed33SMarcel Moolenaar sbuf_printf(sb, "%s<last>%ju</last>\n", indent,
21301d3aed33SMarcel Moolenaar (uintmax_t)table->gpt_last);
21310081f96eSMarcel Moolenaar sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n", indent,
21320081f96eSMarcel Moolenaar table->gpt_sectors);
21330081f96eSMarcel Moolenaar sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n", indent,
21340081f96eSMarcel Moolenaar table->gpt_heads);
2135e7926a37SAndrey V. Elsukov sbuf_printf(sb, "%s<state>%s</state>\n", indent,
2136e7926a37SAndrey V. Elsukov table->gpt_corrupt ? "CORRUPT": "OK");
2137e76b0614SNathan Whitehorn sbuf_printf(sb, "%s<modified>%s</modified>\n", indent,
2138e76b0614SNathan Whitehorn table->gpt_opened ? "true": "false");
21391d3aed33SMarcel Moolenaar G_PART_DUMPCONF(table, NULL, sb, indent);
21401d3aed33SMarcel Moolenaar }
21411d3aed33SMarcel Moolenaar }
21421d3aed33SMarcel Moolenaar
214373f49e9eSWarner Losh /*-
214473f49e9eSWarner Losh * This start routine is only called for non-trivial requests, all the
214573f49e9eSWarner Losh * trivial ones are handled autonomously by the slice code.
214673f49e9eSWarner Losh * For requests we handle here, we must call the g_io_deliver() on the
214773f49e9eSWarner Losh * bio, and return non-zero to indicate to the slice code that we did so.
214873f49e9eSWarner Losh * This code executes in the "DOWN" I/O path, this means:
214973f49e9eSWarner Losh * * No sleeping.
215073f49e9eSWarner Losh * * Don't grab the topology lock.
215173f49e9eSWarner Losh * * Don't call biowait, g_getattr(), g_setattr() or g_read_data()
215273f49e9eSWarner Losh */
215373f49e9eSWarner Losh static int
g_part_ioctl(struct g_provider * pp,u_long cmd,void * data,int fflag,struct thread * td)215473f49e9eSWarner Losh g_part_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td)
215573f49e9eSWarner Losh {
215673f49e9eSWarner Losh struct g_part_table *table;
215773f49e9eSWarner Losh
215873f49e9eSWarner Losh table = pp->geom->softc;
215973f49e9eSWarner Losh return G_PART_IOCTL(table, pp, cmd, data, fflag, td);
216073f49e9eSWarner Losh }
216173f49e9eSWarner Losh
21621d3aed33SMarcel Moolenaar static void
g_part_resize(struct g_consumer * cp)2163884c8e4fSAndrey V. Elsukov g_part_resize(struct g_consumer *cp)
2164884c8e4fSAndrey V. Elsukov {
2165884c8e4fSAndrey V. Elsukov struct g_part_table *table;
2166884c8e4fSAndrey V. Elsukov
2167884c8e4fSAndrey V. Elsukov G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name));
2168884c8e4fSAndrey V. Elsukov g_topology_assert();
2169884c8e4fSAndrey V. Elsukov
217001ad653aSMariusz Zaborski if (auto_resize == 0)
217101ad653aSMariusz Zaborski return;
217201ad653aSMariusz Zaborski
2173884c8e4fSAndrey V. Elsukov table = cp->geom->softc;
2174884c8e4fSAndrey V. Elsukov if (table->gpt_opened == 0) {
2175884c8e4fSAndrey V. Elsukov if (g_access(cp, 1, 1, 1) != 0)
2176884c8e4fSAndrey V. Elsukov return;
2177884c8e4fSAndrey V. Elsukov table->gpt_opened = 1;
2178884c8e4fSAndrey V. Elsukov }
2179884c8e4fSAndrey V. Elsukov if (G_PART_RESIZE(table, NULL, NULL) == 0)
21804f31a94bSAndrey V. Elsukov printf("GEOM_PART: %s was automatically resized.\n"
21814f31a94bSAndrey V. Elsukov " Use `gpart commit %s` to save changes or "
21824f31a94bSAndrey V. Elsukov "`gpart undo %s` to revert them.\n", cp->geom->name,
21834f31a94bSAndrey V. Elsukov cp->geom->name, cp->geom->name);
2184884c8e4fSAndrey V. Elsukov if (g_part_check_integrity(table, cp) != 0) {
2185884c8e4fSAndrey V. Elsukov g_access(cp, -1, -1, -1);
2186884c8e4fSAndrey V. Elsukov table->gpt_opened = 0;
2187884c8e4fSAndrey V. Elsukov g_part_wither(table->gpt_gp, ENXIO);
2188884c8e4fSAndrey V. Elsukov }
2189884c8e4fSAndrey V. Elsukov }
2190884c8e4fSAndrey V. Elsukov
2191884c8e4fSAndrey V. Elsukov static void
g_part_orphan(struct g_consumer * cp)21921d3aed33SMarcel Moolenaar g_part_orphan(struct g_consumer *cp)
21931d3aed33SMarcel Moolenaar {
21941d3aed33SMarcel Moolenaar struct g_provider *pp;
2195b6d40281SAndrey V. Elsukov struct g_part_table *table;
21961d3aed33SMarcel Moolenaar
21971d3aed33SMarcel Moolenaar pp = cp->provider;
219842a783c1SRui Paulo KASSERT(pp != NULL, ("%s", __func__));
21991d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name));
22001d3aed33SMarcel Moolenaar g_topology_assert();
22011d3aed33SMarcel Moolenaar
220242a783c1SRui Paulo KASSERT(pp->error != 0, ("%s", __func__));
2203b6d40281SAndrey V. Elsukov table = cp->geom->softc;
2204a45f4c6eSAndrey V. Elsukov if (table != NULL && table->gpt_opened)
2205b6d40281SAndrey V. Elsukov g_access(cp, -1, -1, -1);
22061d3aed33SMarcel Moolenaar g_part_wither(cp->geom, pp->error);
22071d3aed33SMarcel Moolenaar }
22081d3aed33SMarcel Moolenaar
22091d3aed33SMarcel Moolenaar static void
g_part_spoiled(struct g_consumer * cp)22101d3aed33SMarcel Moolenaar g_part_spoiled(struct g_consumer *cp)
22111d3aed33SMarcel Moolenaar {
22121d3aed33SMarcel Moolenaar
22131d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name));
22141d3aed33SMarcel Moolenaar g_topology_assert();
22151d3aed33SMarcel Moolenaar
22163631c638SAlexander Motin cp->flags |= G_CF_ORPHAN;
22171d3aed33SMarcel Moolenaar g_part_wither(cp->geom, ENXIO);
22181d3aed33SMarcel Moolenaar }
22191d3aed33SMarcel Moolenaar
22201d3aed33SMarcel Moolenaar static void
g_part_start(struct bio * bp)22211d3aed33SMarcel Moolenaar g_part_start(struct bio *bp)
22221d3aed33SMarcel Moolenaar {
22231d3aed33SMarcel Moolenaar struct bio *bp2;
22241d3aed33SMarcel Moolenaar struct g_consumer *cp;
22251d3aed33SMarcel Moolenaar struct g_geom *gp;
22261d3aed33SMarcel Moolenaar struct g_part_entry *entry;
22271d3aed33SMarcel Moolenaar struct g_part_table *table;
22281d3aed33SMarcel Moolenaar struct g_kerneldump *gkd;
22291d3aed33SMarcel Moolenaar struct g_provider *pp;
223083406320SAlan Somers void (*done_func)(struct bio *) = g_std_done;
22310d8bc07eSAndrey V. Elsukov char buf[64];
22321d3aed33SMarcel Moolenaar
22338532d381SConrad Meyer biotrack(bp, __func__);
22348532d381SConrad Meyer
22351d3aed33SMarcel Moolenaar pp = bp->bio_to;
22361d3aed33SMarcel Moolenaar gp = pp->geom;
22371d3aed33SMarcel Moolenaar table = gp->softc;
22381d3aed33SMarcel Moolenaar cp = LIST_FIRST(&gp->consumer);
22391d3aed33SMarcel Moolenaar
22401d3aed33SMarcel Moolenaar G_PART_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd,
22411d3aed33SMarcel Moolenaar pp->name));
22421d3aed33SMarcel Moolenaar
22431d3aed33SMarcel Moolenaar entry = pp->private;
22441d3aed33SMarcel Moolenaar if (entry == NULL) {
22451d3aed33SMarcel Moolenaar g_io_deliver(bp, ENXIO);
22461d3aed33SMarcel Moolenaar return;
22471d3aed33SMarcel Moolenaar }
22481d3aed33SMarcel Moolenaar
22491d3aed33SMarcel Moolenaar switch(bp->bio_cmd) {
22501d3aed33SMarcel Moolenaar case BIO_DELETE:
22511d3aed33SMarcel Moolenaar case BIO_READ:
22521d3aed33SMarcel Moolenaar case BIO_WRITE:
22531d3aed33SMarcel Moolenaar if (bp->bio_offset >= pp->mediasize) {
22541d3aed33SMarcel Moolenaar g_io_deliver(bp, EIO);
22551d3aed33SMarcel Moolenaar return;
22561d3aed33SMarcel Moolenaar }
22571d3aed33SMarcel Moolenaar bp2 = g_clone_bio(bp);
22581d3aed33SMarcel Moolenaar if (bp2 == NULL) {
22591d3aed33SMarcel Moolenaar g_io_deliver(bp, ENOMEM);
22601d3aed33SMarcel Moolenaar return;
22611d3aed33SMarcel Moolenaar }
22621d3aed33SMarcel Moolenaar if (bp2->bio_offset + bp2->bio_length > pp->mediasize)
22631d3aed33SMarcel Moolenaar bp2->bio_length = pp->mediasize - bp2->bio_offset;
22641d3aed33SMarcel Moolenaar bp2->bio_done = g_std_done;
22651d3aed33SMarcel Moolenaar bp2->bio_offset += entry->gpe_offset;
22661d3aed33SMarcel Moolenaar g_io_request(bp2, cp);
22671d3aed33SMarcel Moolenaar return;
22688b522bdaSWarner Losh case BIO_SPEEDUP:
22691d3aed33SMarcel Moolenaar case BIO_FLUSH:
22701d3aed33SMarcel Moolenaar break;
22711d3aed33SMarcel Moolenaar case BIO_GETATTR:
22720081f96eSMarcel Moolenaar if (g_handleattr_int(bp, "GEOM::fwheads", table->gpt_heads))
22730081f96eSMarcel Moolenaar return;
22740081f96eSMarcel Moolenaar if (g_handleattr_int(bp, "GEOM::fwsectors", table->gpt_sectors))
22750081f96eSMarcel Moolenaar return;
2276ef03f57dSKyle Evans /*
2277ef03f57dSKyle Evans * allow_nesting overrides "isleaf" to false _unless_ the
2278ef03f57dSKyle Evans * provider offset is zero, since otherwise we would recurse.
2279ef03f57dSKyle Evans */
2280ef03f57dSKyle Evans if (g_handleattr_int(bp, "PART::isleaf",
2281ef03f57dSKyle Evans table->gpt_isleaf &&
2282ef03f57dSKyle Evans (allow_nesting == 0 || entry->gpe_offset == 0)))
22830081f96eSMarcel Moolenaar return;
22840081f96eSMarcel Moolenaar if (g_handleattr_int(bp, "PART::depth", table->gpt_depth))
22850081f96eSMarcel Moolenaar return;
2286165651a5SMarcel Moolenaar if (g_handleattr_str(bp, "PART::scheme",
2287165651a5SMarcel Moolenaar table->gpt_scheme->name))
2288165651a5SMarcel Moolenaar return;
22890d8bc07eSAndrey V. Elsukov if (g_handleattr_str(bp, "PART::type",
22900d8bc07eSAndrey V. Elsukov G_PART_TYPE(table, entry, buf, sizeof(buf))))
22910d8bc07eSAndrey V. Elsukov return;
229283406320SAlan Somers if (!strcmp("GEOM::physpath", bp->bio_attribute)) {
229383406320SAlan Somers done_func = g_part_get_physpath_done;
229483406320SAlan Somers break;
229583406320SAlan Somers }
22961d3aed33SMarcel Moolenaar if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) {
22971d3aed33SMarcel Moolenaar /*
22981d3aed33SMarcel Moolenaar * Check that the partition is suitable for kernel
22991d3aed33SMarcel Moolenaar * dumps. Typically only swap partitions should be
23005357f275SAndrey V. Elsukov * used. If the request comes from the nested scheme
23015357f275SAndrey V. Elsukov * we allow dumping there as well.
23021d3aed33SMarcel Moolenaar */
23035357f275SAndrey V. Elsukov if ((bp->bio_from == NULL ||
23045357f275SAndrey V. Elsukov bp->bio_from->geom->class != &g_part_class) &&
23055357f275SAndrey V. Elsukov G_PART_DUMPTO(table, entry) == 0) {
230615c48b9aSIvan Voras g_io_deliver(bp, ENODEV);
230715c48b9aSIvan Voras printf("GEOM_PART: Partition '%s' not suitable"
230815c48b9aSIvan Voras " for kernel dumps (wrong type?)\n",
230915c48b9aSIvan Voras pp->name);
23101d3aed33SMarcel Moolenaar return;
23111d3aed33SMarcel Moolenaar }
23121d3aed33SMarcel Moolenaar gkd = (struct g_kerneldump *)bp->bio_data;
23131d3aed33SMarcel Moolenaar if (gkd->offset >= pp->mediasize) {
23141d3aed33SMarcel Moolenaar g_io_deliver(bp, EIO);
23151d3aed33SMarcel Moolenaar return;
23161d3aed33SMarcel Moolenaar }
23171d3aed33SMarcel Moolenaar if (gkd->offset + gkd->length > pp->mediasize)
23181d3aed33SMarcel Moolenaar gkd->length = pp->mediasize - gkd->offset;
23191d3aed33SMarcel Moolenaar gkd->offset += entry->gpe_offset;
23201d3aed33SMarcel Moolenaar }
23211d3aed33SMarcel Moolenaar break;
23221d3aed33SMarcel Moolenaar default:
23231d3aed33SMarcel Moolenaar g_io_deliver(bp, EOPNOTSUPP);
23241d3aed33SMarcel Moolenaar return;
23251d3aed33SMarcel Moolenaar }
23261d3aed33SMarcel Moolenaar
23271d3aed33SMarcel Moolenaar bp2 = g_clone_bio(bp);
23281d3aed33SMarcel Moolenaar if (bp2 == NULL) {
23291d3aed33SMarcel Moolenaar g_io_deliver(bp, ENOMEM);
23301d3aed33SMarcel Moolenaar return;
23311d3aed33SMarcel Moolenaar }
233283406320SAlan Somers bp2->bio_done = done_func;
23331d3aed33SMarcel Moolenaar g_io_request(bp2, cp);
23341d3aed33SMarcel Moolenaar }
23354ffca444SMarcel Moolenaar
23364ffca444SMarcel Moolenaar static void
g_part_init(struct g_class * mp)23374ffca444SMarcel Moolenaar g_part_init(struct g_class *mp)
23384ffca444SMarcel Moolenaar {
23394ffca444SMarcel Moolenaar
23401e2fbcfaSMarcel Moolenaar TAILQ_INSERT_HEAD(&g_part_schemes, &g_part_null_scheme, scheme_list);
23414ffca444SMarcel Moolenaar }
23424ffca444SMarcel Moolenaar
23434ffca444SMarcel Moolenaar static void
g_part_fini(struct g_class * mp)23444ffca444SMarcel Moolenaar g_part_fini(struct g_class *mp)
23454ffca444SMarcel Moolenaar {
23464ffca444SMarcel Moolenaar
23474ffca444SMarcel Moolenaar TAILQ_REMOVE(&g_part_schemes, &g_part_null_scheme, scheme_list);
23484ffca444SMarcel Moolenaar }
23494ffca444SMarcel Moolenaar
23504ffca444SMarcel Moolenaar static void
g_part_unload_event(void * arg,int flag)23514ffca444SMarcel Moolenaar g_part_unload_event(void *arg, int flag)
23524ffca444SMarcel Moolenaar {
23534ffca444SMarcel Moolenaar struct g_consumer *cp;
23544ffca444SMarcel Moolenaar struct g_geom *gp;
23554ffca444SMarcel Moolenaar struct g_provider *pp;
23564ffca444SMarcel Moolenaar struct g_part_scheme *scheme;
23574ffca444SMarcel Moolenaar struct g_part_table *table;
23584ffca444SMarcel Moolenaar uintptr_t *xchg;
23594ffca444SMarcel Moolenaar int acc, error;
23604ffca444SMarcel Moolenaar
23614ffca444SMarcel Moolenaar if (flag == EV_CANCEL)
23624ffca444SMarcel Moolenaar return;
23634ffca444SMarcel Moolenaar
23644ffca444SMarcel Moolenaar xchg = arg;
23654ffca444SMarcel Moolenaar error = 0;
23664ffca444SMarcel Moolenaar scheme = (void *)(*xchg);
23674ffca444SMarcel Moolenaar
23684ffca444SMarcel Moolenaar g_topology_assert();
23694ffca444SMarcel Moolenaar
23704ffca444SMarcel Moolenaar LIST_FOREACH(gp, &g_part_class.geom, geom) {
23714ffca444SMarcel Moolenaar table = gp->softc;
23724ffca444SMarcel Moolenaar if (table->gpt_scheme != scheme)
23734ffca444SMarcel Moolenaar continue;
23744ffca444SMarcel Moolenaar
23754ffca444SMarcel Moolenaar acc = 0;
23764ffca444SMarcel Moolenaar LIST_FOREACH(pp, &gp->provider, provider)
23774ffca444SMarcel Moolenaar acc += pp->acr + pp->acw + pp->ace;
23784ffca444SMarcel Moolenaar LIST_FOREACH(cp, &gp->consumer, consumer)
23794ffca444SMarcel Moolenaar acc += cp->acr + cp->acw + cp->ace;
23804ffca444SMarcel Moolenaar
23814ffca444SMarcel Moolenaar if (!acc)
23824ffca444SMarcel Moolenaar g_part_wither(gp, ENOSYS);
23834ffca444SMarcel Moolenaar else
23844ffca444SMarcel Moolenaar error = EBUSY;
23854ffca444SMarcel Moolenaar }
23864ffca444SMarcel Moolenaar
23874ffca444SMarcel Moolenaar if (!error)
23884ffca444SMarcel Moolenaar TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list);
23894ffca444SMarcel Moolenaar
23904ffca444SMarcel Moolenaar *xchg = error;
23914ffca444SMarcel Moolenaar }
23924ffca444SMarcel Moolenaar
23934ffca444SMarcel Moolenaar int
g_part_modevent(module_t mod,int type,struct g_part_scheme * scheme)23944ffca444SMarcel Moolenaar g_part_modevent(module_t mod, int type, struct g_part_scheme *scheme)
23954ffca444SMarcel Moolenaar {
2396472794bbSAndrey V. Elsukov struct g_part_scheme *iter;
23974ffca444SMarcel Moolenaar uintptr_t arg;
23984ffca444SMarcel Moolenaar int error;
23994ffca444SMarcel Moolenaar
2400472794bbSAndrey V. Elsukov error = 0;
24014ffca444SMarcel Moolenaar switch (type) {
24024ffca444SMarcel Moolenaar case MOD_LOAD:
2403472794bbSAndrey V. Elsukov TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) {
2404472794bbSAndrey V. Elsukov if (scheme == iter) {
2405472794bbSAndrey V. Elsukov printf("GEOM_PART: scheme %s is already "
2406472794bbSAndrey V. Elsukov "registered!\n", scheme->name);
2407472794bbSAndrey V. Elsukov break;
2408472794bbSAndrey V. Elsukov }
2409472794bbSAndrey V. Elsukov }
2410472794bbSAndrey V. Elsukov if (iter == NULL) {
2411472794bbSAndrey V. Elsukov TAILQ_INSERT_TAIL(&g_part_schemes, scheme,
2412472794bbSAndrey V. Elsukov scheme_list);
2413472794bbSAndrey V. Elsukov g_retaste(&g_part_class);
2414472794bbSAndrey V. Elsukov }
24154ffca444SMarcel Moolenaar break;
24164ffca444SMarcel Moolenaar case MOD_UNLOAD:
24174ffca444SMarcel Moolenaar arg = (uintptr_t)scheme;
24184ffca444SMarcel Moolenaar error = g_waitfor_event(g_part_unload_event, &arg, M_WAITOK,
24194ffca444SMarcel Moolenaar NULL);
2420472794bbSAndrey V. Elsukov if (error == 0)
2421472794bbSAndrey V. Elsukov error = arg;
24224ffca444SMarcel Moolenaar break;
24234ffca444SMarcel Moolenaar default:
24244ffca444SMarcel Moolenaar error = EOPNOTSUPP;
24254ffca444SMarcel Moolenaar break;
24264ffca444SMarcel Moolenaar }
24274ffca444SMarcel Moolenaar
24284ffca444SMarcel Moolenaar return (error);
24294ffca444SMarcel Moolenaar }
2430