Deleted Added
full compact
g_part.c (200539) g_part.c (201645)
1/*-
2 * Copyright (c) 2002, 2005-2009 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2002, 2005-2009 Marcel Moolenaar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/geom/part/g_part.c 200539 2009-12-14 20:26:27Z rpaulo $");
28__FBSDID("$FreeBSD: head/sys/geom/part/g_part.c 201645 2010-01-06 13:14:37Z mav $");
29
30#include <sys/param.h>
31#include <sys/bio.h>
32#include <sys/diskmbr.h>
33#include <sys/endian.h>
34#include <sys/kernel.h>
35#include <sys/kobj.h>
36#include <sys/limits.h>
37#include <sys/lock.h>
38#include <sys/malloc.h>
39#include <sys/mutex.h>
40#include <sys/queue.h>
41#include <sys/sbuf.h>
42#include <sys/systm.h>
43#include <sys/uuid.h>
44#include <geom/geom.h>
45#include <geom/geom_ctl.h>
46#include <geom/geom_int.h>
47#include <geom/part/g_part.h>
48
49#include "g_part_if.h"
50
51#ifndef _PATH_DEV
52#define _PATH_DEV "/dev/"
53#endif
54
55static kobj_method_t g_part_null_methods[] = {
56 { 0, 0 }
57};
58
59static struct g_part_scheme g_part_null_scheme = {
60 "(none)",
61 g_part_null_methods,
62 sizeof(struct g_part_table),
63};
64
65TAILQ_HEAD(, g_part_scheme) g_part_schemes =
66 TAILQ_HEAD_INITIALIZER(g_part_schemes);
67
68struct g_part_alias_list {
69 const char *lexeme;
70 enum g_part_alias alias;
71} g_part_alias_list[G_PART_ALIAS_COUNT] = {
72 { "apple-boot", G_PART_ALIAS_APPLE_BOOT },
73 { "apple-hfs", G_PART_ALIAS_APPLE_HFS },
74 { "apple-label", G_PART_ALIAS_APPLE_LABEL },
75 { "apple-raid", G_PART_ALIAS_APPLE_RAID },
76 { "apple-raid-offline", G_PART_ALIAS_APPLE_RAID_OFFLINE },
77 { "apple-tv-recovery", G_PART_ALIAS_APPLE_TV_RECOVERY },
78 { "apple-ufs", G_PART_ALIAS_APPLE_UFS },
79 { "efi", G_PART_ALIAS_EFI },
80 { "freebsd", G_PART_ALIAS_FREEBSD },
81 { "freebsd-boot", G_PART_ALIAS_FREEBSD_BOOT },
82 { "freebsd-swap", G_PART_ALIAS_FREEBSD_SWAP },
83 { "freebsd-ufs", G_PART_ALIAS_FREEBSD_UFS },
84 { "freebsd-vinum", G_PART_ALIAS_FREEBSD_VINUM },
85 { "freebsd-zfs", G_PART_ALIAS_FREEBSD_ZFS },
86 { "linux-data", G_PART_ALIAS_LINUX_DATA },
87 { "linux-lvm", G_PART_ALIAS_LINUX_LVM },
88 { "linux-raid", G_PART_ALIAS_LINUX_RAID },
89 { "linux-swap", G_PART_ALIAS_LINUX_SWAP },
90 { "ms-basic-data", G_PART_ALIAS_MS_BASIC_DATA },
91 { "ms-ldm-data", G_PART_ALIAS_MS_LDM_DATA },
92 { "ms-ldm-metadata", G_PART_ALIAS_MS_LDM_METADATA },
93 { "ms-reserved", G_PART_ALIAS_MS_RESERVED },
94 { "netbsd-ccd", G_PART_ALIAS_NETBSD_CCD },
95 { "netbsd-cgd", G_PART_ALIAS_NETBSD_CGD },
96 { "netbsd-ffs", G_PART_ALIAS_NETBSD_FFS },
97 { "netbsd-lfs", G_PART_ALIAS_NETBSD_LFS },
98 { "netbsd-raid", G_PART_ALIAS_NETBSD_RAID },
99 { "netbsd-swap", G_PART_ALIAS_NETBSD_SWAP },
100 { "mbr", G_PART_ALIAS_MBR }
101};
102
103/*
104 * The GEOM partitioning class.
105 */
106static g_ctl_req_t g_part_ctlreq;
107static g_ctl_destroy_geom_t g_part_destroy_geom;
108static g_fini_t g_part_fini;
109static g_init_t g_part_init;
110static g_taste_t g_part_taste;
111
112static g_access_t g_part_access;
113static g_dumpconf_t g_part_dumpconf;
114static g_orphan_t g_part_orphan;
115static g_spoiled_t g_part_spoiled;
116static g_start_t g_part_start;
117
118static struct g_class g_part_class = {
119 .name = "PART",
120 .version = G_VERSION,
121 /* Class methods. */
122 .ctlreq = g_part_ctlreq,
123 .destroy_geom = g_part_destroy_geom,
124 .fini = g_part_fini,
125 .init = g_part_init,
126 .taste = g_part_taste,
127 /* Geom methods. */
128 .access = g_part_access,
129 .dumpconf = g_part_dumpconf,
130 .orphan = g_part_orphan,
131 .spoiled = g_part_spoiled,
132 .start = g_part_start,
133};
134
135DECLARE_GEOM_CLASS(g_part_class, g_part);
136
137/*
138 * Support functions.
139 */
140
141static void g_part_wither(struct g_geom *, int);
142
143const char *
144g_part_alias_name(enum g_part_alias alias)
145{
146 int i;
147
148 for (i = 0; i < G_PART_ALIAS_COUNT; i++) {
149 if (g_part_alias_list[i].alias != alias)
150 continue;
151 return (g_part_alias_list[i].lexeme);
152 }
153
154 return (NULL);
155}
156
157void
158g_part_geometry_heads(off_t blocks, u_int sectors, off_t *bestchs,
159 u_int *bestheads)
160{
161 static u_int candidate_heads[] = { 1, 2, 16, 32, 64, 128, 255, 0 };
162 off_t chs, cylinders;
163 u_int heads;
164 int idx;
165
166 *bestchs = 0;
167 *bestheads = 0;
168 for (idx = 0; candidate_heads[idx] != 0; idx++) {
169 heads = candidate_heads[idx];
170 cylinders = blocks / heads / sectors;
171 if (cylinders < heads || cylinders < sectors)
172 break;
173 if (cylinders > 1023)
174 continue;
175 chs = cylinders * heads * sectors;
176 if (chs > *bestchs || (chs == *bestchs && *bestheads == 1)) {
177 *bestchs = chs;
178 *bestheads = heads;
179 }
180 }
181}
182
183static void
184g_part_geometry(struct g_part_table *table, struct g_consumer *cp,
185 off_t blocks)
186{
187 static u_int candidate_sectors[] = { 1, 9, 17, 33, 63, 0 };
188 off_t chs, bestchs;
189 u_int heads, sectors;
190 int idx;
191
192 if (g_getattr("GEOM::fwsectors", cp, &sectors) != 0 || sectors == 0 ||
193 g_getattr("GEOM::fwheads", cp, &heads) != 0 || heads == 0) {
194 table->gpt_fixgeom = 0;
195 table->gpt_heads = 0;
196 table->gpt_sectors = 0;
197 bestchs = 0;
198 for (idx = 0; candidate_sectors[idx] != 0; idx++) {
199 sectors = candidate_sectors[idx];
200 g_part_geometry_heads(blocks, sectors, &chs, &heads);
201 if (chs == 0)
202 continue;
203 /*
204 * Prefer a geometry with sectors > 1, but only if
205 * it doesn't bump down the numbver of heads to 1.
206 */
207 if (chs > bestchs || (chs == bestchs && heads > 1 &&
208 table->gpt_sectors == 1)) {
209 bestchs = chs;
210 table->gpt_heads = heads;
211 table->gpt_sectors = sectors;
212 }
213 }
214 /*
215 * If we didn't find a geometry at all, then the disk is
216 * too big. This means we can use the maximum number of
217 * heads and sectors.
218 */
219 if (bestchs == 0) {
220 table->gpt_heads = 255;
221 table->gpt_sectors = 63;
222 }
223 } else {
224 table->gpt_fixgeom = 1;
225 table->gpt_heads = heads;
226 table->gpt_sectors = sectors;
227 }
228}
229
230struct g_part_entry *
231g_part_new_entry(struct g_part_table *table, int index, quad_t start,
232 quad_t end)
233{
234 struct g_part_entry *entry, *last;
235
236 last = NULL;
237 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
238 if (entry->gpe_index == index)
239 break;
240 if (entry->gpe_index > index) {
241 entry = NULL;
242 break;
243 }
244 last = entry;
245 }
246 if (entry == NULL) {
247 entry = g_malloc(table->gpt_scheme->gps_entrysz,
248 M_WAITOK | M_ZERO);
249 entry->gpe_index = index;
250 if (last == NULL)
251 LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry);
252 else
253 LIST_INSERT_AFTER(last, entry, gpe_entry);
254 } else
255 entry->gpe_offset = 0;
256 entry->gpe_start = start;
257 entry->gpe_end = end;
258 return (entry);
259}
260
261static void
262g_part_new_provider(struct g_geom *gp, struct g_part_table *table,
263 struct g_part_entry *entry)
264{
265 struct g_consumer *cp;
266 struct g_provider *pp;
267 struct sbuf *sb;
268 off_t offset;
269
270 cp = LIST_FIRST(&gp->consumer);
271 pp = cp->provider;
272
273 offset = entry->gpe_start * pp->sectorsize;
274 if (entry->gpe_offset < offset)
275 entry->gpe_offset = offset;
276
277 if (entry->gpe_pp == NULL) {
278 sb = sbuf_new_auto();
279 G_PART_FULLNAME(table, entry, sb, gp->name);
280 sbuf_finish(sb);
281 entry->gpe_pp = g_new_providerf(gp, "%s", sbuf_data(sb));
282 sbuf_delete(sb);
283 entry->gpe_pp->private = entry; /* Close the circle. */
284 }
285 entry->gpe_pp->index = entry->gpe_index - 1; /* index is 1-based. */
286 entry->gpe_pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) *
287 pp->sectorsize;
288 entry->gpe_pp->mediasize -= entry->gpe_offset - offset;
289 entry->gpe_pp->sectorsize = pp->sectorsize;
290 entry->gpe_pp->flags = pp->flags & G_PF_CANDELETE;
29
30#include <sys/param.h>
31#include <sys/bio.h>
32#include <sys/diskmbr.h>
33#include <sys/endian.h>
34#include <sys/kernel.h>
35#include <sys/kobj.h>
36#include <sys/limits.h>
37#include <sys/lock.h>
38#include <sys/malloc.h>
39#include <sys/mutex.h>
40#include <sys/queue.h>
41#include <sys/sbuf.h>
42#include <sys/systm.h>
43#include <sys/uuid.h>
44#include <geom/geom.h>
45#include <geom/geom_ctl.h>
46#include <geom/geom_int.h>
47#include <geom/part/g_part.h>
48
49#include "g_part_if.h"
50
51#ifndef _PATH_DEV
52#define _PATH_DEV "/dev/"
53#endif
54
55static kobj_method_t g_part_null_methods[] = {
56 { 0, 0 }
57};
58
59static struct g_part_scheme g_part_null_scheme = {
60 "(none)",
61 g_part_null_methods,
62 sizeof(struct g_part_table),
63};
64
65TAILQ_HEAD(, g_part_scheme) g_part_schemes =
66 TAILQ_HEAD_INITIALIZER(g_part_schemes);
67
68struct g_part_alias_list {
69 const char *lexeme;
70 enum g_part_alias alias;
71} g_part_alias_list[G_PART_ALIAS_COUNT] = {
72 { "apple-boot", G_PART_ALIAS_APPLE_BOOT },
73 { "apple-hfs", G_PART_ALIAS_APPLE_HFS },
74 { "apple-label", G_PART_ALIAS_APPLE_LABEL },
75 { "apple-raid", G_PART_ALIAS_APPLE_RAID },
76 { "apple-raid-offline", G_PART_ALIAS_APPLE_RAID_OFFLINE },
77 { "apple-tv-recovery", G_PART_ALIAS_APPLE_TV_RECOVERY },
78 { "apple-ufs", G_PART_ALIAS_APPLE_UFS },
79 { "efi", G_PART_ALIAS_EFI },
80 { "freebsd", G_PART_ALIAS_FREEBSD },
81 { "freebsd-boot", G_PART_ALIAS_FREEBSD_BOOT },
82 { "freebsd-swap", G_PART_ALIAS_FREEBSD_SWAP },
83 { "freebsd-ufs", G_PART_ALIAS_FREEBSD_UFS },
84 { "freebsd-vinum", G_PART_ALIAS_FREEBSD_VINUM },
85 { "freebsd-zfs", G_PART_ALIAS_FREEBSD_ZFS },
86 { "linux-data", G_PART_ALIAS_LINUX_DATA },
87 { "linux-lvm", G_PART_ALIAS_LINUX_LVM },
88 { "linux-raid", G_PART_ALIAS_LINUX_RAID },
89 { "linux-swap", G_PART_ALIAS_LINUX_SWAP },
90 { "ms-basic-data", G_PART_ALIAS_MS_BASIC_DATA },
91 { "ms-ldm-data", G_PART_ALIAS_MS_LDM_DATA },
92 { "ms-ldm-metadata", G_PART_ALIAS_MS_LDM_METADATA },
93 { "ms-reserved", G_PART_ALIAS_MS_RESERVED },
94 { "netbsd-ccd", G_PART_ALIAS_NETBSD_CCD },
95 { "netbsd-cgd", G_PART_ALIAS_NETBSD_CGD },
96 { "netbsd-ffs", G_PART_ALIAS_NETBSD_FFS },
97 { "netbsd-lfs", G_PART_ALIAS_NETBSD_LFS },
98 { "netbsd-raid", G_PART_ALIAS_NETBSD_RAID },
99 { "netbsd-swap", G_PART_ALIAS_NETBSD_SWAP },
100 { "mbr", G_PART_ALIAS_MBR }
101};
102
103/*
104 * The GEOM partitioning class.
105 */
106static g_ctl_req_t g_part_ctlreq;
107static g_ctl_destroy_geom_t g_part_destroy_geom;
108static g_fini_t g_part_fini;
109static g_init_t g_part_init;
110static g_taste_t g_part_taste;
111
112static g_access_t g_part_access;
113static g_dumpconf_t g_part_dumpconf;
114static g_orphan_t g_part_orphan;
115static g_spoiled_t g_part_spoiled;
116static g_start_t g_part_start;
117
118static struct g_class g_part_class = {
119 .name = "PART",
120 .version = G_VERSION,
121 /* Class methods. */
122 .ctlreq = g_part_ctlreq,
123 .destroy_geom = g_part_destroy_geom,
124 .fini = g_part_fini,
125 .init = g_part_init,
126 .taste = g_part_taste,
127 /* Geom methods. */
128 .access = g_part_access,
129 .dumpconf = g_part_dumpconf,
130 .orphan = g_part_orphan,
131 .spoiled = g_part_spoiled,
132 .start = g_part_start,
133};
134
135DECLARE_GEOM_CLASS(g_part_class, g_part);
136
137/*
138 * Support functions.
139 */
140
141static void g_part_wither(struct g_geom *, int);
142
143const char *
144g_part_alias_name(enum g_part_alias alias)
145{
146 int i;
147
148 for (i = 0; i < G_PART_ALIAS_COUNT; i++) {
149 if (g_part_alias_list[i].alias != alias)
150 continue;
151 return (g_part_alias_list[i].lexeme);
152 }
153
154 return (NULL);
155}
156
157void
158g_part_geometry_heads(off_t blocks, u_int sectors, off_t *bestchs,
159 u_int *bestheads)
160{
161 static u_int candidate_heads[] = { 1, 2, 16, 32, 64, 128, 255, 0 };
162 off_t chs, cylinders;
163 u_int heads;
164 int idx;
165
166 *bestchs = 0;
167 *bestheads = 0;
168 for (idx = 0; candidate_heads[idx] != 0; idx++) {
169 heads = candidate_heads[idx];
170 cylinders = blocks / heads / sectors;
171 if (cylinders < heads || cylinders < sectors)
172 break;
173 if (cylinders > 1023)
174 continue;
175 chs = cylinders * heads * sectors;
176 if (chs > *bestchs || (chs == *bestchs && *bestheads == 1)) {
177 *bestchs = chs;
178 *bestheads = heads;
179 }
180 }
181}
182
183static void
184g_part_geometry(struct g_part_table *table, struct g_consumer *cp,
185 off_t blocks)
186{
187 static u_int candidate_sectors[] = { 1, 9, 17, 33, 63, 0 };
188 off_t chs, bestchs;
189 u_int heads, sectors;
190 int idx;
191
192 if (g_getattr("GEOM::fwsectors", cp, &sectors) != 0 || sectors == 0 ||
193 g_getattr("GEOM::fwheads", cp, &heads) != 0 || heads == 0) {
194 table->gpt_fixgeom = 0;
195 table->gpt_heads = 0;
196 table->gpt_sectors = 0;
197 bestchs = 0;
198 for (idx = 0; candidate_sectors[idx] != 0; idx++) {
199 sectors = candidate_sectors[idx];
200 g_part_geometry_heads(blocks, sectors, &chs, &heads);
201 if (chs == 0)
202 continue;
203 /*
204 * Prefer a geometry with sectors > 1, but only if
205 * it doesn't bump down the numbver of heads to 1.
206 */
207 if (chs > bestchs || (chs == bestchs && heads > 1 &&
208 table->gpt_sectors == 1)) {
209 bestchs = chs;
210 table->gpt_heads = heads;
211 table->gpt_sectors = sectors;
212 }
213 }
214 /*
215 * If we didn't find a geometry at all, then the disk is
216 * too big. This means we can use the maximum number of
217 * heads and sectors.
218 */
219 if (bestchs == 0) {
220 table->gpt_heads = 255;
221 table->gpt_sectors = 63;
222 }
223 } else {
224 table->gpt_fixgeom = 1;
225 table->gpt_heads = heads;
226 table->gpt_sectors = sectors;
227 }
228}
229
230struct g_part_entry *
231g_part_new_entry(struct g_part_table *table, int index, quad_t start,
232 quad_t end)
233{
234 struct g_part_entry *entry, *last;
235
236 last = NULL;
237 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
238 if (entry->gpe_index == index)
239 break;
240 if (entry->gpe_index > index) {
241 entry = NULL;
242 break;
243 }
244 last = entry;
245 }
246 if (entry == NULL) {
247 entry = g_malloc(table->gpt_scheme->gps_entrysz,
248 M_WAITOK | M_ZERO);
249 entry->gpe_index = index;
250 if (last == NULL)
251 LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry);
252 else
253 LIST_INSERT_AFTER(last, entry, gpe_entry);
254 } else
255 entry->gpe_offset = 0;
256 entry->gpe_start = start;
257 entry->gpe_end = end;
258 return (entry);
259}
260
261static void
262g_part_new_provider(struct g_geom *gp, struct g_part_table *table,
263 struct g_part_entry *entry)
264{
265 struct g_consumer *cp;
266 struct g_provider *pp;
267 struct sbuf *sb;
268 off_t offset;
269
270 cp = LIST_FIRST(&gp->consumer);
271 pp = cp->provider;
272
273 offset = entry->gpe_start * pp->sectorsize;
274 if (entry->gpe_offset < offset)
275 entry->gpe_offset = offset;
276
277 if (entry->gpe_pp == NULL) {
278 sb = sbuf_new_auto();
279 G_PART_FULLNAME(table, entry, sb, gp->name);
280 sbuf_finish(sb);
281 entry->gpe_pp = g_new_providerf(gp, "%s", sbuf_data(sb));
282 sbuf_delete(sb);
283 entry->gpe_pp->private = entry; /* Close the circle. */
284 }
285 entry->gpe_pp->index = entry->gpe_index - 1; /* index is 1-based. */
286 entry->gpe_pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) *
287 pp->sectorsize;
288 entry->gpe_pp->mediasize -= entry->gpe_offset - offset;
289 entry->gpe_pp->sectorsize = pp->sectorsize;
290 entry->gpe_pp->flags = pp->flags & G_PF_CANDELETE;
291 if (pp->stripesize > 0) {
292 entry->gpe_pp->stripesize = pp->stripesize;
293 entry->gpe_pp->stripeoffset = (pp->stripeoffset +
294 entry->gpe_offset) % pp->stripesize;
295 }
291 entry->gpe_pp->stripesize = pp->stripesize;
292 entry->gpe_pp->stripeoffset = pp->stripeoffset + entry->gpe_offset;
293 if (pp->stripesize > 0)
294 entry->gpe_pp->stripeoffset %= pp->stripesize;
296 g_error_provider(entry->gpe_pp, 0);
297}
298
299static int
300g_part_parm_geom(const char *rawname, struct g_geom **v)
301{
302 struct g_geom *gp;
303 const char *pname;
304
305 if (strncmp(rawname, _PATH_DEV, strlen(_PATH_DEV)) == 0)
306 pname = rawname + strlen(_PATH_DEV);
307 else
308 pname = rawname;
309 LIST_FOREACH(gp, &g_part_class.geom, geom) {
310 if (!strcmp(pname, gp->name))
311 break;
312 }
313 if (gp == NULL)
314 return (EINVAL);
315 *v = gp;
316 return (0);
317}
318
319static int
320g_part_parm_provider(const char *pname, struct g_provider **v)
321{
322 struct g_provider *pp;
323
324 if (strncmp(pname, _PATH_DEV, strlen(_PATH_DEV)) == 0)
325 pp = g_provider_by_name(pname + strlen(_PATH_DEV));
326 else
327 pp = g_provider_by_name(pname);
328 if (pp == NULL)
329 return (EINVAL);
330 *v = pp;
331 return (0);
332}
333
334static int
335g_part_parm_quad(const char *p, quad_t *v)
336{
337 char *x;
338 quad_t q;
339
340 q = strtoq(p, &x, 0);
341 if (*x != '\0' || q < 0)
342 return (EINVAL);
343 *v = q;
344 return (0);
345}
346
347static int
348g_part_parm_scheme(const char *p, struct g_part_scheme **v)
349{
350 struct g_part_scheme *s;
351
352 TAILQ_FOREACH(s, &g_part_schemes, scheme_list) {
353 if (s == &g_part_null_scheme)
354 continue;
355 if (!strcasecmp(s->name, p))
356 break;
357 }
358 if (s == NULL)
359 return (EINVAL);
360 *v = s;
361 return (0);
362}
363
364static int
365g_part_parm_str(const char *p, const char **v)
366{
367
368 if (p[0] == '\0')
369 return (EINVAL);
370 *v = p;
371 return (0);
372}
373
374static int
375g_part_parm_uint(const char *p, u_int *v)
376{
377 char *x;
378 long l;
379
380 l = strtol(p, &x, 0);
381 if (*x != '\0' || l < 0 || l > INT_MAX)
382 return (EINVAL);
383 *v = (unsigned int)l;
384 return (0);
385}
386
387static int
388g_part_probe(struct g_geom *gp, struct g_consumer *cp, int depth)
389{
390 struct g_part_scheme *iter, *scheme;
391 struct g_part_table *table;
392 int pri, probe;
393
394 table = gp->softc;
395 scheme = (table != NULL) ? table->gpt_scheme : NULL;
396 pri = (scheme != NULL) ? G_PART_PROBE(table, cp) : INT_MIN;
397 if (pri == 0)
398 goto done;
399 if (pri > 0) { /* error */
400 scheme = NULL;
401 pri = INT_MIN;
402 }
403
404 TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) {
405 if (iter == &g_part_null_scheme)
406 continue;
407 table = (void *)kobj_create((kobj_class_t)iter, M_GEOM,
408 M_WAITOK);
409 table->gpt_gp = gp;
410 table->gpt_scheme = iter;
411 table->gpt_depth = depth;
412 probe = G_PART_PROBE(table, cp);
413 if (probe <= 0 && probe > pri) {
414 pri = probe;
415 scheme = iter;
416 if (gp->softc != NULL)
417 kobj_delete((kobj_t)gp->softc, M_GEOM);
418 gp->softc = table;
419 if (pri == 0)
420 goto done;
421 } else
422 kobj_delete((kobj_t)table, M_GEOM);
423 }
424
425done:
426 return ((scheme == NULL) ? ENXIO : 0);
427}
428
429/*
430 * Control request functions.
431 */
432
433static int
434g_part_ctl_add(struct gctl_req *req, struct g_part_parms *gpp)
435{
436 struct g_geom *gp;
437 struct g_provider *pp;
438 struct g_part_entry *delent, *last, *entry;
439 struct g_part_table *table;
440 struct sbuf *sb;
441 quad_t end;
442 unsigned int index;
443 int error;
444
445 gp = gpp->gpp_geom;
446 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
447 g_topology_assert();
448
449 pp = LIST_FIRST(&gp->consumer)->provider;
450 table = gp->softc;
451 end = gpp->gpp_start + gpp->gpp_size - 1;
452
453 if (gpp->gpp_start < table->gpt_first ||
454 gpp->gpp_start > table->gpt_last) {
455 gctl_error(req, "%d start '%jd'", EINVAL,
456 (intmax_t)gpp->gpp_start);
457 return (EINVAL);
458 }
459 if (end < gpp->gpp_start || end > table->gpt_last) {
460 gctl_error(req, "%d size '%jd'", EINVAL,
461 (intmax_t)gpp->gpp_size);
462 return (EINVAL);
463 }
464 if (gpp->gpp_index > table->gpt_entries) {
465 gctl_error(req, "%d index '%d'", EINVAL, gpp->gpp_index);
466 return (EINVAL);
467 }
468
469 delent = last = NULL;
470 index = (gpp->gpp_index > 0) ? gpp->gpp_index : 1;
471 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
472 if (entry->gpe_deleted) {
473 if (entry->gpe_index == index)
474 delent = entry;
475 continue;
476 }
477 if (entry->gpe_index == index)
478 index = entry->gpe_index + 1;
479 if (entry->gpe_index < index)
480 last = entry;
481 if (entry->gpe_internal)
482 continue;
483 if (gpp->gpp_start >= entry->gpe_start &&
484 gpp->gpp_start <= entry->gpe_end) {
485 gctl_error(req, "%d start '%jd'", ENOSPC,
486 (intmax_t)gpp->gpp_start);
487 return (ENOSPC);
488 }
489 if (end >= entry->gpe_start && end <= entry->gpe_end) {
490 gctl_error(req, "%d end '%jd'", ENOSPC, (intmax_t)end);
491 return (ENOSPC);
492 }
493 if (gpp->gpp_start < entry->gpe_start && end > entry->gpe_end) {
494 gctl_error(req, "%d size '%jd'", ENOSPC,
495 (intmax_t)gpp->gpp_size);
496 return (ENOSPC);
497 }
498 }
499 if (gpp->gpp_index > 0 && index != gpp->gpp_index) {
500 gctl_error(req, "%d index '%d'", EEXIST, gpp->gpp_index);
501 return (EEXIST);
502 }
503 if (index > table->gpt_entries) {
504 gctl_error(req, "%d index '%d'", ENOSPC, index);
505 return (ENOSPC);
506 }
507
508 entry = (delent == NULL) ? g_malloc(table->gpt_scheme->gps_entrysz,
509 M_WAITOK | M_ZERO) : delent;
510 entry->gpe_index = index;
511 entry->gpe_start = gpp->gpp_start;
512 entry->gpe_end = end;
513 error = G_PART_ADD(table, entry, gpp);
514 if (error) {
515 gctl_error(req, "%d", error);
516 if (delent == NULL)
517 g_free(entry);
518 return (error);
519 }
520 if (delent == NULL) {
521 if (last == NULL)
522 LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry);
523 else
524 LIST_INSERT_AFTER(last, entry, gpe_entry);
525 entry->gpe_created = 1;
526 } else {
527 entry->gpe_deleted = 0;
528 entry->gpe_modified = 1;
529 }
530 g_part_new_provider(gp, table, entry);
531
532 /* Provide feedback if so requested. */
533 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
534 sb = sbuf_new_auto();
535 G_PART_FULLNAME(table, entry, sb, gp->name);
536 sbuf_cat(sb, " added\n");
537 sbuf_finish(sb);
538 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
539 sbuf_delete(sb);
540 }
541 return (0);
542}
543
544static int
545g_part_ctl_bootcode(struct gctl_req *req, struct g_part_parms *gpp)
546{
547 struct g_geom *gp;
548 struct g_part_table *table;
549 struct sbuf *sb;
550 int error, sz;
551
552 gp = gpp->gpp_geom;
553 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
554 g_topology_assert();
555
556 table = gp->softc;
557 sz = table->gpt_scheme->gps_bootcodesz;
558 if (sz == 0) {
559 error = ENODEV;
560 goto fail;
561 }
562 if (gpp->gpp_codesize > sz) {
563 error = EFBIG;
564 goto fail;
565 }
566
567 error = G_PART_BOOTCODE(table, gpp);
568 if (error)
569 goto fail;
570
571 /* Provide feedback if so requested. */
572 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
573 sb = sbuf_new_auto();
574 sbuf_printf(sb, "%s has bootcode\n", gp->name);
575 sbuf_finish(sb);
576 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
577 sbuf_delete(sb);
578 }
579 return (0);
580
581 fail:
582 gctl_error(req, "%d", error);
583 return (error);
584}
585
586static int
587g_part_ctl_commit(struct gctl_req *req, struct g_part_parms *gpp)
588{
589 struct g_consumer *cp;
590 struct g_geom *gp;
591 struct g_provider *pp;
592 struct g_part_entry *entry, *tmp;
593 struct g_part_table *table;
594 char *buf;
595 int error, i;
596
597 gp = gpp->gpp_geom;
598 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
599 g_topology_assert();
600
601 table = gp->softc;
602 if (!table->gpt_opened) {
603 gctl_error(req, "%d", EPERM);
604 return (EPERM);
605 }
606
607 g_topology_unlock();
608
609 cp = LIST_FIRST(&gp->consumer);
610 if ((table->gpt_smhead | table->gpt_smtail) != 0) {
611 pp = cp->provider;
612 buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
613 while (table->gpt_smhead != 0) {
614 i = ffs(table->gpt_smhead) - 1;
615 error = g_write_data(cp, i * pp->sectorsize, buf,
616 pp->sectorsize);
617 if (error) {
618 g_free(buf);
619 goto fail;
620 }
621 table->gpt_smhead &= ~(1 << i);
622 }
623 while (table->gpt_smtail != 0) {
624 i = ffs(table->gpt_smtail) - 1;
625 error = g_write_data(cp, pp->mediasize - (i + 1) *
626 pp->sectorsize, buf, pp->sectorsize);
627 if (error) {
628 g_free(buf);
629 goto fail;
630 }
631 table->gpt_smtail &= ~(1 << i);
632 }
633 g_free(buf);
634 }
635
636 if (table->gpt_scheme == &g_part_null_scheme) {
637 g_topology_lock();
638 g_access(cp, -1, -1, -1);
639 g_part_wither(gp, ENXIO);
640 return (0);
641 }
642
643 error = G_PART_WRITE(table, cp);
644 if (error)
645 goto fail;
646
647 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
648 if (!entry->gpe_deleted) {
649 entry->gpe_created = 0;
650 entry->gpe_modified = 0;
651 continue;
652 }
653 LIST_REMOVE(entry, gpe_entry);
654 g_free(entry);
655 }
656 table->gpt_created = 0;
657 table->gpt_opened = 0;
658
659 g_topology_lock();
660 g_access(cp, -1, -1, -1);
661 return (0);
662
663fail:
664 g_topology_lock();
665 gctl_error(req, "%d", error);
666 return (error);
667}
668
669static int
670g_part_ctl_create(struct gctl_req *req, struct g_part_parms *gpp)
671{
672 struct g_consumer *cp;
673 struct g_geom *gp;
674 struct g_provider *pp;
675 struct g_part_scheme *scheme;
676 struct g_part_table *null, *table;
677 struct sbuf *sb;
678 int attr, error;
679
680 pp = gpp->gpp_provider;
681 scheme = gpp->gpp_scheme;
682 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name));
683 g_topology_assert();
684
685 /* Check that there isn't already a g_part geom on the provider. */
686 error = g_part_parm_geom(pp->name, &gp);
687 if (!error) {
688 null = gp->softc;
689 if (null->gpt_scheme != &g_part_null_scheme) {
690 gctl_error(req, "%d geom '%s'", EEXIST, pp->name);
691 return (EEXIST);
692 }
693 } else
694 null = NULL;
695
696 if ((gpp->gpp_parms & G_PART_PARM_ENTRIES) &&
697 (gpp->gpp_entries < scheme->gps_minent ||
698 gpp->gpp_entries > scheme->gps_maxent)) {
699 gctl_error(req, "%d entries '%d'", EINVAL, gpp->gpp_entries);
700 return (EINVAL);
701 }
702
703 if (null == NULL)
704 gp = g_new_geomf(&g_part_class, "%s", pp->name);
705 gp->softc = kobj_create((kobj_class_t)gpp->gpp_scheme, M_GEOM,
706 M_WAITOK);
707 table = gp->softc;
708 table->gpt_gp = gp;
709 table->gpt_scheme = gpp->gpp_scheme;
710 table->gpt_entries = (gpp->gpp_parms & G_PART_PARM_ENTRIES) ?
711 gpp->gpp_entries : scheme->gps_minent;
712 LIST_INIT(&table->gpt_entry);
713 if (null == NULL) {
714 cp = g_new_consumer(gp);
715 error = g_attach(cp, pp);
716 if (error == 0)
717 error = g_access(cp, 1, 1, 1);
718 if (error != 0) {
719 g_part_wither(gp, error);
720 gctl_error(req, "%d geom '%s'", error, pp->name);
721 return (error);
722 }
723 table->gpt_opened = 1;
724 } else {
725 cp = LIST_FIRST(&gp->consumer);
726 table->gpt_opened = null->gpt_opened;
727 table->gpt_smhead = null->gpt_smhead;
728 table->gpt_smtail = null->gpt_smtail;
729 }
730
731 g_topology_unlock();
732
733 /* Make sure the provider has media. */
734 if (pp->mediasize == 0 || pp->sectorsize == 0) {
735 error = ENODEV;
736 goto fail;
737 }
738
739 /* Make sure we can nest and if so, determine our depth. */
740 error = g_getattr("PART::isleaf", cp, &attr);
741 if (!error && attr) {
742 error = ENODEV;
743 goto fail;
744 }
745 error = g_getattr("PART::depth", cp, &attr);
746 table->gpt_depth = (!error) ? attr + 1 : 0;
747
748 /*
749 * Synthesize a disk geometry. Some partitioning schemes
750 * depend on it and since some file systems need it even
751 * when the partitition scheme doesn't, we do it here in
752 * scheme-independent code.
753 */
754 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
755
756 error = G_PART_CREATE(table, gpp);
757 if (error)
758 goto fail;
759
760 g_topology_lock();
761
762 table->gpt_created = 1;
763 if (null != NULL)
764 kobj_delete((kobj_t)null, M_GEOM);
765
766 /*
767 * Support automatic commit by filling in the gpp_geom
768 * parameter.
769 */
770 gpp->gpp_parms |= G_PART_PARM_GEOM;
771 gpp->gpp_geom = gp;
772
773 /* Provide feedback if so requested. */
774 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
775 sb = sbuf_new_auto();
776 sbuf_printf(sb, "%s created\n", gp->name);
777 sbuf_finish(sb);
778 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
779 sbuf_delete(sb);
780 }
781 return (0);
782
783fail:
784 g_topology_lock();
785 if (null == NULL) {
786 g_access(cp, -1, -1, -1);
787 g_part_wither(gp, error);
788 } else {
789 kobj_delete((kobj_t)gp->softc, M_GEOM);
790 gp->softc = null;
791 }
792 gctl_error(req, "%d provider", error);
793 return (error);
794}
795
796static int
797g_part_ctl_delete(struct gctl_req *req, struct g_part_parms *gpp)
798{
799 struct g_geom *gp;
800 struct g_provider *pp;
801 struct g_part_entry *entry;
802 struct g_part_table *table;
803 struct sbuf *sb;
804
805 gp = gpp->gpp_geom;
806 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
807 g_topology_assert();
808
809 table = gp->softc;
810
811 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
812 if (entry->gpe_deleted || entry->gpe_internal)
813 continue;
814 if (entry->gpe_index == gpp->gpp_index)
815 break;
816 }
817 if (entry == NULL) {
818 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
819 return (ENOENT);
820 }
821
822 pp = entry->gpe_pp;
823 if (pp != NULL) {
824 if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) {
825 gctl_error(req, "%d", EBUSY);
826 return (EBUSY);
827 }
828
829 pp->private = NULL;
830 entry->gpe_pp = NULL;
831 }
832
833 if (entry->gpe_created) {
834 LIST_REMOVE(entry, gpe_entry);
835 g_free(entry);
836 } else {
837 entry->gpe_modified = 0;
838 entry->gpe_deleted = 1;
839 }
840
841 if (pp != NULL)
842 g_wither_provider(pp, ENXIO);
843
844 /* Provide feedback if so requested. */
845 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
846 sb = sbuf_new_auto();
847 G_PART_FULLNAME(table, entry, sb, gp->name);
848 sbuf_cat(sb, " deleted\n");
849 sbuf_finish(sb);
850 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
851 sbuf_delete(sb);
852 }
853 return (0);
854}
855
856static int
857g_part_ctl_destroy(struct gctl_req *req, struct g_part_parms *gpp)
858{
859 struct g_geom *gp;
860 struct g_part_entry *entry;
861 struct g_part_table *null, *table;
862 struct sbuf *sb;
863 int error;
864
865 gp = gpp->gpp_geom;
866 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
867 g_topology_assert();
868
869 table = gp->softc;
870 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
871 if (entry->gpe_deleted || entry->gpe_internal)
872 continue;
873 gctl_error(req, "%d", EBUSY);
874 return (EBUSY);
875 }
876
877 error = G_PART_DESTROY(table, gpp);
878 if (error) {
879 gctl_error(req, "%d", error);
880 return (error);
881 }
882
883 gp->softc = kobj_create((kobj_class_t)&g_part_null_scheme, M_GEOM,
884 M_WAITOK);
885 null = gp->softc;
886 null->gpt_gp = gp;
887 null->gpt_scheme = &g_part_null_scheme;
888 LIST_INIT(&null->gpt_entry);
889 null->gpt_depth = table->gpt_depth;
890 null->gpt_opened = table->gpt_opened;
891 null->gpt_smhead = table->gpt_smhead;
892 null->gpt_smtail = table->gpt_smtail;
893
894 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
895 LIST_REMOVE(entry, gpe_entry);
896 g_free(entry);
897 }
898 kobj_delete((kobj_t)table, M_GEOM);
899
900 /* Provide feedback if so requested. */
901 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
902 sb = sbuf_new_auto();
903 sbuf_printf(sb, "%s destroyed\n", gp->name);
904 sbuf_finish(sb);
905 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
906 sbuf_delete(sb);
907 }
908 return (0);
909}
910
911static int
912g_part_ctl_modify(struct gctl_req *req, struct g_part_parms *gpp)
913{
914 struct g_geom *gp;
915 struct g_part_entry *entry;
916 struct g_part_table *table;
917 struct sbuf *sb;
918 int error;
919
920 gp = gpp->gpp_geom;
921 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
922 g_topology_assert();
923
924 table = gp->softc;
925
926 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
927 if (entry->gpe_deleted || entry->gpe_internal)
928 continue;
929 if (entry->gpe_index == gpp->gpp_index)
930 break;
931 }
932 if (entry == NULL) {
933 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
934 return (ENOENT);
935 }
936
937 error = G_PART_MODIFY(table, entry, gpp);
938 if (error) {
939 gctl_error(req, "%d", error);
940 return (error);
941 }
942
943 if (!entry->gpe_created)
944 entry->gpe_modified = 1;
945
946 /* Provide feedback if so requested. */
947 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
948 sb = sbuf_new_auto();
949 G_PART_FULLNAME(table, entry, sb, gp->name);
950 sbuf_cat(sb, " modified\n");
951 sbuf_finish(sb);
952 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
953 sbuf_delete(sb);
954 }
955 return (0);
956}
957
958static int
959g_part_ctl_move(struct gctl_req *req, struct g_part_parms *gpp)
960{
961 gctl_error(req, "%d verb 'move'", ENOSYS);
962 return (ENOSYS);
963}
964
965static int
966g_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp)
967{
968 gctl_error(req, "%d verb 'recover'", ENOSYS);
969 return (ENOSYS);
970}
971
972static int
973g_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp)
974{
975 gctl_error(req, "%d verb 'resize'", ENOSYS);
976 return (ENOSYS);
977}
978
979static int
980g_part_ctl_setunset(struct gctl_req *req, struct g_part_parms *gpp,
981 unsigned int set)
982{
983 struct g_geom *gp;
984 struct g_part_entry *entry;
985 struct g_part_table *table;
986 struct sbuf *sb;
987 int error;
988
989 gp = gpp->gpp_geom;
990 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
991 g_topology_assert();
992
993 table = gp->softc;
994
995 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
996 if (entry->gpe_deleted || entry->gpe_internal)
997 continue;
998 if (entry->gpe_index == gpp->gpp_index)
999 break;
1000 }
1001 if (entry == NULL) {
1002 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
1003 return (ENOENT);
1004 }
1005
1006 error = G_PART_SETUNSET(table, entry, gpp->gpp_attrib, set);
1007 if (error) {
1008 gctl_error(req, "%d attrib '%s'", error, gpp->gpp_attrib);
1009 return (error);
1010 }
1011
1012 /* Provide feedback if so requested. */
1013 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1014 sb = sbuf_new_auto();
1015 G_PART_FULLNAME(table, entry, sb, gp->name);
1016 sbuf_printf(sb, " has %s %sset\n", gpp->gpp_attrib,
1017 (set) ? "" : "un");
1018 sbuf_finish(sb);
1019 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1020 sbuf_delete(sb);
1021 }
1022 return (0);
1023}
1024
1025static int
1026g_part_ctl_undo(struct gctl_req *req, struct g_part_parms *gpp)
1027{
1028 struct g_consumer *cp;
1029 struct g_provider *pp;
1030 struct g_geom *gp;
1031 struct g_part_entry *entry, *tmp;
1032 struct g_part_table *table;
1033 int error, reprobe;
1034
1035 gp = gpp->gpp_geom;
1036 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1037 g_topology_assert();
1038
1039 table = gp->softc;
1040 if (!table->gpt_opened) {
1041 gctl_error(req, "%d", EPERM);
1042 return (EPERM);
1043 }
1044
1045 cp = LIST_FIRST(&gp->consumer);
1046 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
1047 entry->gpe_modified = 0;
1048 if (entry->gpe_created) {
1049 pp = entry->gpe_pp;
1050 if (pp != NULL) {
1051 pp->private = NULL;
1052 entry->gpe_pp = NULL;
1053 g_wither_provider(pp, ENXIO);
1054 }
1055 entry->gpe_deleted = 1;
1056 }
1057 if (entry->gpe_deleted) {
1058 LIST_REMOVE(entry, gpe_entry);
1059 g_free(entry);
1060 }
1061 }
1062
1063 g_topology_unlock();
1064
1065 reprobe = (table->gpt_scheme == &g_part_null_scheme ||
1066 table->gpt_created) ? 1 : 0;
1067
1068 if (reprobe) {
1069 if (!LIST_EMPTY(&table->gpt_entry)) {
1070 error = EBUSY;
1071 goto fail;
1072 }
1073 error = g_part_probe(gp, cp, table->gpt_depth);
1074 if (error) {
1075 g_topology_lock();
1076 g_access(cp, -1, -1, -1);
1077 g_part_wither(gp, error);
1078 return (0);
1079 }
1080 table = gp->softc;
1081 }
1082
1083 error = G_PART_READ(table, cp);
1084 if (error)
1085 goto fail;
1086
1087 g_topology_lock();
1088
1089 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1090 if (!entry->gpe_internal)
1091 g_part_new_provider(gp, table, entry);
1092 }
1093
1094 table->gpt_opened = 0;
1095 g_access(cp, -1, -1, -1);
1096 return (0);
1097
1098fail:
1099 g_topology_lock();
1100 gctl_error(req, "%d", error);
1101 return (error);
1102}
1103
1104static void
1105g_part_wither(struct g_geom *gp, int error)
1106{
1107 struct g_part_entry *entry;
1108 struct g_part_table *table;
1109
1110 table = gp->softc;
1111 if (table != NULL) {
1112 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
1113 LIST_REMOVE(entry, gpe_entry);
1114 g_free(entry);
1115 }
1116 if (gp->softc != NULL) {
1117 kobj_delete((kobj_t)gp->softc, M_GEOM);
1118 gp->softc = NULL;
1119 }
1120 }
1121 g_wither_geom(gp, error);
1122}
1123
1124/*
1125 * Class methods.
1126 */
1127
1128static void
1129g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb)
1130{
1131 struct g_part_parms gpp;
1132 struct g_part_table *table;
1133 struct gctl_req_arg *ap;
1134 const char *p;
1135 enum g_part_ctl ctlreq;
1136 unsigned int i, mparms, oparms, parm;
1137 int auto_commit, close_on_error;
1138 int error, len, modifies;
1139
1140 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb));
1141 g_topology_assert();
1142
1143 ctlreq = G_PART_CTL_NONE;
1144 modifies = 1;
1145 mparms = 0;
1146 oparms = G_PART_PARM_FLAGS | G_PART_PARM_OUTPUT | G_PART_PARM_VERSION;
1147 switch (*verb) {
1148 case 'a':
1149 if (!strcmp(verb, "add")) {
1150 ctlreq = G_PART_CTL_ADD;
1151 mparms |= G_PART_PARM_GEOM | G_PART_PARM_SIZE |
1152 G_PART_PARM_START | G_PART_PARM_TYPE;
1153 oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL;
1154 }
1155 break;
1156 case 'b':
1157 if (!strcmp(verb, "bootcode")) {
1158 ctlreq = G_PART_CTL_BOOTCODE;
1159 mparms |= G_PART_PARM_GEOM | G_PART_PARM_BOOTCODE;
1160 }
1161 break;
1162 case 'c':
1163 if (!strcmp(verb, "commit")) {
1164 ctlreq = G_PART_CTL_COMMIT;
1165 mparms |= G_PART_PARM_GEOM;
1166 modifies = 0;
1167 } else if (!strcmp(verb, "create")) {
1168 ctlreq = G_PART_CTL_CREATE;
1169 mparms |= G_PART_PARM_PROVIDER | G_PART_PARM_SCHEME;
1170 oparms |= G_PART_PARM_ENTRIES;
1171 }
1172 break;
1173 case 'd':
1174 if (!strcmp(verb, "delete")) {
1175 ctlreq = G_PART_CTL_DELETE;
1176 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1177 } else if (!strcmp(verb, "destroy")) {
1178 ctlreq = G_PART_CTL_DESTROY;
1179 mparms |= G_PART_PARM_GEOM;
1180 }
1181 break;
1182 case 'm':
1183 if (!strcmp(verb, "modify")) {
1184 ctlreq = G_PART_CTL_MODIFY;
1185 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1186 oparms |= G_PART_PARM_LABEL | G_PART_PARM_TYPE;
1187 } else if (!strcmp(verb, "move")) {
1188 ctlreq = G_PART_CTL_MOVE;
1189 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1190 }
1191 break;
1192 case 'r':
1193 if (!strcmp(verb, "recover")) {
1194 ctlreq = G_PART_CTL_RECOVER;
1195 mparms |= G_PART_PARM_GEOM;
1196 } else if (!strcmp(verb, "resize")) {
1197 ctlreq = G_PART_CTL_RESIZE;
1198 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1199 }
1200 break;
1201 case 's':
1202 if (!strcmp(verb, "set")) {
1203 ctlreq = G_PART_CTL_SET;
1204 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM |
1205 G_PART_PARM_INDEX;
1206 }
1207 break;
1208 case 'u':
1209 if (!strcmp(verb, "undo")) {
1210 ctlreq = G_PART_CTL_UNDO;
1211 mparms |= G_PART_PARM_GEOM;
1212 modifies = 0;
1213 } else if (!strcmp(verb, "unset")) {
1214 ctlreq = G_PART_CTL_UNSET;
1215 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM |
1216 G_PART_PARM_INDEX;
1217 }
1218 break;
1219 }
1220 if (ctlreq == G_PART_CTL_NONE) {
1221 gctl_error(req, "%d verb '%s'", EINVAL, verb);
1222 return;
1223 }
1224
1225 bzero(&gpp, sizeof(gpp));
1226 for (i = 0; i < req->narg; i++) {
1227 ap = &req->arg[i];
1228 parm = 0;
1229 switch (ap->name[0]) {
1230 case 'a':
1231 if (!strcmp(ap->name, "attrib"))
1232 parm = G_PART_PARM_ATTRIB;
1233 break;
1234 case 'b':
1235 if (!strcmp(ap->name, "bootcode"))
1236 parm = G_PART_PARM_BOOTCODE;
1237 break;
1238 case 'c':
1239 if (!strcmp(ap->name, "class"))
1240 continue;
1241 break;
1242 case 'e':
1243 if (!strcmp(ap->name, "entries"))
1244 parm = G_PART_PARM_ENTRIES;
1245 break;
1246 case 'f':
1247 if (!strcmp(ap->name, "flags"))
1248 parm = G_PART_PARM_FLAGS;
1249 break;
1250 case 'g':
1251 if (!strcmp(ap->name, "geom"))
1252 parm = G_PART_PARM_GEOM;
1253 break;
1254 case 'i':
1255 if (!strcmp(ap->name, "index"))
1256 parm = G_PART_PARM_INDEX;
1257 break;
1258 case 'l':
1259 if (!strcmp(ap->name, "label"))
1260 parm = G_PART_PARM_LABEL;
1261 break;
1262 case 'o':
1263 if (!strcmp(ap->name, "output"))
1264 parm = G_PART_PARM_OUTPUT;
1265 break;
1266 case 'p':
1267 if (!strcmp(ap->name, "provider"))
1268 parm = G_PART_PARM_PROVIDER;
1269 break;
1270 case 's':
1271 if (!strcmp(ap->name, "scheme"))
1272 parm = G_PART_PARM_SCHEME;
1273 else if (!strcmp(ap->name, "size"))
1274 parm = G_PART_PARM_SIZE;
1275 else if (!strcmp(ap->name, "start"))
1276 parm = G_PART_PARM_START;
1277 break;
1278 case 't':
1279 if (!strcmp(ap->name, "type"))
1280 parm = G_PART_PARM_TYPE;
1281 break;
1282 case 'v':
1283 if (!strcmp(ap->name, "verb"))
1284 continue;
1285 else if (!strcmp(ap->name, "version"))
1286 parm = G_PART_PARM_VERSION;
1287 break;
1288 }
1289 if ((parm & (mparms | oparms)) == 0) {
1290 gctl_error(req, "%d param '%s'", EINVAL, ap->name);
1291 return;
1292 }
1293 if (parm == G_PART_PARM_BOOTCODE)
1294 p = gctl_get_param(req, ap->name, &len);
1295 else
1296 p = gctl_get_asciiparam(req, ap->name);
1297 if (p == NULL) {
1298 gctl_error(req, "%d param '%s'", ENOATTR, ap->name);
1299 return;
1300 }
1301 switch (parm) {
1302 case G_PART_PARM_ATTRIB:
1303 error = g_part_parm_str(p, &gpp.gpp_attrib);
1304 break;
1305 case G_PART_PARM_BOOTCODE:
1306 gpp.gpp_codeptr = p;
1307 gpp.gpp_codesize = len;
1308 error = 0;
1309 break;
1310 case G_PART_PARM_ENTRIES:
1311 error = g_part_parm_uint(p, &gpp.gpp_entries);
1312 break;
1313 case G_PART_PARM_FLAGS:
1314 if (p[0] == '\0')
1315 continue;
1316 error = g_part_parm_str(p, &gpp.gpp_flags);
1317 break;
1318 case G_PART_PARM_GEOM:
1319 error = g_part_parm_geom(p, &gpp.gpp_geom);
1320 break;
1321 case G_PART_PARM_INDEX:
1322 error = g_part_parm_uint(p, &gpp.gpp_index);
1323 break;
1324 case G_PART_PARM_LABEL:
1325 /* An empty label is always valid. */
1326 gpp.gpp_label = p;
1327 error = 0;
1328 break;
1329 case G_PART_PARM_OUTPUT:
1330 error = 0; /* Write-only parameter */
1331 break;
1332 case G_PART_PARM_PROVIDER:
1333 error = g_part_parm_provider(p, &gpp.gpp_provider);
1334 break;
1335 case G_PART_PARM_SCHEME:
1336 error = g_part_parm_scheme(p, &gpp.gpp_scheme);
1337 break;
1338 case G_PART_PARM_SIZE:
1339 error = g_part_parm_quad(p, &gpp.gpp_size);
1340 break;
1341 case G_PART_PARM_START:
1342 error = g_part_parm_quad(p, &gpp.gpp_start);
1343 break;
1344 case G_PART_PARM_TYPE:
1345 error = g_part_parm_str(p, &gpp.gpp_type);
1346 break;
1347 case G_PART_PARM_VERSION:
1348 error = g_part_parm_uint(p, &gpp.gpp_version);
1349 break;
1350 default:
1351 error = EDOOFUS;
1352 break;
1353 }
1354 if (error) {
1355 gctl_error(req, "%d %s '%s'", error, ap->name, p);
1356 return;
1357 }
1358 gpp.gpp_parms |= parm;
1359 }
1360 if ((gpp.gpp_parms & mparms) != mparms) {
1361 parm = mparms - (gpp.gpp_parms & mparms);
1362 gctl_error(req, "%d param '%x'", ENOATTR, parm);
1363 return;
1364 }
1365
1366 /* Obtain permissions if possible/necessary. */
1367 close_on_error = 0;
1368 table = NULL;
1369 if (modifies && (gpp.gpp_parms & G_PART_PARM_GEOM)) {
1370 table = gpp.gpp_geom->softc;
1371 if (table != NULL && !table->gpt_opened) {
1372 error = g_access(LIST_FIRST(&gpp.gpp_geom->consumer),
1373 1, 1, 1);
1374 if (error) {
1375 gctl_error(req, "%d geom '%s'", error,
1376 gpp.gpp_geom->name);
1377 return;
1378 }
1379 table->gpt_opened = 1;
1380 close_on_error = 1;
1381 }
1382 }
1383
1384 /* Allow the scheme to check or modify the parameters. */
1385 if (table != NULL) {
1386 error = G_PART_PRECHECK(table, ctlreq, &gpp);
1387 if (error) {
1388 gctl_error(req, "%d pre-check failed", error);
1389 goto out;
1390 }
1391 } else
1392 error = EDOOFUS; /* Prevent bogus uninit. warning. */
1393
1394 switch (ctlreq) {
1395 case G_PART_CTL_NONE:
1396 panic("%s", __func__);
1397 case G_PART_CTL_ADD:
1398 error = g_part_ctl_add(req, &gpp);
1399 break;
1400 case G_PART_CTL_BOOTCODE:
1401 error = g_part_ctl_bootcode(req, &gpp);
1402 break;
1403 case G_PART_CTL_COMMIT:
1404 error = g_part_ctl_commit(req, &gpp);
1405 break;
1406 case G_PART_CTL_CREATE:
1407 error = g_part_ctl_create(req, &gpp);
1408 break;
1409 case G_PART_CTL_DELETE:
1410 error = g_part_ctl_delete(req, &gpp);
1411 break;
1412 case G_PART_CTL_DESTROY:
1413 error = g_part_ctl_destroy(req, &gpp);
1414 break;
1415 case G_PART_CTL_MODIFY:
1416 error = g_part_ctl_modify(req, &gpp);
1417 break;
1418 case G_PART_CTL_MOVE:
1419 error = g_part_ctl_move(req, &gpp);
1420 break;
1421 case G_PART_CTL_RECOVER:
1422 error = g_part_ctl_recover(req, &gpp);
1423 break;
1424 case G_PART_CTL_RESIZE:
1425 error = g_part_ctl_resize(req, &gpp);
1426 break;
1427 case G_PART_CTL_SET:
1428 error = g_part_ctl_setunset(req, &gpp, 1);
1429 break;
1430 case G_PART_CTL_UNDO:
1431 error = g_part_ctl_undo(req, &gpp);
1432 break;
1433 case G_PART_CTL_UNSET:
1434 error = g_part_ctl_setunset(req, &gpp, 0);
1435 break;
1436 }
1437
1438 /* Implement automatic commit. */
1439 if (!error) {
1440 auto_commit = (modifies &&
1441 (gpp.gpp_parms & G_PART_PARM_FLAGS) &&
1442 strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0;
1443 if (auto_commit) {
1444 KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, (__func__));
1445 error = g_part_ctl_commit(req, &gpp);
1446 }
1447 }
1448
1449 out:
1450 if (error && close_on_error) {
1451 g_access(LIST_FIRST(&gpp.gpp_geom->consumer), -1, -1, -1);
1452 table->gpt_opened = 0;
1453 }
1454}
1455
1456static int
1457g_part_destroy_geom(struct gctl_req *req, struct g_class *mp,
1458 struct g_geom *gp)
1459{
1460
1461 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name));
1462 g_topology_assert();
1463
1464 g_part_wither(gp, EINVAL);
1465 return (0);
1466}
1467
1468static struct g_geom *
1469g_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
1470{
1471 struct g_consumer *cp;
1472 struct g_geom *gp;
1473 struct g_part_entry *entry;
1474 struct g_part_table *table;
1475 struct root_hold_token *rht;
1476 int attr, depth;
1477 int error;
1478
1479 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name));
1480 g_topology_assert();
1481
1482 /* Skip providers that are already open for writing. */
1483 if (pp->acw > 0)
1484 return (NULL);
1485
1486 /*
1487 * Create a GEOM with consumer and hook it up to the provider.
1488 * With that we become part of the topology. Optain read access
1489 * to the provider.
1490 */
1491 gp = g_new_geomf(mp, "%s", pp->name);
1492 cp = g_new_consumer(gp);
1493 error = g_attach(cp, pp);
1494 if (error == 0)
1495 error = g_access(cp, 1, 0, 0);
1496 if (error != 0) {
1497 g_part_wither(gp, error);
1498 return (NULL);
1499 }
1500
1501 rht = root_mount_hold(mp->name);
1502 g_topology_unlock();
1503
1504 /*
1505 * Short-circuit the whole probing galore when there's no
1506 * media present.
1507 */
1508 if (pp->mediasize == 0 || pp->sectorsize == 0) {
1509 error = ENODEV;
1510 goto fail;
1511 }
1512
1513 /* Make sure we can nest and if so, determine our depth. */
1514 error = g_getattr("PART::isleaf", cp, &attr);
1515 if (!error && attr) {
1516 error = ENODEV;
1517 goto fail;
1518 }
1519 error = g_getattr("PART::depth", cp, &attr);
1520 depth = (!error) ? attr + 1 : 0;
1521
1522 error = g_part_probe(gp, cp, depth);
1523 if (error)
1524 goto fail;
1525
1526 table = gp->softc;
1527
1528 /*
1529 * Synthesize a disk geometry. Some partitioning schemes
1530 * depend on it and since some file systems need it even
1531 * when the partitition scheme doesn't, we do it here in
1532 * scheme-independent code.
1533 */
1534 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
1535
1536 error = G_PART_READ(table, cp);
1537 if (error)
1538 goto fail;
1539
1540 g_topology_lock();
1541 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1542 if (!entry->gpe_internal)
1543 g_part_new_provider(gp, table, entry);
1544 }
1545
1546 root_mount_rel(rht);
1547 g_access(cp, -1, 0, 0);
1548 return (gp);
1549
1550 fail:
1551 g_topology_lock();
1552 root_mount_rel(rht);
1553 g_access(cp, -1, 0, 0);
1554 g_part_wither(gp, error);
1555 return (NULL);
1556}
1557
1558/*
1559 * Geom methods.
1560 */
1561
1562static int
1563g_part_access(struct g_provider *pp, int dr, int dw, int de)
1564{
1565 struct g_consumer *cp;
1566
1567 G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr,
1568 dw, de));
1569
1570 cp = LIST_FIRST(&pp->geom->consumer);
1571
1572 /* We always gain write-exclusive access. */
1573 return (g_access(cp, dr, dw, dw + de));
1574}
1575
1576static void
1577g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
1578 struct g_consumer *cp, struct g_provider *pp)
1579{
1580 char buf[64];
1581 struct g_part_entry *entry;
1582 struct g_part_table *table;
1583
1584 KASSERT(sb != NULL && gp != NULL, (__func__));
1585 table = gp->softc;
1586
1587 if (indent == NULL) {
1588 KASSERT(cp == NULL && pp != NULL, (__func__));
1589 entry = pp->private;
1590 if (entry == NULL)
1591 return;
1592 sbuf_printf(sb, " i %u o %ju ty %s", entry->gpe_index,
1593 (uintmax_t)entry->gpe_offset,
1594 G_PART_TYPE(table, entry, buf, sizeof(buf)));
1595 /*
1596 * libdisk compatibility quirk - the scheme dumps the
1597 * slicer name and partition type in a way that is
1598 * compatible with libdisk. When libdisk is not used
1599 * anymore, this should go away.
1600 */
1601 G_PART_DUMPCONF(table, entry, sb, indent);
1602 } else if (cp != NULL) { /* Consumer configuration. */
1603 KASSERT(pp == NULL, (__func__));
1604 /* none */
1605 } else if (pp != NULL) { /* Provider configuration. */
1606 entry = pp->private;
1607 if (entry == NULL)
1608 return;
1609 sbuf_printf(sb, "%s<start>%ju</start>\n", indent,
1610 (uintmax_t)entry->gpe_start);
1611 sbuf_printf(sb, "%s<end>%ju</end>\n", indent,
1612 (uintmax_t)entry->gpe_end);
1613 sbuf_printf(sb, "%s<index>%u</index>\n", indent,
1614 entry->gpe_index);
1615 sbuf_printf(sb, "%s<type>%s</type>\n", indent,
1616 G_PART_TYPE(table, entry, buf, sizeof(buf)));
1617 sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent,
1618 (uintmax_t)entry->gpe_offset);
1619 sbuf_printf(sb, "%s<length>%ju</length>\n", indent,
1620 (uintmax_t)pp->mediasize);
1621 G_PART_DUMPCONF(table, entry, sb, indent);
1622 } else { /* Geom configuration. */
1623 sbuf_printf(sb, "%s<scheme>%s</scheme>\n", indent,
1624 table->gpt_scheme->name);
1625 sbuf_printf(sb, "%s<entries>%u</entries>\n", indent,
1626 table->gpt_entries);
1627 sbuf_printf(sb, "%s<first>%ju</first>\n", indent,
1628 (uintmax_t)table->gpt_first);
1629 sbuf_printf(sb, "%s<last>%ju</last>\n", indent,
1630 (uintmax_t)table->gpt_last);
1631 sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n", indent,
1632 table->gpt_sectors);
1633 sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n", indent,
1634 table->gpt_heads);
1635 G_PART_DUMPCONF(table, NULL, sb, indent);
1636 }
1637}
1638
1639static void
1640g_part_orphan(struct g_consumer *cp)
1641{
1642 struct g_provider *pp;
1643
1644 pp = cp->provider;
1645 KASSERT(pp != NULL, (__func__));
1646 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name));
1647 g_topology_assert();
1648
1649 KASSERT(pp->error != 0, (__func__));
1650 g_part_wither(cp->geom, pp->error);
1651}
1652
1653static void
1654g_part_spoiled(struct g_consumer *cp)
1655{
1656
1657 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name));
1658 g_topology_assert();
1659
1660 g_part_wither(cp->geom, ENXIO);
1661}
1662
1663static void
1664g_part_start(struct bio *bp)
1665{
1666 struct bio *bp2;
1667 struct g_consumer *cp;
1668 struct g_geom *gp;
1669 struct g_part_entry *entry;
1670 struct g_part_table *table;
1671 struct g_kerneldump *gkd;
1672 struct g_provider *pp;
1673
1674 pp = bp->bio_to;
1675 gp = pp->geom;
1676 table = gp->softc;
1677 cp = LIST_FIRST(&gp->consumer);
1678
1679 G_PART_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd,
1680 pp->name));
1681
1682 entry = pp->private;
1683 if (entry == NULL) {
1684 g_io_deliver(bp, ENXIO);
1685 return;
1686 }
1687
1688 switch(bp->bio_cmd) {
1689 case BIO_DELETE:
1690 case BIO_READ:
1691 case BIO_WRITE:
1692 if (bp->bio_offset >= pp->mediasize) {
1693 g_io_deliver(bp, EIO);
1694 return;
1695 }
1696 bp2 = g_clone_bio(bp);
1697 if (bp2 == NULL) {
1698 g_io_deliver(bp, ENOMEM);
1699 return;
1700 }
1701 if (bp2->bio_offset + bp2->bio_length > pp->mediasize)
1702 bp2->bio_length = pp->mediasize - bp2->bio_offset;
1703 bp2->bio_done = g_std_done;
1704 bp2->bio_offset += entry->gpe_offset;
1705 g_io_request(bp2, cp);
1706 return;
1707 case BIO_FLUSH:
1708 break;
1709 case BIO_GETATTR:
1710 if (g_handleattr_int(bp, "GEOM::fwheads", table->gpt_heads))
1711 return;
1712 if (g_handleattr_int(bp, "GEOM::fwsectors", table->gpt_sectors))
1713 return;
1714 if (g_handleattr_int(bp, "PART::isleaf", table->gpt_isleaf))
1715 return;
1716 if (g_handleattr_int(bp, "PART::depth", table->gpt_depth))
1717 return;
1718 if (g_handleattr_str(bp, "PART::scheme",
1719 table->gpt_scheme->name))
1720 return;
1721 if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) {
1722 /*
1723 * Check that the partition is suitable for kernel
1724 * dumps. Typically only swap partitions should be
1725 * used.
1726 */
1727 if (!G_PART_DUMPTO(table, entry)) {
1728 g_io_deliver(bp, ENODEV);
1729 printf("GEOM_PART: Partition '%s' not suitable"
1730 " for kernel dumps (wrong type?)\n",
1731 pp->name);
1732 return;
1733 }
1734 gkd = (struct g_kerneldump *)bp->bio_data;
1735 if (gkd->offset >= pp->mediasize) {
1736 g_io_deliver(bp, EIO);
1737 return;
1738 }
1739 if (gkd->offset + gkd->length > pp->mediasize)
1740 gkd->length = pp->mediasize - gkd->offset;
1741 gkd->offset += entry->gpe_offset;
1742 }
1743 break;
1744 default:
1745 g_io_deliver(bp, EOPNOTSUPP);
1746 return;
1747 }
1748
1749 bp2 = g_clone_bio(bp);
1750 if (bp2 == NULL) {
1751 g_io_deliver(bp, ENOMEM);
1752 return;
1753 }
1754 bp2->bio_done = g_std_done;
1755 g_io_request(bp2, cp);
1756}
1757
1758static void
1759g_part_init(struct g_class *mp)
1760{
1761
1762 TAILQ_INSERT_HEAD(&g_part_schemes, &g_part_null_scheme, scheme_list);
1763}
1764
1765static void
1766g_part_fini(struct g_class *mp)
1767{
1768
1769 TAILQ_REMOVE(&g_part_schemes, &g_part_null_scheme, scheme_list);
1770}
1771
1772static void
1773g_part_unload_event(void *arg, int flag)
1774{
1775 struct g_consumer *cp;
1776 struct g_geom *gp;
1777 struct g_provider *pp;
1778 struct g_part_scheme *scheme;
1779 struct g_part_table *table;
1780 uintptr_t *xchg;
1781 int acc, error;
1782
1783 if (flag == EV_CANCEL)
1784 return;
1785
1786 xchg = arg;
1787 error = 0;
1788 scheme = (void *)(*xchg);
1789
1790 g_topology_assert();
1791
1792 LIST_FOREACH(gp, &g_part_class.geom, geom) {
1793 table = gp->softc;
1794 if (table->gpt_scheme != scheme)
1795 continue;
1796
1797 acc = 0;
1798 LIST_FOREACH(pp, &gp->provider, provider)
1799 acc += pp->acr + pp->acw + pp->ace;
1800 LIST_FOREACH(cp, &gp->consumer, consumer)
1801 acc += cp->acr + cp->acw + cp->ace;
1802
1803 if (!acc)
1804 g_part_wither(gp, ENOSYS);
1805 else
1806 error = EBUSY;
1807 }
1808
1809 if (!error)
1810 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list);
1811
1812 *xchg = error;
1813}
1814
1815int
1816g_part_modevent(module_t mod, int type, struct g_part_scheme *scheme)
1817{
1818 uintptr_t arg;
1819 int error;
1820
1821 switch (type) {
1822 case MOD_LOAD:
1823 TAILQ_INSERT_TAIL(&g_part_schemes, scheme, scheme_list);
1824
1825 error = g_retaste(&g_part_class);
1826 if (error)
1827 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list);
1828 break;
1829 case MOD_UNLOAD:
1830 arg = (uintptr_t)scheme;
1831 error = g_waitfor_event(g_part_unload_event, &arg, M_WAITOK,
1832 NULL);
1833 if (!error)
1834 error = (arg == (uintptr_t)scheme) ? EDOOFUS : arg;
1835 break;
1836 default:
1837 error = EOPNOTSUPP;
1838 break;
1839 }
1840
1841 return (error);
1842}
295 g_error_provider(entry->gpe_pp, 0);
296}
297
298static int
299g_part_parm_geom(const char *rawname, struct g_geom **v)
300{
301 struct g_geom *gp;
302 const char *pname;
303
304 if (strncmp(rawname, _PATH_DEV, strlen(_PATH_DEV)) == 0)
305 pname = rawname + strlen(_PATH_DEV);
306 else
307 pname = rawname;
308 LIST_FOREACH(gp, &g_part_class.geom, geom) {
309 if (!strcmp(pname, gp->name))
310 break;
311 }
312 if (gp == NULL)
313 return (EINVAL);
314 *v = gp;
315 return (0);
316}
317
318static int
319g_part_parm_provider(const char *pname, struct g_provider **v)
320{
321 struct g_provider *pp;
322
323 if (strncmp(pname, _PATH_DEV, strlen(_PATH_DEV)) == 0)
324 pp = g_provider_by_name(pname + strlen(_PATH_DEV));
325 else
326 pp = g_provider_by_name(pname);
327 if (pp == NULL)
328 return (EINVAL);
329 *v = pp;
330 return (0);
331}
332
333static int
334g_part_parm_quad(const char *p, quad_t *v)
335{
336 char *x;
337 quad_t q;
338
339 q = strtoq(p, &x, 0);
340 if (*x != '\0' || q < 0)
341 return (EINVAL);
342 *v = q;
343 return (0);
344}
345
346static int
347g_part_parm_scheme(const char *p, struct g_part_scheme **v)
348{
349 struct g_part_scheme *s;
350
351 TAILQ_FOREACH(s, &g_part_schemes, scheme_list) {
352 if (s == &g_part_null_scheme)
353 continue;
354 if (!strcasecmp(s->name, p))
355 break;
356 }
357 if (s == NULL)
358 return (EINVAL);
359 *v = s;
360 return (0);
361}
362
363static int
364g_part_parm_str(const char *p, const char **v)
365{
366
367 if (p[0] == '\0')
368 return (EINVAL);
369 *v = p;
370 return (0);
371}
372
373static int
374g_part_parm_uint(const char *p, u_int *v)
375{
376 char *x;
377 long l;
378
379 l = strtol(p, &x, 0);
380 if (*x != '\0' || l < 0 || l > INT_MAX)
381 return (EINVAL);
382 *v = (unsigned int)l;
383 return (0);
384}
385
386static int
387g_part_probe(struct g_geom *gp, struct g_consumer *cp, int depth)
388{
389 struct g_part_scheme *iter, *scheme;
390 struct g_part_table *table;
391 int pri, probe;
392
393 table = gp->softc;
394 scheme = (table != NULL) ? table->gpt_scheme : NULL;
395 pri = (scheme != NULL) ? G_PART_PROBE(table, cp) : INT_MIN;
396 if (pri == 0)
397 goto done;
398 if (pri > 0) { /* error */
399 scheme = NULL;
400 pri = INT_MIN;
401 }
402
403 TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) {
404 if (iter == &g_part_null_scheme)
405 continue;
406 table = (void *)kobj_create((kobj_class_t)iter, M_GEOM,
407 M_WAITOK);
408 table->gpt_gp = gp;
409 table->gpt_scheme = iter;
410 table->gpt_depth = depth;
411 probe = G_PART_PROBE(table, cp);
412 if (probe <= 0 && probe > pri) {
413 pri = probe;
414 scheme = iter;
415 if (gp->softc != NULL)
416 kobj_delete((kobj_t)gp->softc, M_GEOM);
417 gp->softc = table;
418 if (pri == 0)
419 goto done;
420 } else
421 kobj_delete((kobj_t)table, M_GEOM);
422 }
423
424done:
425 return ((scheme == NULL) ? ENXIO : 0);
426}
427
428/*
429 * Control request functions.
430 */
431
432static int
433g_part_ctl_add(struct gctl_req *req, struct g_part_parms *gpp)
434{
435 struct g_geom *gp;
436 struct g_provider *pp;
437 struct g_part_entry *delent, *last, *entry;
438 struct g_part_table *table;
439 struct sbuf *sb;
440 quad_t end;
441 unsigned int index;
442 int error;
443
444 gp = gpp->gpp_geom;
445 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
446 g_topology_assert();
447
448 pp = LIST_FIRST(&gp->consumer)->provider;
449 table = gp->softc;
450 end = gpp->gpp_start + gpp->gpp_size - 1;
451
452 if (gpp->gpp_start < table->gpt_first ||
453 gpp->gpp_start > table->gpt_last) {
454 gctl_error(req, "%d start '%jd'", EINVAL,
455 (intmax_t)gpp->gpp_start);
456 return (EINVAL);
457 }
458 if (end < gpp->gpp_start || end > table->gpt_last) {
459 gctl_error(req, "%d size '%jd'", EINVAL,
460 (intmax_t)gpp->gpp_size);
461 return (EINVAL);
462 }
463 if (gpp->gpp_index > table->gpt_entries) {
464 gctl_error(req, "%d index '%d'", EINVAL, gpp->gpp_index);
465 return (EINVAL);
466 }
467
468 delent = last = NULL;
469 index = (gpp->gpp_index > 0) ? gpp->gpp_index : 1;
470 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
471 if (entry->gpe_deleted) {
472 if (entry->gpe_index == index)
473 delent = entry;
474 continue;
475 }
476 if (entry->gpe_index == index)
477 index = entry->gpe_index + 1;
478 if (entry->gpe_index < index)
479 last = entry;
480 if (entry->gpe_internal)
481 continue;
482 if (gpp->gpp_start >= entry->gpe_start &&
483 gpp->gpp_start <= entry->gpe_end) {
484 gctl_error(req, "%d start '%jd'", ENOSPC,
485 (intmax_t)gpp->gpp_start);
486 return (ENOSPC);
487 }
488 if (end >= entry->gpe_start && end <= entry->gpe_end) {
489 gctl_error(req, "%d end '%jd'", ENOSPC, (intmax_t)end);
490 return (ENOSPC);
491 }
492 if (gpp->gpp_start < entry->gpe_start && end > entry->gpe_end) {
493 gctl_error(req, "%d size '%jd'", ENOSPC,
494 (intmax_t)gpp->gpp_size);
495 return (ENOSPC);
496 }
497 }
498 if (gpp->gpp_index > 0 && index != gpp->gpp_index) {
499 gctl_error(req, "%d index '%d'", EEXIST, gpp->gpp_index);
500 return (EEXIST);
501 }
502 if (index > table->gpt_entries) {
503 gctl_error(req, "%d index '%d'", ENOSPC, index);
504 return (ENOSPC);
505 }
506
507 entry = (delent == NULL) ? g_malloc(table->gpt_scheme->gps_entrysz,
508 M_WAITOK | M_ZERO) : delent;
509 entry->gpe_index = index;
510 entry->gpe_start = gpp->gpp_start;
511 entry->gpe_end = end;
512 error = G_PART_ADD(table, entry, gpp);
513 if (error) {
514 gctl_error(req, "%d", error);
515 if (delent == NULL)
516 g_free(entry);
517 return (error);
518 }
519 if (delent == NULL) {
520 if (last == NULL)
521 LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry);
522 else
523 LIST_INSERT_AFTER(last, entry, gpe_entry);
524 entry->gpe_created = 1;
525 } else {
526 entry->gpe_deleted = 0;
527 entry->gpe_modified = 1;
528 }
529 g_part_new_provider(gp, table, entry);
530
531 /* Provide feedback if so requested. */
532 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
533 sb = sbuf_new_auto();
534 G_PART_FULLNAME(table, entry, sb, gp->name);
535 sbuf_cat(sb, " added\n");
536 sbuf_finish(sb);
537 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
538 sbuf_delete(sb);
539 }
540 return (0);
541}
542
543static int
544g_part_ctl_bootcode(struct gctl_req *req, struct g_part_parms *gpp)
545{
546 struct g_geom *gp;
547 struct g_part_table *table;
548 struct sbuf *sb;
549 int error, sz;
550
551 gp = gpp->gpp_geom;
552 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
553 g_topology_assert();
554
555 table = gp->softc;
556 sz = table->gpt_scheme->gps_bootcodesz;
557 if (sz == 0) {
558 error = ENODEV;
559 goto fail;
560 }
561 if (gpp->gpp_codesize > sz) {
562 error = EFBIG;
563 goto fail;
564 }
565
566 error = G_PART_BOOTCODE(table, gpp);
567 if (error)
568 goto fail;
569
570 /* Provide feedback if so requested. */
571 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
572 sb = sbuf_new_auto();
573 sbuf_printf(sb, "%s has bootcode\n", gp->name);
574 sbuf_finish(sb);
575 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
576 sbuf_delete(sb);
577 }
578 return (0);
579
580 fail:
581 gctl_error(req, "%d", error);
582 return (error);
583}
584
585static int
586g_part_ctl_commit(struct gctl_req *req, struct g_part_parms *gpp)
587{
588 struct g_consumer *cp;
589 struct g_geom *gp;
590 struct g_provider *pp;
591 struct g_part_entry *entry, *tmp;
592 struct g_part_table *table;
593 char *buf;
594 int error, i;
595
596 gp = gpp->gpp_geom;
597 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
598 g_topology_assert();
599
600 table = gp->softc;
601 if (!table->gpt_opened) {
602 gctl_error(req, "%d", EPERM);
603 return (EPERM);
604 }
605
606 g_topology_unlock();
607
608 cp = LIST_FIRST(&gp->consumer);
609 if ((table->gpt_smhead | table->gpt_smtail) != 0) {
610 pp = cp->provider;
611 buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
612 while (table->gpt_smhead != 0) {
613 i = ffs(table->gpt_smhead) - 1;
614 error = g_write_data(cp, i * pp->sectorsize, buf,
615 pp->sectorsize);
616 if (error) {
617 g_free(buf);
618 goto fail;
619 }
620 table->gpt_smhead &= ~(1 << i);
621 }
622 while (table->gpt_smtail != 0) {
623 i = ffs(table->gpt_smtail) - 1;
624 error = g_write_data(cp, pp->mediasize - (i + 1) *
625 pp->sectorsize, buf, pp->sectorsize);
626 if (error) {
627 g_free(buf);
628 goto fail;
629 }
630 table->gpt_smtail &= ~(1 << i);
631 }
632 g_free(buf);
633 }
634
635 if (table->gpt_scheme == &g_part_null_scheme) {
636 g_topology_lock();
637 g_access(cp, -1, -1, -1);
638 g_part_wither(gp, ENXIO);
639 return (0);
640 }
641
642 error = G_PART_WRITE(table, cp);
643 if (error)
644 goto fail;
645
646 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
647 if (!entry->gpe_deleted) {
648 entry->gpe_created = 0;
649 entry->gpe_modified = 0;
650 continue;
651 }
652 LIST_REMOVE(entry, gpe_entry);
653 g_free(entry);
654 }
655 table->gpt_created = 0;
656 table->gpt_opened = 0;
657
658 g_topology_lock();
659 g_access(cp, -1, -1, -1);
660 return (0);
661
662fail:
663 g_topology_lock();
664 gctl_error(req, "%d", error);
665 return (error);
666}
667
668static int
669g_part_ctl_create(struct gctl_req *req, struct g_part_parms *gpp)
670{
671 struct g_consumer *cp;
672 struct g_geom *gp;
673 struct g_provider *pp;
674 struct g_part_scheme *scheme;
675 struct g_part_table *null, *table;
676 struct sbuf *sb;
677 int attr, error;
678
679 pp = gpp->gpp_provider;
680 scheme = gpp->gpp_scheme;
681 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name));
682 g_topology_assert();
683
684 /* Check that there isn't already a g_part geom on the provider. */
685 error = g_part_parm_geom(pp->name, &gp);
686 if (!error) {
687 null = gp->softc;
688 if (null->gpt_scheme != &g_part_null_scheme) {
689 gctl_error(req, "%d geom '%s'", EEXIST, pp->name);
690 return (EEXIST);
691 }
692 } else
693 null = NULL;
694
695 if ((gpp->gpp_parms & G_PART_PARM_ENTRIES) &&
696 (gpp->gpp_entries < scheme->gps_minent ||
697 gpp->gpp_entries > scheme->gps_maxent)) {
698 gctl_error(req, "%d entries '%d'", EINVAL, gpp->gpp_entries);
699 return (EINVAL);
700 }
701
702 if (null == NULL)
703 gp = g_new_geomf(&g_part_class, "%s", pp->name);
704 gp->softc = kobj_create((kobj_class_t)gpp->gpp_scheme, M_GEOM,
705 M_WAITOK);
706 table = gp->softc;
707 table->gpt_gp = gp;
708 table->gpt_scheme = gpp->gpp_scheme;
709 table->gpt_entries = (gpp->gpp_parms & G_PART_PARM_ENTRIES) ?
710 gpp->gpp_entries : scheme->gps_minent;
711 LIST_INIT(&table->gpt_entry);
712 if (null == NULL) {
713 cp = g_new_consumer(gp);
714 error = g_attach(cp, pp);
715 if (error == 0)
716 error = g_access(cp, 1, 1, 1);
717 if (error != 0) {
718 g_part_wither(gp, error);
719 gctl_error(req, "%d geom '%s'", error, pp->name);
720 return (error);
721 }
722 table->gpt_opened = 1;
723 } else {
724 cp = LIST_FIRST(&gp->consumer);
725 table->gpt_opened = null->gpt_opened;
726 table->gpt_smhead = null->gpt_smhead;
727 table->gpt_smtail = null->gpt_smtail;
728 }
729
730 g_topology_unlock();
731
732 /* Make sure the provider has media. */
733 if (pp->mediasize == 0 || pp->sectorsize == 0) {
734 error = ENODEV;
735 goto fail;
736 }
737
738 /* Make sure we can nest and if so, determine our depth. */
739 error = g_getattr("PART::isleaf", cp, &attr);
740 if (!error && attr) {
741 error = ENODEV;
742 goto fail;
743 }
744 error = g_getattr("PART::depth", cp, &attr);
745 table->gpt_depth = (!error) ? attr + 1 : 0;
746
747 /*
748 * Synthesize a disk geometry. Some partitioning schemes
749 * depend on it and since some file systems need it even
750 * when the partitition scheme doesn't, we do it here in
751 * scheme-independent code.
752 */
753 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
754
755 error = G_PART_CREATE(table, gpp);
756 if (error)
757 goto fail;
758
759 g_topology_lock();
760
761 table->gpt_created = 1;
762 if (null != NULL)
763 kobj_delete((kobj_t)null, M_GEOM);
764
765 /*
766 * Support automatic commit by filling in the gpp_geom
767 * parameter.
768 */
769 gpp->gpp_parms |= G_PART_PARM_GEOM;
770 gpp->gpp_geom = gp;
771
772 /* Provide feedback if so requested. */
773 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
774 sb = sbuf_new_auto();
775 sbuf_printf(sb, "%s created\n", gp->name);
776 sbuf_finish(sb);
777 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
778 sbuf_delete(sb);
779 }
780 return (0);
781
782fail:
783 g_topology_lock();
784 if (null == NULL) {
785 g_access(cp, -1, -1, -1);
786 g_part_wither(gp, error);
787 } else {
788 kobj_delete((kobj_t)gp->softc, M_GEOM);
789 gp->softc = null;
790 }
791 gctl_error(req, "%d provider", error);
792 return (error);
793}
794
795static int
796g_part_ctl_delete(struct gctl_req *req, struct g_part_parms *gpp)
797{
798 struct g_geom *gp;
799 struct g_provider *pp;
800 struct g_part_entry *entry;
801 struct g_part_table *table;
802 struct sbuf *sb;
803
804 gp = gpp->gpp_geom;
805 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
806 g_topology_assert();
807
808 table = gp->softc;
809
810 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
811 if (entry->gpe_deleted || entry->gpe_internal)
812 continue;
813 if (entry->gpe_index == gpp->gpp_index)
814 break;
815 }
816 if (entry == NULL) {
817 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
818 return (ENOENT);
819 }
820
821 pp = entry->gpe_pp;
822 if (pp != NULL) {
823 if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) {
824 gctl_error(req, "%d", EBUSY);
825 return (EBUSY);
826 }
827
828 pp->private = NULL;
829 entry->gpe_pp = NULL;
830 }
831
832 if (entry->gpe_created) {
833 LIST_REMOVE(entry, gpe_entry);
834 g_free(entry);
835 } else {
836 entry->gpe_modified = 0;
837 entry->gpe_deleted = 1;
838 }
839
840 if (pp != NULL)
841 g_wither_provider(pp, ENXIO);
842
843 /* Provide feedback if so requested. */
844 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
845 sb = sbuf_new_auto();
846 G_PART_FULLNAME(table, entry, sb, gp->name);
847 sbuf_cat(sb, " deleted\n");
848 sbuf_finish(sb);
849 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
850 sbuf_delete(sb);
851 }
852 return (0);
853}
854
855static int
856g_part_ctl_destroy(struct gctl_req *req, struct g_part_parms *gpp)
857{
858 struct g_geom *gp;
859 struct g_part_entry *entry;
860 struct g_part_table *null, *table;
861 struct sbuf *sb;
862 int error;
863
864 gp = gpp->gpp_geom;
865 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
866 g_topology_assert();
867
868 table = gp->softc;
869 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
870 if (entry->gpe_deleted || entry->gpe_internal)
871 continue;
872 gctl_error(req, "%d", EBUSY);
873 return (EBUSY);
874 }
875
876 error = G_PART_DESTROY(table, gpp);
877 if (error) {
878 gctl_error(req, "%d", error);
879 return (error);
880 }
881
882 gp->softc = kobj_create((kobj_class_t)&g_part_null_scheme, M_GEOM,
883 M_WAITOK);
884 null = gp->softc;
885 null->gpt_gp = gp;
886 null->gpt_scheme = &g_part_null_scheme;
887 LIST_INIT(&null->gpt_entry);
888 null->gpt_depth = table->gpt_depth;
889 null->gpt_opened = table->gpt_opened;
890 null->gpt_smhead = table->gpt_smhead;
891 null->gpt_smtail = table->gpt_smtail;
892
893 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
894 LIST_REMOVE(entry, gpe_entry);
895 g_free(entry);
896 }
897 kobj_delete((kobj_t)table, M_GEOM);
898
899 /* Provide feedback if so requested. */
900 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
901 sb = sbuf_new_auto();
902 sbuf_printf(sb, "%s destroyed\n", gp->name);
903 sbuf_finish(sb);
904 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
905 sbuf_delete(sb);
906 }
907 return (0);
908}
909
910static int
911g_part_ctl_modify(struct gctl_req *req, struct g_part_parms *gpp)
912{
913 struct g_geom *gp;
914 struct g_part_entry *entry;
915 struct g_part_table *table;
916 struct sbuf *sb;
917 int error;
918
919 gp = gpp->gpp_geom;
920 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
921 g_topology_assert();
922
923 table = gp->softc;
924
925 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
926 if (entry->gpe_deleted || entry->gpe_internal)
927 continue;
928 if (entry->gpe_index == gpp->gpp_index)
929 break;
930 }
931 if (entry == NULL) {
932 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
933 return (ENOENT);
934 }
935
936 error = G_PART_MODIFY(table, entry, gpp);
937 if (error) {
938 gctl_error(req, "%d", error);
939 return (error);
940 }
941
942 if (!entry->gpe_created)
943 entry->gpe_modified = 1;
944
945 /* Provide feedback if so requested. */
946 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
947 sb = sbuf_new_auto();
948 G_PART_FULLNAME(table, entry, sb, gp->name);
949 sbuf_cat(sb, " modified\n");
950 sbuf_finish(sb);
951 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
952 sbuf_delete(sb);
953 }
954 return (0);
955}
956
957static int
958g_part_ctl_move(struct gctl_req *req, struct g_part_parms *gpp)
959{
960 gctl_error(req, "%d verb 'move'", ENOSYS);
961 return (ENOSYS);
962}
963
964static int
965g_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp)
966{
967 gctl_error(req, "%d verb 'recover'", ENOSYS);
968 return (ENOSYS);
969}
970
971static int
972g_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp)
973{
974 gctl_error(req, "%d verb 'resize'", ENOSYS);
975 return (ENOSYS);
976}
977
978static int
979g_part_ctl_setunset(struct gctl_req *req, struct g_part_parms *gpp,
980 unsigned int set)
981{
982 struct g_geom *gp;
983 struct g_part_entry *entry;
984 struct g_part_table *table;
985 struct sbuf *sb;
986 int error;
987
988 gp = gpp->gpp_geom;
989 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
990 g_topology_assert();
991
992 table = gp->softc;
993
994 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
995 if (entry->gpe_deleted || entry->gpe_internal)
996 continue;
997 if (entry->gpe_index == gpp->gpp_index)
998 break;
999 }
1000 if (entry == NULL) {
1001 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
1002 return (ENOENT);
1003 }
1004
1005 error = G_PART_SETUNSET(table, entry, gpp->gpp_attrib, set);
1006 if (error) {
1007 gctl_error(req, "%d attrib '%s'", error, gpp->gpp_attrib);
1008 return (error);
1009 }
1010
1011 /* Provide feedback if so requested. */
1012 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1013 sb = sbuf_new_auto();
1014 G_PART_FULLNAME(table, entry, sb, gp->name);
1015 sbuf_printf(sb, " has %s %sset\n", gpp->gpp_attrib,
1016 (set) ? "" : "un");
1017 sbuf_finish(sb);
1018 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1019 sbuf_delete(sb);
1020 }
1021 return (0);
1022}
1023
1024static int
1025g_part_ctl_undo(struct gctl_req *req, struct g_part_parms *gpp)
1026{
1027 struct g_consumer *cp;
1028 struct g_provider *pp;
1029 struct g_geom *gp;
1030 struct g_part_entry *entry, *tmp;
1031 struct g_part_table *table;
1032 int error, reprobe;
1033
1034 gp = gpp->gpp_geom;
1035 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1036 g_topology_assert();
1037
1038 table = gp->softc;
1039 if (!table->gpt_opened) {
1040 gctl_error(req, "%d", EPERM);
1041 return (EPERM);
1042 }
1043
1044 cp = LIST_FIRST(&gp->consumer);
1045 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
1046 entry->gpe_modified = 0;
1047 if (entry->gpe_created) {
1048 pp = entry->gpe_pp;
1049 if (pp != NULL) {
1050 pp->private = NULL;
1051 entry->gpe_pp = NULL;
1052 g_wither_provider(pp, ENXIO);
1053 }
1054 entry->gpe_deleted = 1;
1055 }
1056 if (entry->gpe_deleted) {
1057 LIST_REMOVE(entry, gpe_entry);
1058 g_free(entry);
1059 }
1060 }
1061
1062 g_topology_unlock();
1063
1064 reprobe = (table->gpt_scheme == &g_part_null_scheme ||
1065 table->gpt_created) ? 1 : 0;
1066
1067 if (reprobe) {
1068 if (!LIST_EMPTY(&table->gpt_entry)) {
1069 error = EBUSY;
1070 goto fail;
1071 }
1072 error = g_part_probe(gp, cp, table->gpt_depth);
1073 if (error) {
1074 g_topology_lock();
1075 g_access(cp, -1, -1, -1);
1076 g_part_wither(gp, error);
1077 return (0);
1078 }
1079 table = gp->softc;
1080 }
1081
1082 error = G_PART_READ(table, cp);
1083 if (error)
1084 goto fail;
1085
1086 g_topology_lock();
1087
1088 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1089 if (!entry->gpe_internal)
1090 g_part_new_provider(gp, table, entry);
1091 }
1092
1093 table->gpt_opened = 0;
1094 g_access(cp, -1, -1, -1);
1095 return (0);
1096
1097fail:
1098 g_topology_lock();
1099 gctl_error(req, "%d", error);
1100 return (error);
1101}
1102
1103static void
1104g_part_wither(struct g_geom *gp, int error)
1105{
1106 struct g_part_entry *entry;
1107 struct g_part_table *table;
1108
1109 table = gp->softc;
1110 if (table != NULL) {
1111 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
1112 LIST_REMOVE(entry, gpe_entry);
1113 g_free(entry);
1114 }
1115 if (gp->softc != NULL) {
1116 kobj_delete((kobj_t)gp->softc, M_GEOM);
1117 gp->softc = NULL;
1118 }
1119 }
1120 g_wither_geom(gp, error);
1121}
1122
1123/*
1124 * Class methods.
1125 */
1126
1127static void
1128g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb)
1129{
1130 struct g_part_parms gpp;
1131 struct g_part_table *table;
1132 struct gctl_req_arg *ap;
1133 const char *p;
1134 enum g_part_ctl ctlreq;
1135 unsigned int i, mparms, oparms, parm;
1136 int auto_commit, close_on_error;
1137 int error, len, modifies;
1138
1139 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb));
1140 g_topology_assert();
1141
1142 ctlreq = G_PART_CTL_NONE;
1143 modifies = 1;
1144 mparms = 0;
1145 oparms = G_PART_PARM_FLAGS | G_PART_PARM_OUTPUT | G_PART_PARM_VERSION;
1146 switch (*verb) {
1147 case 'a':
1148 if (!strcmp(verb, "add")) {
1149 ctlreq = G_PART_CTL_ADD;
1150 mparms |= G_PART_PARM_GEOM | G_PART_PARM_SIZE |
1151 G_PART_PARM_START | G_PART_PARM_TYPE;
1152 oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL;
1153 }
1154 break;
1155 case 'b':
1156 if (!strcmp(verb, "bootcode")) {
1157 ctlreq = G_PART_CTL_BOOTCODE;
1158 mparms |= G_PART_PARM_GEOM | G_PART_PARM_BOOTCODE;
1159 }
1160 break;
1161 case 'c':
1162 if (!strcmp(verb, "commit")) {
1163 ctlreq = G_PART_CTL_COMMIT;
1164 mparms |= G_PART_PARM_GEOM;
1165 modifies = 0;
1166 } else if (!strcmp(verb, "create")) {
1167 ctlreq = G_PART_CTL_CREATE;
1168 mparms |= G_PART_PARM_PROVIDER | G_PART_PARM_SCHEME;
1169 oparms |= G_PART_PARM_ENTRIES;
1170 }
1171 break;
1172 case 'd':
1173 if (!strcmp(verb, "delete")) {
1174 ctlreq = G_PART_CTL_DELETE;
1175 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1176 } else if (!strcmp(verb, "destroy")) {
1177 ctlreq = G_PART_CTL_DESTROY;
1178 mparms |= G_PART_PARM_GEOM;
1179 }
1180 break;
1181 case 'm':
1182 if (!strcmp(verb, "modify")) {
1183 ctlreq = G_PART_CTL_MODIFY;
1184 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1185 oparms |= G_PART_PARM_LABEL | G_PART_PARM_TYPE;
1186 } else if (!strcmp(verb, "move")) {
1187 ctlreq = G_PART_CTL_MOVE;
1188 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1189 }
1190 break;
1191 case 'r':
1192 if (!strcmp(verb, "recover")) {
1193 ctlreq = G_PART_CTL_RECOVER;
1194 mparms |= G_PART_PARM_GEOM;
1195 } else if (!strcmp(verb, "resize")) {
1196 ctlreq = G_PART_CTL_RESIZE;
1197 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1198 }
1199 break;
1200 case 's':
1201 if (!strcmp(verb, "set")) {
1202 ctlreq = G_PART_CTL_SET;
1203 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM |
1204 G_PART_PARM_INDEX;
1205 }
1206 break;
1207 case 'u':
1208 if (!strcmp(verb, "undo")) {
1209 ctlreq = G_PART_CTL_UNDO;
1210 mparms |= G_PART_PARM_GEOM;
1211 modifies = 0;
1212 } else if (!strcmp(verb, "unset")) {
1213 ctlreq = G_PART_CTL_UNSET;
1214 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM |
1215 G_PART_PARM_INDEX;
1216 }
1217 break;
1218 }
1219 if (ctlreq == G_PART_CTL_NONE) {
1220 gctl_error(req, "%d verb '%s'", EINVAL, verb);
1221 return;
1222 }
1223
1224 bzero(&gpp, sizeof(gpp));
1225 for (i = 0; i < req->narg; i++) {
1226 ap = &req->arg[i];
1227 parm = 0;
1228 switch (ap->name[0]) {
1229 case 'a':
1230 if (!strcmp(ap->name, "attrib"))
1231 parm = G_PART_PARM_ATTRIB;
1232 break;
1233 case 'b':
1234 if (!strcmp(ap->name, "bootcode"))
1235 parm = G_PART_PARM_BOOTCODE;
1236 break;
1237 case 'c':
1238 if (!strcmp(ap->name, "class"))
1239 continue;
1240 break;
1241 case 'e':
1242 if (!strcmp(ap->name, "entries"))
1243 parm = G_PART_PARM_ENTRIES;
1244 break;
1245 case 'f':
1246 if (!strcmp(ap->name, "flags"))
1247 parm = G_PART_PARM_FLAGS;
1248 break;
1249 case 'g':
1250 if (!strcmp(ap->name, "geom"))
1251 parm = G_PART_PARM_GEOM;
1252 break;
1253 case 'i':
1254 if (!strcmp(ap->name, "index"))
1255 parm = G_PART_PARM_INDEX;
1256 break;
1257 case 'l':
1258 if (!strcmp(ap->name, "label"))
1259 parm = G_PART_PARM_LABEL;
1260 break;
1261 case 'o':
1262 if (!strcmp(ap->name, "output"))
1263 parm = G_PART_PARM_OUTPUT;
1264 break;
1265 case 'p':
1266 if (!strcmp(ap->name, "provider"))
1267 parm = G_PART_PARM_PROVIDER;
1268 break;
1269 case 's':
1270 if (!strcmp(ap->name, "scheme"))
1271 parm = G_PART_PARM_SCHEME;
1272 else if (!strcmp(ap->name, "size"))
1273 parm = G_PART_PARM_SIZE;
1274 else if (!strcmp(ap->name, "start"))
1275 parm = G_PART_PARM_START;
1276 break;
1277 case 't':
1278 if (!strcmp(ap->name, "type"))
1279 parm = G_PART_PARM_TYPE;
1280 break;
1281 case 'v':
1282 if (!strcmp(ap->name, "verb"))
1283 continue;
1284 else if (!strcmp(ap->name, "version"))
1285 parm = G_PART_PARM_VERSION;
1286 break;
1287 }
1288 if ((parm & (mparms | oparms)) == 0) {
1289 gctl_error(req, "%d param '%s'", EINVAL, ap->name);
1290 return;
1291 }
1292 if (parm == G_PART_PARM_BOOTCODE)
1293 p = gctl_get_param(req, ap->name, &len);
1294 else
1295 p = gctl_get_asciiparam(req, ap->name);
1296 if (p == NULL) {
1297 gctl_error(req, "%d param '%s'", ENOATTR, ap->name);
1298 return;
1299 }
1300 switch (parm) {
1301 case G_PART_PARM_ATTRIB:
1302 error = g_part_parm_str(p, &gpp.gpp_attrib);
1303 break;
1304 case G_PART_PARM_BOOTCODE:
1305 gpp.gpp_codeptr = p;
1306 gpp.gpp_codesize = len;
1307 error = 0;
1308 break;
1309 case G_PART_PARM_ENTRIES:
1310 error = g_part_parm_uint(p, &gpp.gpp_entries);
1311 break;
1312 case G_PART_PARM_FLAGS:
1313 if (p[0] == '\0')
1314 continue;
1315 error = g_part_parm_str(p, &gpp.gpp_flags);
1316 break;
1317 case G_PART_PARM_GEOM:
1318 error = g_part_parm_geom(p, &gpp.gpp_geom);
1319 break;
1320 case G_PART_PARM_INDEX:
1321 error = g_part_parm_uint(p, &gpp.gpp_index);
1322 break;
1323 case G_PART_PARM_LABEL:
1324 /* An empty label is always valid. */
1325 gpp.gpp_label = p;
1326 error = 0;
1327 break;
1328 case G_PART_PARM_OUTPUT:
1329 error = 0; /* Write-only parameter */
1330 break;
1331 case G_PART_PARM_PROVIDER:
1332 error = g_part_parm_provider(p, &gpp.gpp_provider);
1333 break;
1334 case G_PART_PARM_SCHEME:
1335 error = g_part_parm_scheme(p, &gpp.gpp_scheme);
1336 break;
1337 case G_PART_PARM_SIZE:
1338 error = g_part_parm_quad(p, &gpp.gpp_size);
1339 break;
1340 case G_PART_PARM_START:
1341 error = g_part_parm_quad(p, &gpp.gpp_start);
1342 break;
1343 case G_PART_PARM_TYPE:
1344 error = g_part_parm_str(p, &gpp.gpp_type);
1345 break;
1346 case G_PART_PARM_VERSION:
1347 error = g_part_parm_uint(p, &gpp.gpp_version);
1348 break;
1349 default:
1350 error = EDOOFUS;
1351 break;
1352 }
1353 if (error) {
1354 gctl_error(req, "%d %s '%s'", error, ap->name, p);
1355 return;
1356 }
1357 gpp.gpp_parms |= parm;
1358 }
1359 if ((gpp.gpp_parms & mparms) != mparms) {
1360 parm = mparms - (gpp.gpp_parms & mparms);
1361 gctl_error(req, "%d param '%x'", ENOATTR, parm);
1362 return;
1363 }
1364
1365 /* Obtain permissions if possible/necessary. */
1366 close_on_error = 0;
1367 table = NULL;
1368 if (modifies && (gpp.gpp_parms & G_PART_PARM_GEOM)) {
1369 table = gpp.gpp_geom->softc;
1370 if (table != NULL && !table->gpt_opened) {
1371 error = g_access(LIST_FIRST(&gpp.gpp_geom->consumer),
1372 1, 1, 1);
1373 if (error) {
1374 gctl_error(req, "%d geom '%s'", error,
1375 gpp.gpp_geom->name);
1376 return;
1377 }
1378 table->gpt_opened = 1;
1379 close_on_error = 1;
1380 }
1381 }
1382
1383 /* Allow the scheme to check or modify the parameters. */
1384 if (table != NULL) {
1385 error = G_PART_PRECHECK(table, ctlreq, &gpp);
1386 if (error) {
1387 gctl_error(req, "%d pre-check failed", error);
1388 goto out;
1389 }
1390 } else
1391 error = EDOOFUS; /* Prevent bogus uninit. warning. */
1392
1393 switch (ctlreq) {
1394 case G_PART_CTL_NONE:
1395 panic("%s", __func__);
1396 case G_PART_CTL_ADD:
1397 error = g_part_ctl_add(req, &gpp);
1398 break;
1399 case G_PART_CTL_BOOTCODE:
1400 error = g_part_ctl_bootcode(req, &gpp);
1401 break;
1402 case G_PART_CTL_COMMIT:
1403 error = g_part_ctl_commit(req, &gpp);
1404 break;
1405 case G_PART_CTL_CREATE:
1406 error = g_part_ctl_create(req, &gpp);
1407 break;
1408 case G_PART_CTL_DELETE:
1409 error = g_part_ctl_delete(req, &gpp);
1410 break;
1411 case G_PART_CTL_DESTROY:
1412 error = g_part_ctl_destroy(req, &gpp);
1413 break;
1414 case G_PART_CTL_MODIFY:
1415 error = g_part_ctl_modify(req, &gpp);
1416 break;
1417 case G_PART_CTL_MOVE:
1418 error = g_part_ctl_move(req, &gpp);
1419 break;
1420 case G_PART_CTL_RECOVER:
1421 error = g_part_ctl_recover(req, &gpp);
1422 break;
1423 case G_PART_CTL_RESIZE:
1424 error = g_part_ctl_resize(req, &gpp);
1425 break;
1426 case G_PART_CTL_SET:
1427 error = g_part_ctl_setunset(req, &gpp, 1);
1428 break;
1429 case G_PART_CTL_UNDO:
1430 error = g_part_ctl_undo(req, &gpp);
1431 break;
1432 case G_PART_CTL_UNSET:
1433 error = g_part_ctl_setunset(req, &gpp, 0);
1434 break;
1435 }
1436
1437 /* Implement automatic commit. */
1438 if (!error) {
1439 auto_commit = (modifies &&
1440 (gpp.gpp_parms & G_PART_PARM_FLAGS) &&
1441 strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0;
1442 if (auto_commit) {
1443 KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, (__func__));
1444 error = g_part_ctl_commit(req, &gpp);
1445 }
1446 }
1447
1448 out:
1449 if (error && close_on_error) {
1450 g_access(LIST_FIRST(&gpp.gpp_geom->consumer), -1, -1, -1);
1451 table->gpt_opened = 0;
1452 }
1453}
1454
1455static int
1456g_part_destroy_geom(struct gctl_req *req, struct g_class *mp,
1457 struct g_geom *gp)
1458{
1459
1460 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name));
1461 g_topology_assert();
1462
1463 g_part_wither(gp, EINVAL);
1464 return (0);
1465}
1466
1467static struct g_geom *
1468g_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
1469{
1470 struct g_consumer *cp;
1471 struct g_geom *gp;
1472 struct g_part_entry *entry;
1473 struct g_part_table *table;
1474 struct root_hold_token *rht;
1475 int attr, depth;
1476 int error;
1477
1478 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name));
1479 g_topology_assert();
1480
1481 /* Skip providers that are already open for writing. */
1482 if (pp->acw > 0)
1483 return (NULL);
1484
1485 /*
1486 * Create a GEOM with consumer and hook it up to the provider.
1487 * With that we become part of the topology. Optain read access
1488 * to the provider.
1489 */
1490 gp = g_new_geomf(mp, "%s", pp->name);
1491 cp = g_new_consumer(gp);
1492 error = g_attach(cp, pp);
1493 if (error == 0)
1494 error = g_access(cp, 1, 0, 0);
1495 if (error != 0) {
1496 g_part_wither(gp, error);
1497 return (NULL);
1498 }
1499
1500 rht = root_mount_hold(mp->name);
1501 g_topology_unlock();
1502
1503 /*
1504 * Short-circuit the whole probing galore when there's no
1505 * media present.
1506 */
1507 if (pp->mediasize == 0 || pp->sectorsize == 0) {
1508 error = ENODEV;
1509 goto fail;
1510 }
1511
1512 /* Make sure we can nest and if so, determine our depth. */
1513 error = g_getattr("PART::isleaf", cp, &attr);
1514 if (!error && attr) {
1515 error = ENODEV;
1516 goto fail;
1517 }
1518 error = g_getattr("PART::depth", cp, &attr);
1519 depth = (!error) ? attr + 1 : 0;
1520
1521 error = g_part_probe(gp, cp, depth);
1522 if (error)
1523 goto fail;
1524
1525 table = gp->softc;
1526
1527 /*
1528 * Synthesize a disk geometry. Some partitioning schemes
1529 * depend on it and since some file systems need it even
1530 * when the partitition scheme doesn't, we do it here in
1531 * scheme-independent code.
1532 */
1533 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
1534
1535 error = G_PART_READ(table, cp);
1536 if (error)
1537 goto fail;
1538
1539 g_topology_lock();
1540 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1541 if (!entry->gpe_internal)
1542 g_part_new_provider(gp, table, entry);
1543 }
1544
1545 root_mount_rel(rht);
1546 g_access(cp, -1, 0, 0);
1547 return (gp);
1548
1549 fail:
1550 g_topology_lock();
1551 root_mount_rel(rht);
1552 g_access(cp, -1, 0, 0);
1553 g_part_wither(gp, error);
1554 return (NULL);
1555}
1556
1557/*
1558 * Geom methods.
1559 */
1560
1561static int
1562g_part_access(struct g_provider *pp, int dr, int dw, int de)
1563{
1564 struct g_consumer *cp;
1565
1566 G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr,
1567 dw, de));
1568
1569 cp = LIST_FIRST(&pp->geom->consumer);
1570
1571 /* We always gain write-exclusive access. */
1572 return (g_access(cp, dr, dw, dw + de));
1573}
1574
1575static void
1576g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
1577 struct g_consumer *cp, struct g_provider *pp)
1578{
1579 char buf[64];
1580 struct g_part_entry *entry;
1581 struct g_part_table *table;
1582
1583 KASSERT(sb != NULL && gp != NULL, (__func__));
1584 table = gp->softc;
1585
1586 if (indent == NULL) {
1587 KASSERT(cp == NULL && pp != NULL, (__func__));
1588 entry = pp->private;
1589 if (entry == NULL)
1590 return;
1591 sbuf_printf(sb, " i %u o %ju ty %s", entry->gpe_index,
1592 (uintmax_t)entry->gpe_offset,
1593 G_PART_TYPE(table, entry, buf, sizeof(buf)));
1594 /*
1595 * libdisk compatibility quirk - the scheme dumps the
1596 * slicer name and partition type in a way that is
1597 * compatible with libdisk. When libdisk is not used
1598 * anymore, this should go away.
1599 */
1600 G_PART_DUMPCONF(table, entry, sb, indent);
1601 } else if (cp != NULL) { /* Consumer configuration. */
1602 KASSERT(pp == NULL, (__func__));
1603 /* none */
1604 } else if (pp != NULL) { /* Provider configuration. */
1605 entry = pp->private;
1606 if (entry == NULL)
1607 return;
1608 sbuf_printf(sb, "%s<start>%ju</start>\n", indent,
1609 (uintmax_t)entry->gpe_start);
1610 sbuf_printf(sb, "%s<end>%ju</end>\n", indent,
1611 (uintmax_t)entry->gpe_end);
1612 sbuf_printf(sb, "%s<index>%u</index>\n", indent,
1613 entry->gpe_index);
1614 sbuf_printf(sb, "%s<type>%s</type>\n", indent,
1615 G_PART_TYPE(table, entry, buf, sizeof(buf)));
1616 sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent,
1617 (uintmax_t)entry->gpe_offset);
1618 sbuf_printf(sb, "%s<length>%ju</length>\n", indent,
1619 (uintmax_t)pp->mediasize);
1620 G_PART_DUMPCONF(table, entry, sb, indent);
1621 } else { /* Geom configuration. */
1622 sbuf_printf(sb, "%s<scheme>%s</scheme>\n", indent,
1623 table->gpt_scheme->name);
1624 sbuf_printf(sb, "%s<entries>%u</entries>\n", indent,
1625 table->gpt_entries);
1626 sbuf_printf(sb, "%s<first>%ju</first>\n", indent,
1627 (uintmax_t)table->gpt_first);
1628 sbuf_printf(sb, "%s<last>%ju</last>\n", indent,
1629 (uintmax_t)table->gpt_last);
1630 sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n", indent,
1631 table->gpt_sectors);
1632 sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n", indent,
1633 table->gpt_heads);
1634 G_PART_DUMPCONF(table, NULL, sb, indent);
1635 }
1636}
1637
1638static void
1639g_part_orphan(struct g_consumer *cp)
1640{
1641 struct g_provider *pp;
1642
1643 pp = cp->provider;
1644 KASSERT(pp != NULL, (__func__));
1645 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name));
1646 g_topology_assert();
1647
1648 KASSERT(pp->error != 0, (__func__));
1649 g_part_wither(cp->geom, pp->error);
1650}
1651
1652static void
1653g_part_spoiled(struct g_consumer *cp)
1654{
1655
1656 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name));
1657 g_topology_assert();
1658
1659 g_part_wither(cp->geom, ENXIO);
1660}
1661
1662static void
1663g_part_start(struct bio *bp)
1664{
1665 struct bio *bp2;
1666 struct g_consumer *cp;
1667 struct g_geom *gp;
1668 struct g_part_entry *entry;
1669 struct g_part_table *table;
1670 struct g_kerneldump *gkd;
1671 struct g_provider *pp;
1672
1673 pp = bp->bio_to;
1674 gp = pp->geom;
1675 table = gp->softc;
1676 cp = LIST_FIRST(&gp->consumer);
1677
1678 G_PART_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd,
1679 pp->name));
1680
1681 entry = pp->private;
1682 if (entry == NULL) {
1683 g_io_deliver(bp, ENXIO);
1684 return;
1685 }
1686
1687 switch(bp->bio_cmd) {
1688 case BIO_DELETE:
1689 case BIO_READ:
1690 case BIO_WRITE:
1691 if (bp->bio_offset >= pp->mediasize) {
1692 g_io_deliver(bp, EIO);
1693 return;
1694 }
1695 bp2 = g_clone_bio(bp);
1696 if (bp2 == NULL) {
1697 g_io_deliver(bp, ENOMEM);
1698 return;
1699 }
1700 if (bp2->bio_offset + bp2->bio_length > pp->mediasize)
1701 bp2->bio_length = pp->mediasize - bp2->bio_offset;
1702 bp2->bio_done = g_std_done;
1703 bp2->bio_offset += entry->gpe_offset;
1704 g_io_request(bp2, cp);
1705 return;
1706 case BIO_FLUSH:
1707 break;
1708 case BIO_GETATTR:
1709 if (g_handleattr_int(bp, "GEOM::fwheads", table->gpt_heads))
1710 return;
1711 if (g_handleattr_int(bp, "GEOM::fwsectors", table->gpt_sectors))
1712 return;
1713 if (g_handleattr_int(bp, "PART::isleaf", table->gpt_isleaf))
1714 return;
1715 if (g_handleattr_int(bp, "PART::depth", table->gpt_depth))
1716 return;
1717 if (g_handleattr_str(bp, "PART::scheme",
1718 table->gpt_scheme->name))
1719 return;
1720 if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) {
1721 /*
1722 * Check that the partition is suitable for kernel
1723 * dumps. Typically only swap partitions should be
1724 * used.
1725 */
1726 if (!G_PART_DUMPTO(table, entry)) {
1727 g_io_deliver(bp, ENODEV);
1728 printf("GEOM_PART: Partition '%s' not suitable"
1729 " for kernel dumps (wrong type?)\n",
1730 pp->name);
1731 return;
1732 }
1733 gkd = (struct g_kerneldump *)bp->bio_data;
1734 if (gkd->offset >= pp->mediasize) {
1735 g_io_deliver(bp, EIO);
1736 return;
1737 }
1738 if (gkd->offset + gkd->length > pp->mediasize)
1739 gkd->length = pp->mediasize - gkd->offset;
1740 gkd->offset += entry->gpe_offset;
1741 }
1742 break;
1743 default:
1744 g_io_deliver(bp, EOPNOTSUPP);
1745 return;
1746 }
1747
1748 bp2 = g_clone_bio(bp);
1749 if (bp2 == NULL) {
1750 g_io_deliver(bp, ENOMEM);
1751 return;
1752 }
1753 bp2->bio_done = g_std_done;
1754 g_io_request(bp2, cp);
1755}
1756
1757static void
1758g_part_init(struct g_class *mp)
1759{
1760
1761 TAILQ_INSERT_HEAD(&g_part_schemes, &g_part_null_scheme, scheme_list);
1762}
1763
1764static void
1765g_part_fini(struct g_class *mp)
1766{
1767
1768 TAILQ_REMOVE(&g_part_schemes, &g_part_null_scheme, scheme_list);
1769}
1770
1771static void
1772g_part_unload_event(void *arg, int flag)
1773{
1774 struct g_consumer *cp;
1775 struct g_geom *gp;
1776 struct g_provider *pp;
1777 struct g_part_scheme *scheme;
1778 struct g_part_table *table;
1779 uintptr_t *xchg;
1780 int acc, error;
1781
1782 if (flag == EV_CANCEL)
1783 return;
1784
1785 xchg = arg;
1786 error = 0;
1787 scheme = (void *)(*xchg);
1788
1789 g_topology_assert();
1790
1791 LIST_FOREACH(gp, &g_part_class.geom, geom) {
1792 table = gp->softc;
1793 if (table->gpt_scheme != scheme)
1794 continue;
1795
1796 acc = 0;
1797 LIST_FOREACH(pp, &gp->provider, provider)
1798 acc += pp->acr + pp->acw + pp->ace;
1799 LIST_FOREACH(cp, &gp->consumer, consumer)
1800 acc += cp->acr + cp->acw + cp->ace;
1801
1802 if (!acc)
1803 g_part_wither(gp, ENOSYS);
1804 else
1805 error = EBUSY;
1806 }
1807
1808 if (!error)
1809 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list);
1810
1811 *xchg = error;
1812}
1813
1814int
1815g_part_modevent(module_t mod, int type, struct g_part_scheme *scheme)
1816{
1817 uintptr_t arg;
1818 int error;
1819
1820 switch (type) {
1821 case MOD_LOAD:
1822 TAILQ_INSERT_TAIL(&g_part_schemes, scheme, scheme_list);
1823
1824 error = g_retaste(&g_part_class);
1825 if (error)
1826 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list);
1827 break;
1828 case MOD_UNLOAD:
1829 arg = (uintptr_t)scheme;
1830 error = g_waitfor_event(g_part_unload_event, &arg, M_WAITOK,
1831 NULL);
1832 if (!error)
1833 error = (arg == (uintptr_t)scheme) ? EDOOFUS : arg;
1834 break;
1835 default:
1836 error = EOPNOTSUPP;
1837 break;
1838 }
1839
1840 return (error);
1841}