FreeBSD/Linux Kernel Cross Reference
sys/geom/part/g_part.c
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2002, 2005-2009 Marcel Moolenaar
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/bio.h>
34 #include <sys/endian.h>
35 #include <sys/kernel.h>
36 #include <sys/kobj.h>
37 #include <sys/limits.h>
38 #include <sys/lock.h>
39 #include <sys/malloc.h>
40 #include <sys/mutex.h>
41 #include <sys/queue.h>
42 #include <sys/sbuf.h>
43 #include <sys/sysctl.h>
44 #include <sys/systm.h>
45 #include <sys/uuid.h>
46 #include <geom/geom.h>
47 #include <geom/geom_ctl.h>
48 #include <geom/geom_int.h>
49 #include <geom/part/g_part.h>
50
51 #include "g_part_if.h"
52
53 static kobj_method_t g_part_null_methods[] = {
54 { 0, 0 }
55 };
56
57 static struct g_part_scheme g_part_null_scheme = {
58 "(none)",
59 g_part_null_methods,
60 sizeof(struct g_part_table),
61 };
62
63 TAILQ_HEAD(, g_part_scheme) g_part_schemes =
64 TAILQ_HEAD_INITIALIZER(g_part_schemes);
65
66 struct g_part_alias_list {
67 const char *lexeme;
68 enum g_part_alias alias;
69 } g_part_alias_list[G_PART_ALIAS_COUNT] = {
70 { "apple-apfs", G_PART_ALIAS_APPLE_APFS },
71 { "apple-boot", G_PART_ALIAS_APPLE_BOOT },
72 { "apple-core-storage", G_PART_ALIAS_APPLE_CORE_STORAGE },
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 { "apple-zfs", G_PART_ALIAS_APPLE_ZFS },
80 { "bios-boot", G_PART_ALIAS_BIOS_BOOT },
81 { "chromeos-firmware", G_PART_ALIAS_CHROMEOS_FIRMWARE },
82 { "chromeos-kernel", G_PART_ALIAS_CHROMEOS_KERNEL },
83 { "chromeos-reserved", G_PART_ALIAS_CHROMEOS_RESERVED },
84 { "chromeos-root", G_PART_ALIAS_CHROMEOS_ROOT },
85 { "dragonfly-ccd", G_PART_ALIAS_DFBSD_CCD },
86 { "dragonfly-hammer", G_PART_ALIAS_DFBSD_HAMMER },
87 { "dragonfly-hammer2", G_PART_ALIAS_DFBSD_HAMMER2 },
88 { "dragonfly-label32", G_PART_ALIAS_DFBSD },
89 { "dragonfly-label64", G_PART_ALIAS_DFBSD64 },
90 { "dragonfly-legacy", G_PART_ALIAS_DFBSD_LEGACY },
91 { "dragonfly-swap", G_PART_ALIAS_DFBSD_SWAP },
92 { "dragonfly-ufs", G_PART_ALIAS_DFBSD_UFS },
93 { "dragonfly-vinum", G_PART_ALIAS_DFBSD_VINUM },
94 { "ebr", G_PART_ALIAS_EBR },
95 { "efi", G_PART_ALIAS_EFI },
96 { "fat16", G_PART_ALIAS_MS_FAT16 },
97 { "fat32", G_PART_ALIAS_MS_FAT32 },
98 { "fat32lba", G_PART_ALIAS_MS_FAT32LBA },
99 { "freebsd", G_PART_ALIAS_FREEBSD },
100 { "freebsd-boot", G_PART_ALIAS_FREEBSD_BOOT },
101 { "freebsd-nandfs", G_PART_ALIAS_FREEBSD_NANDFS },
102 { "freebsd-swap", G_PART_ALIAS_FREEBSD_SWAP },
103 { "freebsd-ufs", G_PART_ALIAS_FREEBSD_UFS },
104 { "freebsd-vinum", G_PART_ALIAS_FREEBSD_VINUM },
105 { "freebsd-zfs", G_PART_ALIAS_FREEBSD_ZFS },
106 { "hifive-fsbl", G_PART_ALIAS_HIFIVE_FSBL },
107 { "hifive-bbl", G_PART_ALIAS_HIFIVE_BBL },
108 { "linux-data", G_PART_ALIAS_LINUX_DATA },
109 { "linux-lvm", G_PART_ALIAS_LINUX_LVM },
110 { "linux-raid", G_PART_ALIAS_LINUX_RAID },
111 { "linux-swap", G_PART_ALIAS_LINUX_SWAP },
112 { "mbr", G_PART_ALIAS_MBR },
113 { "ms-basic-data", G_PART_ALIAS_MS_BASIC_DATA },
114 { "ms-ldm-data", G_PART_ALIAS_MS_LDM_DATA },
115 { "ms-ldm-metadata", G_PART_ALIAS_MS_LDM_METADATA },
116 { "ms-recovery", G_PART_ALIAS_MS_RECOVERY },
117 { "ms-reserved", G_PART_ALIAS_MS_RESERVED },
118 { "ms-spaces", G_PART_ALIAS_MS_SPACES },
119 { "netbsd-ccd", G_PART_ALIAS_NETBSD_CCD },
120 { "netbsd-cgd", G_PART_ALIAS_NETBSD_CGD },
121 { "netbsd-ffs", G_PART_ALIAS_NETBSD_FFS },
122 { "netbsd-lfs", G_PART_ALIAS_NETBSD_LFS },
123 { "netbsd-raid", G_PART_ALIAS_NETBSD_RAID },
124 { "netbsd-swap", G_PART_ALIAS_NETBSD_SWAP },
125 { "ntfs", G_PART_ALIAS_MS_NTFS },
126 { "openbsd-data", G_PART_ALIAS_OPENBSD_DATA },
127 { "prep-boot", G_PART_ALIAS_PREP_BOOT },
128 { "solaris-boot", G_PART_ALIAS_SOLARIS_BOOT },
129 { "solaris-root", G_PART_ALIAS_SOLARIS_ROOT },
130 { "solaris-swap", G_PART_ALIAS_SOLARIS_SWAP },
131 { "solaris-backup", G_PART_ALIAS_SOLARIS_BACKUP },
132 { "solaris-var", G_PART_ALIAS_SOLARIS_VAR },
133 { "solaris-home", G_PART_ALIAS_SOLARIS_HOME },
134 { "solaris-altsec", G_PART_ALIAS_SOLARIS_ALTSEC },
135 { "solaris-reserved", G_PART_ALIAS_SOLARIS_RESERVED },
136 { "vmware-reserved", G_PART_ALIAS_VMRESERVED },
137 { "vmware-vmfs", G_PART_ALIAS_VMFS },
138 { "vmware-vmkdiag", G_PART_ALIAS_VMKDIAG },
139 { "vmware-vsanhdr", G_PART_ALIAS_VMVSANHDR },
140 };
141
142 SYSCTL_DECL(_kern_geom);
143 SYSCTL_NODE(_kern_geom, OID_AUTO, part, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
144 "GEOM_PART stuff");
145 u_int geom_part_check_integrity = 1;
146 SYSCTL_UINT(_kern_geom_part, OID_AUTO, check_integrity,
147 CTLFLAG_RWTUN, &geom_part_check_integrity, 1,
148 "Enable integrity checking");
149 static u_int auto_resize = 1;
150 SYSCTL_UINT(_kern_geom_part, OID_AUTO, auto_resize,
151 CTLFLAG_RWTUN, &auto_resize, 1,
152 "Enable auto resize");
153 static u_int allow_nesting = 0;
154 SYSCTL_UINT(_kern_geom_part, OID_AUTO, allow_nesting,
155 CTLFLAG_RWTUN, &allow_nesting, 0,
156 "Allow additional levels of nesting");
157 char g_part_separator[MAXPATHLEN] = "";
158 SYSCTL_STRING(_kern_geom_part, OID_AUTO, separator,
159 CTLFLAG_RDTUN, &g_part_separator, sizeof(g_part_separator),
160 "Partition name separator");
161
162 /*
163 * The GEOM partitioning class.
164 */
165 static g_ctl_req_t g_part_ctlreq;
166 static g_ctl_destroy_geom_t g_part_destroy_geom;
167 static g_fini_t g_part_fini;
168 static g_init_t g_part_init;
169 static g_taste_t g_part_taste;
170
171 static g_access_t g_part_access;
172 static g_dumpconf_t g_part_dumpconf;
173 static g_orphan_t g_part_orphan;
174 static g_spoiled_t g_part_spoiled;
175 static g_start_t g_part_start;
176 static g_resize_t g_part_resize;
177 static g_ioctl_t g_part_ioctl;
178
179 static struct g_class g_part_class = {
180 .name = "PART",
181 .version = G_VERSION,
182 /* Class methods. */
183 .ctlreq = g_part_ctlreq,
184 .destroy_geom = g_part_destroy_geom,
185 .fini = g_part_fini,
186 .init = g_part_init,
187 .taste = g_part_taste,
188 /* Geom methods. */
189 .access = g_part_access,
190 .dumpconf = g_part_dumpconf,
191 .orphan = g_part_orphan,
192 .spoiled = g_part_spoiled,
193 .start = g_part_start,
194 .resize = g_part_resize,
195 .ioctl = g_part_ioctl,
196 };
197
198 DECLARE_GEOM_CLASS(g_part_class, g_part);
199 MODULE_VERSION(g_part, 0);
200
201 /*
202 * Support functions.
203 */
204
205 static void g_part_wither(struct g_geom *, int);
206
207 const char *
208 g_part_alias_name(enum g_part_alias alias)
209 {
210 int i;
211
212 for (i = 0; i < G_PART_ALIAS_COUNT; i++) {
213 if (g_part_alias_list[i].alias != alias)
214 continue;
215 return (g_part_alias_list[i].lexeme);
216 }
217
218 return (NULL);
219 }
220
221 void
222 g_part_geometry_heads(off_t blocks, u_int sectors, off_t *bestchs,
223 u_int *bestheads)
224 {
225 static u_int candidate_heads[] = { 1, 2, 16, 32, 64, 128, 255, 0 };
226 off_t chs, cylinders;
227 u_int heads;
228 int idx;
229
230 *bestchs = 0;
231 *bestheads = 0;
232 for (idx = 0; candidate_heads[idx] != 0; idx++) {
233 heads = candidate_heads[idx];
234 cylinders = blocks / heads / sectors;
235 if (cylinders < heads || cylinders < sectors)
236 break;
237 if (cylinders > 1023)
238 continue;
239 chs = cylinders * heads * sectors;
240 if (chs > *bestchs || (chs == *bestchs && *bestheads == 1)) {
241 *bestchs = chs;
242 *bestheads = heads;
243 }
244 }
245 }
246
247 static void
248 g_part_geometry(struct g_part_table *table, struct g_consumer *cp,
249 off_t blocks)
250 {
251 static u_int candidate_sectors[] = { 1, 9, 17, 33, 63, 0 };
252 off_t chs, bestchs;
253 u_int heads, sectors;
254 int idx;
255
256 if (g_getattr("GEOM::fwsectors", cp, §ors) != 0 || sectors == 0 ||
257 g_getattr("GEOM::fwheads", cp, &heads) != 0 || heads == 0) {
258 table->gpt_fixgeom = 0;
259 table->gpt_heads = 0;
260 table->gpt_sectors = 0;
261 bestchs = 0;
262 for (idx = 0; candidate_sectors[idx] != 0; idx++) {
263 sectors = candidate_sectors[idx];
264 g_part_geometry_heads(blocks, sectors, &chs, &heads);
265 if (chs == 0)
266 continue;
267 /*
268 * Prefer a geometry with sectors > 1, but only if
269 * it doesn't bump down the number of heads to 1.
270 */
271 if (chs > bestchs || (chs == bestchs && heads > 1 &&
272 table->gpt_sectors == 1)) {
273 bestchs = chs;
274 table->gpt_heads = heads;
275 table->gpt_sectors = sectors;
276 }
277 }
278 /*
279 * If we didn't find a geometry at all, then the disk is
280 * too big. This means we can use the maximum number of
281 * heads and sectors.
282 */
283 if (bestchs == 0) {
284 table->gpt_heads = 255;
285 table->gpt_sectors = 63;
286 }
287 } else {
288 table->gpt_fixgeom = 1;
289 table->gpt_heads = heads;
290 table->gpt_sectors = sectors;
291 }
292 }
293
294 static void
295 g_part_get_physpath_done(struct bio *bp)
296 {
297 struct g_geom *gp;
298 struct g_part_entry *entry;
299 struct g_part_table *table;
300 struct g_provider *pp;
301 struct bio *pbp;
302
303 pbp = bp->bio_parent;
304 pp = pbp->bio_to;
305 gp = pp->geom;
306 table = gp->softc;
307 entry = pp->private;
308
309 if (bp->bio_error == 0) {
310 char *end;
311 size_t len, remainder;
312 len = strlcat(bp->bio_data, "/", bp->bio_length);
313 if (len < bp->bio_length) {
314 end = bp->bio_data + len;
315 remainder = bp->bio_length - len;
316 G_PART_NAME(table, entry, end, remainder);
317 }
318 }
319 g_std_done(bp);
320 }
321
322 #define DPRINTF(...) if (bootverbose) { \
323 printf("GEOM_PART: " __VA_ARGS__); \
324 }
325
326 static int
327 g_part_check_integrity(struct g_part_table *table, struct g_consumer *cp)
328 {
329 struct g_part_entry *e1, *e2;
330 struct g_provider *pp;
331 off_t offset;
332 int failed;
333
334 failed = 0;
335 pp = cp->provider;
336 if (table->gpt_last < table->gpt_first) {
337 DPRINTF("last LBA is below first LBA: %jd < %jd\n",
338 (intmax_t)table->gpt_last, (intmax_t)table->gpt_first);
339 failed++;
340 }
341 if (table->gpt_last > pp->mediasize / pp->sectorsize - 1) {
342 DPRINTF("last LBA extends beyond mediasize: "
343 "%jd > %jd\n", (intmax_t)table->gpt_last,
344 (intmax_t)pp->mediasize / pp->sectorsize - 1);
345 failed++;
346 }
347 LIST_FOREACH(e1, &table->gpt_entry, gpe_entry) {
348 if (e1->gpe_deleted || e1->gpe_internal)
349 continue;
350 if (e1->gpe_start < table->gpt_first) {
351 DPRINTF("partition %d has start offset below first "
352 "LBA: %jd < %jd\n", e1->gpe_index,
353 (intmax_t)e1->gpe_start,
354 (intmax_t)table->gpt_first);
355 failed++;
356 }
357 if (e1->gpe_start > table->gpt_last) {
358 DPRINTF("partition %d has start offset beyond last "
359 "LBA: %jd > %jd\n", e1->gpe_index,
360 (intmax_t)e1->gpe_start,
361 (intmax_t)table->gpt_last);
362 failed++;
363 }
364 if (e1->gpe_end < e1->gpe_start) {
365 DPRINTF("partition %d has end offset below start "
366 "offset: %jd < %jd\n", e1->gpe_index,
367 (intmax_t)e1->gpe_end,
368 (intmax_t)e1->gpe_start);
369 failed++;
370 }
371 if (e1->gpe_end > table->gpt_last) {
372 DPRINTF("partition %d has end offset beyond last "
373 "LBA: %jd > %jd\n", e1->gpe_index,
374 (intmax_t)e1->gpe_end,
375 (intmax_t)table->gpt_last);
376 failed++;
377 }
378 if (pp->stripesize > 0) {
379 offset = e1->gpe_start * pp->sectorsize;
380 if (e1->gpe_offset > offset)
381 offset = e1->gpe_offset;
382 if ((offset + pp->stripeoffset) % pp->stripesize) {
383 DPRINTF("partition %d on (%s, %s) is not "
384 "aligned on %ju bytes\n", e1->gpe_index,
385 pp->name, table->gpt_scheme->name,
386 (uintmax_t)pp->stripesize);
387 /* Don't treat this as a critical failure */
388 }
389 }
390 e2 = e1;
391 while ((e2 = LIST_NEXT(e2, gpe_entry)) != NULL) {
392 if (e2->gpe_deleted || e2->gpe_internal)
393 continue;
394 if (e1->gpe_start >= e2->gpe_start &&
395 e1->gpe_start <= e2->gpe_end) {
396 DPRINTF("partition %d has start offset inside "
397 "partition %d: start[%d] %jd >= start[%d] "
398 "%jd <= end[%d] %jd\n",
399 e1->gpe_index, e2->gpe_index,
400 e2->gpe_index, (intmax_t)e2->gpe_start,
401 e1->gpe_index, (intmax_t)e1->gpe_start,
402 e2->gpe_index, (intmax_t)e2->gpe_end);
403 failed++;
404 }
405 if (e1->gpe_end >= e2->gpe_start &&
406 e1->gpe_end <= e2->gpe_end) {
407 DPRINTF("partition %d has end offset inside "
408 "partition %d: start[%d] %jd >= end[%d] "
409 "%jd <= end[%d] %jd\n",
410 e1->gpe_index, e2->gpe_index,
411 e2->gpe_index, (intmax_t)e2->gpe_start,
412 e1->gpe_index, (intmax_t)e1->gpe_end,
413 e2->gpe_index, (intmax_t)e2->gpe_end);
414 failed++;
415 }
416 if (e1->gpe_start < e2->gpe_start &&
417 e1->gpe_end > e2->gpe_end) {
418 DPRINTF("partition %d contains partition %d: "
419 "start[%d] %jd > start[%d] %jd, end[%d] "
420 "%jd < end[%d] %jd\n",
421 e1->gpe_index, e2->gpe_index,
422 e1->gpe_index, (intmax_t)e1->gpe_start,
423 e2->gpe_index, (intmax_t)e2->gpe_start,
424 e2->gpe_index, (intmax_t)e2->gpe_end,
425 e1->gpe_index, (intmax_t)e1->gpe_end);
426 failed++;
427 }
428 }
429 }
430 if (failed != 0) {
431 printf("GEOM_PART: integrity check failed (%s, %s)\n",
432 pp->name, table->gpt_scheme->name);
433 if (geom_part_check_integrity != 0)
434 return (EINVAL);
435 table->gpt_corrupt = 1;
436 }
437 return (0);
438 }
439 #undef DPRINTF
440
441 struct g_part_entry *
442 g_part_new_entry(struct g_part_table *table, int index, quad_t start,
443 quad_t end)
444 {
445 struct g_part_entry *entry, *last;
446
447 last = NULL;
448 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
449 if (entry->gpe_index == index)
450 break;
451 if (entry->gpe_index > index) {
452 entry = NULL;
453 break;
454 }
455 last = entry;
456 }
457 if (entry == NULL) {
458 entry = g_malloc(table->gpt_scheme->gps_entrysz,
459 M_WAITOK | M_ZERO);
460 entry->gpe_index = index;
461 if (last == NULL)
462 LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry);
463 else
464 LIST_INSERT_AFTER(last, entry, gpe_entry);
465 } else
466 entry->gpe_offset = 0;
467 entry->gpe_start = start;
468 entry->gpe_end = end;
469 return (entry);
470 }
471
472 static void
473 g_part_new_provider(struct g_geom *gp, struct g_part_table *table,
474 struct g_part_entry *entry)
475 {
476 struct g_consumer *cp;
477 struct g_provider *pp;
478 struct g_geom_alias *gap;
479 off_t offset;
480
481 cp = LIST_FIRST(&gp->consumer);
482 pp = cp->provider;
483
484 offset = entry->gpe_start * pp->sectorsize;
485 if (entry->gpe_offset < offset)
486 entry->gpe_offset = offset;
487
488 if (entry->gpe_pp == NULL) {
489 entry->gpe_pp = G_PART_NEW_PROVIDER(table, gp, entry, gp->name);
490 /*
491 * If our parent provider had any aliases, then copy them to our
492 * provider so when geom DEV tastes things later, they will be
493 * there for it to create the aliases with those name used in
494 * place of the geom's name we use to create the provider. The
495 * kobj interface that generates names makes this awkward.
496 */
497 LIST_FOREACH(gap, &pp->aliases, ga_next)
498 G_PART_ADD_ALIAS(table, entry->gpe_pp, entry, gap->ga_alias);
499 entry->gpe_pp->flags |= G_PF_DIRECT_SEND | G_PF_DIRECT_RECEIVE;
500 entry->gpe_pp->private = entry; /* Close the circle. */
501 }
502 entry->gpe_pp->index = entry->gpe_index - 1; /* index is 1-based. */
503 entry->gpe_pp->mediasize = (entry->gpe_end - entry->gpe_start + 1) *
504 pp->sectorsize;
505 entry->gpe_pp->mediasize -= entry->gpe_offset - offset;
506 entry->gpe_pp->sectorsize = pp->sectorsize;
507 entry->gpe_pp->stripesize = pp->stripesize;
508 entry->gpe_pp->stripeoffset = pp->stripeoffset + entry->gpe_offset;
509 if (pp->stripesize > 0)
510 entry->gpe_pp->stripeoffset %= pp->stripesize;
511 entry->gpe_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED;
512 g_error_provider(entry->gpe_pp, 0);
513 }
514
515 static struct g_geom*
516 g_part_find_geom(const char *name)
517 {
518 struct g_geom *gp;
519 LIST_FOREACH(gp, &g_part_class.geom, geom) {
520 if ((gp->flags & G_GEOM_WITHER) == 0 &&
521 strcmp(name, gp->name) == 0)
522 break;
523 }
524 return (gp);
525 }
526
527 static int
528 g_part_parm_geom(struct gctl_req *req, const char *name, struct g_geom **v)
529 {
530 struct g_geom *gp;
531 const char *gname;
532
533 gname = gctl_get_asciiparam(req, name);
534 if (gname == NULL)
535 return (ENOATTR);
536 if (strncmp(gname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
537 gname += sizeof(_PATH_DEV) - 1;
538 gp = g_part_find_geom(gname);
539 if (gp == NULL) {
540 gctl_error(req, "%d %s '%s'", EINVAL, name, gname);
541 return (EINVAL);
542 }
543 *v = gp;
544 return (0);
545 }
546
547 static int
548 g_part_parm_provider(struct gctl_req *req, const char *name,
549 struct g_provider **v)
550 {
551 struct g_provider *pp;
552 const char *pname;
553
554 pname = gctl_get_asciiparam(req, name);
555 if (pname == NULL)
556 return (ENOATTR);
557 if (strncmp(pname, _PATH_DEV, sizeof(_PATH_DEV) - 1) == 0)
558 pname += sizeof(_PATH_DEV) - 1;
559 pp = g_provider_by_name(pname);
560 if (pp == NULL) {
561 gctl_error(req, "%d %s '%s'", EINVAL, name, pname);
562 return (EINVAL);
563 }
564 *v = pp;
565 return (0);
566 }
567
568 static int
569 g_part_parm_quad(struct gctl_req *req, const char *name, quad_t *v)
570 {
571 const char *p;
572 char *x;
573 quad_t q;
574
575 p = gctl_get_asciiparam(req, name);
576 if (p == NULL)
577 return (ENOATTR);
578 q = strtoq(p, &x, 0);
579 if (*x != '\0' || q < 0) {
580 gctl_error(req, "%d %s '%s'", EINVAL, name, p);
581 return (EINVAL);
582 }
583 *v = q;
584 return (0);
585 }
586
587 static int
588 g_part_parm_scheme(struct gctl_req *req, const char *name,
589 struct g_part_scheme **v)
590 {
591 struct g_part_scheme *s;
592 const char *p;
593
594 p = gctl_get_asciiparam(req, name);
595 if (p == NULL)
596 return (ENOATTR);
597 TAILQ_FOREACH(s, &g_part_schemes, scheme_list) {
598 if (s == &g_part_null_scheme)
599 continue;
600 if (!strcasecmp(s->name, p))
601 break;
602 }
603 if (s == NULL) {
604 gctl_error(req, "%d %s '%s'", EINVAL, name, p);
605 return (EINVAL);
606 }
607 *v = s;
608 return (0);
609 }
610
611 static int
612 g_part_parm_str(struct gctl_req *req, const char *name, const char **v)
613 {
614 const char *p;
615
616 p = gctl_get_asciiparam(req, name);
617 if (p == NULL)
618 return (ENOATTR);
619 /* An empty label is always valid. */
620 if (strcmp(name, "label") != 0 && p[0] == '\0') {
621 gctl_error(req, "%d %s '%s'", EINVAL, name, p);
622 return (EINVAL);
623 }
624 *v = p;
625 return (0);
626 }
627
628 static int
629 g_part_parm_intmax(struct gctl_req *req, const char *name, u_int *v)
630 {
631 const intmax_t *p;
632 int size;
633
634 p = gctl_get_param(req, name, &size);
635 if (p == NULL)
636 return (ENOATTR);
637 if (size != sizeof(*p) || *p < 0 || *p > INT_MAX) {
638 gctl_error(req, "%d %s '%jd'", EINVAL, name, *p);
639 return (EINVAL);
640 }
641 *v = (u_int)*p;
642 return (0);
643 }
644
645 static int
646 g_part_parm_uint32(struct gctl_req *req, const char *name, u_int *v)
647 {
648 const uint32_t *p;
649 int size;
650
651 p = gctl_get_param(req, name, &size);
652 if (p == NULL)
653 return (ENOATTR);
654 if (size != sizeof(*p) || *p > INT_MAX) {
655 gctl_error(req, "%d %s '%u'", EINVAL, name, (unsigned int)*p);
656 return (EINVAL);
657 }
658 *v = (u_int)*p;
659 return (0);
660 }
661
662 static int
663 g_part_parm_bootcode(struct gctl_req *req, const char *name, const void **v,
664 unsigned int *s)
665 {
666 const void *p;
667 int size;
668
669 p = gctl_get_param(req, name, &size);
670 if (p == NULL)
671 return (ENOATTR);
672 *v = p;
673 *s = size;
674 return (0);
675 }
676
677 static int
678 g_part_probe(struct g_geom *gp, struct g_consumer *cp, int depth)
679 {
680 struct g_part_scheme *iter, *scheme;
681 struct g_part_table *table;
682 int pri, probe;
683
684 table = gp->softc;
685 scheme = (table != NULL) ? table->gpt_scheme : NULL;
686 pri = (scheme != NULL) ? G_PART_PROBE(table, cp) : INT_MIN;
687 if (pri == 0)
688 goto done;
689 if (pri > 0) { /* error */
690 scheme = NULL;
691 pri = INT_MIN;
692 }
693
694 TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) {
695 if (iter == &g_part_null_scheme)
696 continue;
697 table = (void *)kobj_create((kobj_class_t)iter, M_GEOM,
698 M_WAITOK);
699 table->gpt_gp = gp;
700 table->gpt_scheme = iter;
701 table->gpt_depth = depth;
702 probe = G_PART_PROBE(table, cp);
703 if (probe <= 0 && probe > pri) {
704 pri = probe;
705 scheme = iter;
706 if (gp->softc != NULL)
707 kobj_delete((kobj_t)gp->softc, M_GEOM);
708 gp->softc = table;
709 if (pri == 0)
710 goto done;
711 } else
712 kobj_delete((kobj_t)table, M_GEOM);
713 }
714
715 done:
716 return ((scheme == NULL) ? ENXIO : 0);
717 }
718
719 /*
720 * Control request functions.
721 */
722
723 static int
724 g_part_ctl_add(struct gctl_req *req, struct g_part_parms *gpp)
725 {
726 struct g_geom *gp;
727 struct g_provider *pp;
728 struct g_part_entry *delent, *last, *entry;
729 struct g_part_table *table;
730 struct sbuf *sb;
731 quad_t end;
732 unsigned int index;
733 int error;
734
735 gp = gpp->gpp_geom;
736 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
737 g_topology_assert();
738
739 pp = LIST_FIRST(&gp->consumer)->provider;
740 table = gp->softc;
741 end = gpp->gpp_start + gpp->gpp_size - 1;
742
743 if (gpp->gpp_start < table->gpt_first ||
744 gpp->gpp_start > table->gpt_last) {
745 gctl_error(req, "%d start '%jd'", EINVAL,
746 (intmax_t)gpp->gpp_start);
747 return (EINVAL);
748 }
749 if (end < gpp->gpp_start || end > table->gpt_last) {
750 gctl_error(req, "%d size '%jd'", EINVAL,
751 (intmax_t)gpp->gpp_size);
752 return (EINVAL);
753 }
754 if (gpp->gpp_index > table->gpt_entries) {
755 gctl_error(req, "%d index '%d'", EINVAL, gpp->gpp_index);
756 return (EINVAL);
757 }
758
759 delent = last = NULL;
760 index = (gpp->gpp_index > 0) ? gpp->gpp_index : 1;
761 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
762 if (entry->gpe_deleted) {
763 if (entry->gpe_index == index)
764 delent = entry;
765 continue;
766 }
767 if (entry->gpe_index == index)
768 index = entry->gpe_index + 1;
769 if (entry->gpe_index < index)
770 last = entry;
771 if (entry->gpe_internal)
772 continue;
773 if (gpp->gpp_start >= entry->gpe_start &&
774 gpp->gpp_start <= entry->gpe_end) {
775 gctl_error(req, "%d start '%jd'", ENOSPC,
776 (intmax_t)gpp->gpp_start);
777 return (ENOSPC);
778 }
779 if (end >= entry->gpe_start && end <= entry->gpe_end) {
780 gctl_error(req, "%d end '%jd'", ENOSPC, (intmax_t)end);
781 return (ENOSPC);
782 }
783 if (gpp->gpp_start < entry->gpe_start && end > entry->gpe_end) {
784 gctl_error(req, "%d size '%jd'", ENOSPC,
785 (intmax_t)gpp->gpp_size);
786 return (ENOSPC);
787 }
788 }
789 if (gpp->gpp_index > 0 && index != gpp->gpp_index) {
790 gctl_error(req, "%d index '%d'", EEXIST, gpp->gpp_index);
791 return (EEXIST);
792 }
793 if (index > table->gpt_entries) {
794 gctl_error(req, "%d index '%d'", ENOSPC, index);
795 return (ENOSPC);
796 }
797
798 entry = (delent == NULL) ? g_malloc(table->gpt_scheme->gps_entrysz,
799 M_WAITOK | M_ZERO) : delent;
800 entry->gpe_index = index;
801 entry->gpe_start = gpp->gpp_start;
802 entry->gpe_end = end;
803 error = G_PART_ADD(table, entry, gpp);
804 if (error) {
805 gctl_error(req, "%d", error);
806 if (delent == NULL)
807 g_free(entry);
808 return (error);
809 }
810 if (delent == NULL) {
811 if (last == NULL)
812 LIST_INSERT_HEAD(&table->gpt_entry, entry, gpe_entry);
813 else
814 LIST_INSERT_AFTER(last, entry, gpe_entry);
815 entry->gpe_created = 1;
816 } else {
817 entry->gpe_deleted = 0;
818 entry->gpe_modified = 1;
819 }
820 g_part_new_provider(gp, table, entry);
821
822 /* Provide feedback if so requested. */
823 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
824 sb = sbuf_new_auto();
825 G_PART_FULLNAME(table, entry, sb, gp->name);
826 if (pp->stripesize > 0 && entry->gpe_pp->stripeoffset != 0)
827 sbuf_printf(sb, " added, but partition is not "
828 "aligned on %ju bytes\n", (uintmax_t)pp->stripesize);
829 else
830 sbuf_cat(sb, " added\n");
831 sbuf_finish(sb);
832 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
833 sbuf_delete(sb);
834 }
835 return (0);
836 }
837
838 static int
839 g_part_ctl_bootcode(struct gctl_req *req, struct g_part_parms *gpp)
840 {
841 struct g_geom *gp;
842 struct g_part_table *table;
843 struct sbuf *sb;
844 int error, sz;
845
846 gp = gpp->gpp_geom;
847 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
848 g_topology_assert();
849
850 table = gp->softc;
851 sz = table->gpt_scheme->gps_bootcodesz;
852 if (sz == 0) {
853 error = ENODEV;
854 goto fail;
855 }
856 if (gpp->gpp_codesize > sz) {
857 error = EFBIG;
858 goto fail;
859 }
860
861 error = G_PART_BOOTCODE(table, gpp);
862 if (error)
863 goto fail;
864
865 /* Provide feedback if so requested. */
866 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
867 sb = sbuf_new_auto();
868 sbuf_printf(sb, "bootcode written to %s\n", gp->name);
869 sbuf_finish(sb);
870 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
871 sbuf_delete(sb);
872 }
873 return (0);
874
875 fail:
876 gctl_error(req, "%d", error);
877 return (error);
878 }
879
880 static int
881 g_part_ctl_commit(struct gctl_req *req, struct g_part_parms *gpp)
882 {
883 struct g_consumer *cp;
884 struct g_geom *gp;
885 struct g_provider *pp;
886 struct g_part_entry *entry, *tmp;
887 struct g_part_table *table;
888 char *buf;
889 int error, i;
890
891 gp = gpp->gpp_geom;
892 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
893 g_topology_assert();
894
895 table = gp->softc;
896 if (!table->gpt_opened) {
897 gctl_error(req, "%d", EPERM);
898 return (EPERM);
899 }
900
901 g_topology_unlock();
902
903 cp = LIST_FIRST(&gp->consumer);
904 if ((table->gpt_smhead | table->gpt_smtail) != 0) {
905 pp = cp->provider;
906 buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
907 while (table->gpt_smhead != 0) {
908 i = ffs(table->gpt_smhead) - 1;
909 error = g_write_data(cp, i * pp->sectorsize, buf,
910 pp->sectorsize);
911 if (error) {
912 g_free(buf);
913 goto fail;
914 }
915 table->gpt_smhead &= ~(1 << i);
916 }
917 while (table->gpt_smtail != 0) {
918 i = ffs(table->gpt_smtail) - 1;
919 error = g_write_data(cp, pp->mediasize - (i + 1) *
920 pp->sectorsize, buf, pp->sectorsize);
921 if (error) {
922 g_free(buf);
923 goto fail;
924 }
925 table->gpt_smtail &= ~(1 << i);
926 }
927 g_free(buf);
928 }
929
930 if (table->gpt_scheme == &g_part_null_scheme) {
931 g_topology_lock();
932 g_access(cp, -1, -1, -1);
933 g_part_wither(gp, ENXIO);
934 return (0);
935 }
936
937 error = G_PART_WRITE(table, cp);
938 if (error)
939 goto fail;
940
941 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
942 if (!entry->gpe_deleted) {
943 /* Notify consumers that provider might be changed. */
944 if (entry->gpe_modified && (
945 entry->gpe_pp->acw + entry->gpe_pp->ace +
946 entry->gpe_pp->acr) == 0)
947 g_media_changed(entry->gpe_pp, M_NOWAIT);
948 entry->gpe_created = 0;
949 entry->gpe_modified = 0;
950 continue;
951 }
952 LIST_REMOVE(entry, gpe_entry);
953 g_free(entry);
954 }
955 table->gpt_created = 0;
956 table->gpt_opened = 0;
957
958 g_topology_lock();
959 g_access(cp, -1, -1, -1);
960 return (0);
961
962 fail:
963 g_topology_lock();
964 gctl_error(req, "%d", error);
965 return (error);
966 }
967
968 static int
969 g_part_ctl_create(struct gctl_req *req, struct g_part_parms *gpp)
970 {
971 struct g_consumer *cp;
972 struct g_geom *gp;
973 struct g_provider *pp;
974 struct g_part_scheme *scheme;
975 struct g_part_table *null, *table;
976 struct sbuf *sb;
977 int attr, error;
978
979 pp = gpp->gpp_provider;
980 scheme = gpp->gpp_scheme;
981 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name));
982 g_topology_assert();
983
984 /* Check that there isn't already a g_part geom on the provider. */
985 gp = g_part_find_geom(pp->name);
986 if (gp != NULL) {
987 null = gp->softc;
988 if (null->gpt_scheme != &g_part_null_scheme) {
989 gctl_error(req, "%d geom '%s'", EEXIST, pp->name);
990 return (EEXIST);
991 }
992 } else
993 null = NULL;
994
995 if ((gpp->gpp_parms & G_PART_PARM_ENTRIES) &&
996 (gpp->gpp_entries < scheme->gps_minent ||
997 gpp->gpp_entries > scheme->gps_maxent)) {
998 gctl_error(req, "%d entries '%d'", EINVAL, gpp->gpp_entries);
999 return (EINVAL);
1000 }
1001
1002 if (null == NULL)
1003 gp = g_new_geomf(&g_part_class, "%s", pp->name);
1004 gp->softc = kobj_create((kobj_class_t)gpp->gpp_scheme, M_GEOM,
1005 M_WAITOK);
1006 table = gp->softc;
1007 table->gpt_gp = gp;
1008 table->gpt_scheme = gpp->gpp_scheme;
1009 table->gpt_entries = (gpp->gpp_parms & G_PART_PARM_ENTRIES) ?
1010 gpp->gpp_entries : scheme->gps_minent;
1011 LIST_INIT(&table->gpt_entry);
1012 if (null == NULL) {
1013 cp = g_new_consumer(gp);
1014 cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
1015 error = g_attach(cp, pp);
1016 if (error == 0)
1017 error = g_access(cp, 1, 1, 1);
1018 if (error != 0) {
1019 g_part_wither(gp, error);
1020 gctl_error(req, "%d geom '%s'", error, pp->name);
1021 return (error);
1022 }
1023 table->gpt_opened = 1;
1024 } else {
1025 cp = LIST_FIRST(&gp->consumer);
1026 table->gpt_opened = null->gpt_opened;
1027 table->gpt_smhead = null->gpt_smhead;
1028 table->gpt_smtail = null->gpt_smtail;
1029 }
1030
1031 g_topology_unlock();
1032
1033 /* Make sure the provider has media. */
1034 if (pp->mediasize == 0 || pp->sectorsize == 0) {
1035 error = ENODEV;
1036 goto fail;
1037 }
1038
1039 /* Make sure we can nest and if so, determine our depth. */
1040 error = g_getattr("PART::isleaf", cp, &attr);
1041 if (!error && attr) {
1042 error = ENODEV;
1043 goto fail;
1044 }
1045 error = g_getattr("PART::depth", cp, &attr);
1046 table->gpt_depth = (!error) ? attr + 1 : 0;
1047
1048 /*
1049 * Synthesize a disk geometry. Some partitioning schemes
1050 * depend on it and since some file systems need it even
1051 * when the partitition scheme doesn't, we do it here in
1052 * scheme-independent code.
1053 */
1054 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
1055
1056 error = G_PART_CREATE(table, gpp);
1057 if (error)
1058 goto fail;
1059
1060 g_topology_lock();
1061
1062 table->gpt_created = 1;
1063 if (null != NULL)
1064 kobj_delete((kobj_t)null, M_GEOM);
1065
1066 /*
1067 * Support automatic commit by filling in the gpp_geom
1068 * parameter.
1069 */
1070 gpp->gpp_parms |= G_PART_PARM_GEOM;
1071 gpp->gpp_geom = gp;
1072
1073 /* Provide feedback if so requested. */
1074 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1075 sb = sbuf_new_auto();
1076 sbuf_printf(sb, "%s created\n", gp->name);
1077 sbuf_finish(sb);
1078 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1079 sbuf_delete(sb);
1080 }
1081 return (0);
1082
1083 fail:
1084 g_topology_lock();
1085 if (null == NULL) {
1086 g_access(cp, -1, -1, -1);
1087 g_part_wither(gp, error);
1088 } else {
1089 kobj_delete((kobj_t)gp->softc, M_GEOM);
1090 gp->softc = null;
1091 }
1092 gctl_error(req, "%d provider", error);
1093 return (error);
1094 }
1095
1096 static int
1097 g_part_ctl_delete(struct gctl_req *req, struct g_part_parms *gpp)
1098 {
1099 struct g_geom *gp;
1100 struct g_provider *pp;
1101 struct g_part_entry *entry;
1102 struct g_part_table *table;
1103 struct sbuf *sb;
1104
1105 gp = gpp->gpp_geom;
1106 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1107 g_topology_assert();
1108
1109 table = gp->softc;
1110
1111 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1112 if (entry->gpe_deleted || entry->gpe_internal)
1113 continue;
1114 if (entry->gpe_index == gpp->gpp_index)
1115 break;
1116 }
1117 if (entry == NULL) {
1118 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
1119 return (ENOENT);
1120 }
1121
1122 pp = entry->gpe_pp;
1123 if (pp != NULL) {
1124 if (pp->acr > 0 || pp->acw > 0 || pp->ace > 0) {
1125 gctl_error(req, "%d", EBUSY);
1126 return (EBUSY);
1127 }
1128
1129 pp->private = NULL;
1130 entry->gpe_pp = NULL;
1131 }
1132
1133 if (pp != NULL)
1134 g_wither_provider(pp, ENXIO);
1135
1136 /* Provide feedback if so requested. */
1137 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1138 sb = sbuf_new_auto();
1139 G_PART_FULLNAME(table, entry, sb, gp->name);
1140 sbuf_cat(sb, " deleted\n");
1141 sbuf_finish(sb);
1142 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1143 sbuf_delete(sb);
1144 }
1145
1146 if (entry->gpe_created) {
1147 LIST_REMOVE(entry, gpe_entry);
1148 g_free(entry);
1149 } else {
1150 entry->gpe_modified = 0;
1151 entry->gpe_deleted = 1;
1152 }
1153 return (0);
1154 }
1155
1156 static int
1157 g_part_ctl_destroy(struct gctl_req *req, struct g_part_parms *gpp)
1158 {
1159 struct g_consumer *cp;
1160 struct g_geom *gp;
1161 struct g_provider *pp;
1162 struct g_part_entry *entry, *tmp;
1163 struct g_part_table *null, *table;
1164 struct sbuf *sb;
1165 int error;
1166
1167 gp = gpp->gpp_geom;
1168 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1169 g_topology_assert();
1170
1171 table = gp->softc;
1172 /* Check for busy providers. */
1173 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1174 if (entry->gpe_deleted || entry->gpe_internal)
1175 continue;
1176 if (gpp->gpp_force) {
1177 pp = entry->gpe_pp;
1178 if (pp == NULL)
1179 continue;
1180 if (pp->acr == 0 && pp->acw == 0 && pp->ace == 0)
1181 continue;
1182 }
1183 gctl_error(req, "%d", EBUSY);
1184 return (EBUSY);
1185 }
1186
1187 if (gpp->gpp_force) {
1188 /* Destroy all providers. */
1189 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
1190 pp = entry->gpe_pp;
1191 if (pp != NULL) {
1192 pp->private = NULL;
1193 g_wither_provider(pp, ENXIO);
1194 }
1195 LIST_REMOVE(entry, gpe_entry);
1196 g_free(entry);
1197 }
1198 }
1199
1200 error = G_PART_DESTROY(table, gpp);
1201 if (error) {
1202 gctl_error(req, "%d", error);
1203 return (error);
1204 }
1205
1206 gp->softc = kobj_create((kobj_class_t)&g_part_null_scheme, M_GEOM,
1207 M_WAITOK);
1208 null = gp->softc;
1209 null->gpt_gp = gp;
1210 null->gpt_scheme = &g_part_null_scheme;
1211 LIST_INIT(&null->gpt_entry);
1212
1213 cp = LIST_FIRST(&gp->consumer);
1214 pp = cp->provider;
1215 null->gpt_last = pp->mediasize / pp->sectorsize - 1;
1216
1217 null->gpt_depth = table->gpt_depth;
1218 null->gpt_opened = table->gpt_opened;
1219 null->gpt_smhead = table->gpt_smhead;
1220 null->gpt_smtail = table->gpt_smtail;
1221
1222 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
1223 LIST_REMOVE(entry, gpe_entry);
1224 g_free(entry);
1225 }
1226 kobj_delete((kobj_t)table, M_GEOM);
1227
1228 /* Provide feedback if so requested. */
1229 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1230 sb = sbuf_new_auto();
1231 sbuf_printf(sb, "%s destroyed\n", gp->name);
1232 sbuf_finish(sb);
1233 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1234 sbuf_delete(sb);
1235 }
1236 return (0);
1237 }
1238
1239 static int
1240 g_part_ctl_modify(struct gctl_req *req, struct g_part_parms *gpp)
1241 {
1242 struct g_geom *gp;
1243 struct g_part_entry *entry;
1244 struct g_part_table *table;
1245 struct sbuf *sb;
1246 int error;
1247
1248 gp = gpp->gpp_geom;
1249 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1250 g_topology_assert();
1251
1252 table = gp->softc;
1253
1254 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1255 if (entry->gpe_deleted || entry->gpe_internal)
1256 continue;
1257 if (entry->gpe_index == gpp->gpp_index)
1258 break;
1259 }
1260 if (entry == NULL) {
1261 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
1262 return (ENOENT);
1263 }
1264
1265 error = G_PART_MODIFY(table, entry, gpp);
1266 if (error) {
1267 gctl_error(req, "%d", error);
1268 return (error);
1269 }
1270
1271 if (!entry->gpe_created)
1272 entry->gpe_modified = 1;
1273
1274 /* Provide feedback if so requested. */
1275 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1276 sb = sbuf_new_auto();
1277 G_PART_FULLNAME(table, entry, sb, gp->name);
1278 sbuf_cat(sb, " modified\n");
1279 sbuf_finish(sb);
1280 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1281 sbuf_delete(sb);
1282 }
1283 return (0);
1284 }
1285
1286 static int
1287 g_part_ctl_move(struct gctl_req *req, struct g_part_parms *gpp)
1288 {
1289 gctl_error(req, "%d verb 'move'", ENOSYS);
1290 return (ENOSYS);
1291 }
1292
1293 static int
1294 g_part_ctl_recover(struct gctl_req *req, struct g_part_parms *gpp)
1295 {
1296 struct g_part_table *table;
1297 struct g_geom *gp;
1298 struct sbuf *sb;
1299 int error, recovered;
1300
1301 gp = gpp->gpp_geom;
1302 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1303 g_topology_assert();
1304 table = gp->softc;
1305 error = recovered = 0;
1306
1307 if (table->gpt_corrupt) {
1308 error = G_PART_RECOVER(table);
1309 if (error == 0)
1310 error = g_part_check_integrity(table,
1311 LIST_FIRST(&gp->consumer));
1312 if (error) {
1313 gctl_error(req, "%d recovering '%s' failed",
1314 error, gp->name);
1315 return (error);
1316 }
1317 recovered = 1;
1318 }
1319 /* Provide feedback if so requested. */
1320 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1321 sb = sbuf_new_auto();
1322 if (recovered)
1323 sbuf_printf(sb, "%s recovered\n", gp->name);
1324 else
1325 sbuf_printf(sb, "%s recovering is not needed\n",
1326 gp->name);
1327 sbuf_finish(sb);
1328 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1329 sbuf_delete(sb);
1330 }
1331 return (0);
1332 }
1333
1334 static int
1335 g_part_ctl_resize(struct gctl_req *req, struct g_part_parms *gpp)
1336 {
1337 struct g_geom *gp;
1338 struct g_provider *pp;
1339 struct g_part_entry *pe, *entry;
1340 struct g_part_table *table;
1341 struct sbuf *sb;
1342 quad_t end;
1343 int error;
1344 off_t mediasize;
1345
1346 gp = gpp->gpp_geom;
1347 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1348 g_topology_assert();
1349 table = gp->softc;
1350
1351 /* check gpp_index */
1352 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1353 if (entry->gpe_deleted || entry->gpe_internal)
1354 continue;
1355 if (entry->gpe_index == gpp->gpp_index)
1356 break;
1357 }
1358 if (entry == NULL) {
1359 gctl_error(req, "%d index '%d'", ENOENT, gpp->gpp_index);
1360 return (ENOENT);
1361 }
1362
1363 /* check gpp_size */
1364 end = entry->gpe_start + gpp->gpp_size - 1;
1365 if (gpp->gpp_size < 1 || end > table->gpt_last) {
1366 gctl_error(req, "%d size '%jd'", EINVAL,
1367 (intmax_t)gpp->gpp_size);
1368 return (EINVAL);
1369 }
1370
1371 LIST_FOREACH(pe, &table->gpt_entry, gpe_entry) {
1372 if (pe->gpe_deleted || pe->gpe_internal || pe == entry)
1373 continue;
1374 if (end >= pe->gpe_start && end <= pe->gpe_end) {
1375 gctl_error(req, "%d end '%jd'", ENOSPC,
1376 (intmax_t)end);
1377 return (ENOSPC);
1378 }
1379 if (entry->gpe_start < pe->gpe_start && end > pe->gpe_end) {
1380 gctl_error(req, "%d size '%jd'", ENOSPC,
1381 (intmax_t)gpp->gpp_size);
1382 return (ENOSPC);
1383 }
1384 }
1385
1386 pp = entry->gpe_pp;
1387 if ((g_debugflags & G_F_FOOTSHOOTING) == 0 &&
1388 (pp->acr > 0 || pp->acw > 0 || pp->ace > 0)) {
1389 if (entry->gpe_end - entry->gpe_start + 1 > gpp->gpp_size) {
1390 /* Deny shrinking of an opened partition. */
1391 gctl_error(req, "%d", EBUSY);
1392 return (EBUSY);
1393 }
1394 }
1395
1396 error = G_PART_RESIZE(table, entry, gpp);
1397 if (error) {
1398 gctl_error(req, "%d%s", error, error != EBUSY ? "":
1399 " resizing will lead to unexpected shrinking"
1400 " due to alignment");
1401 return (error);
1402 }
1403
1404 if (!entry->gpe_created)
1405 entry->gpe_modified = 1;
1406
1407 /* update mediasize of changed provider */
1408 mediasize = (entry->gpe_end - entry->gpe_start + 1) *
1409 pp->sectorsize;
1410 g_resize_provider(pp, mediasize);
1411
1412 /* Provide feedback if so requested. */
1413 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1414 sb = sbuf_new_auto();
1415 G_PART_FULLNAME(table, entry, sb, gp->name);
1416 sbuf_cat(sb, " resized\n");
1417 sbuf_finish(sb);
1418 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1419 sbuf_delete(sb);
1420 }
1421 return (0);
1422 }
1423
1424 static int
1425 g_part_ctl_setunset(struct gctl_req *req, struct g_part_parms *gpp,
1426 unsigned int set)
1427 {
1428 struct g_geom *gp;
1429 struct g_part_entry *entry;
1430 struct g_part_table *table;
1431 struct sbuf *sb;
1432 int error;
1433
1434 gp = gpp->gpp_geom;
1435 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1436 g_topology_assert();
1437
1438 table = gp->softc;
1439
1440 if (gpp->gpp_parms & G_PART_PARM_INDEX) {
1441 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1442 if (entry->gpe_deleted || entry->gpe_internal)
1443 continue;
1444 if (entry->gpe_index == gpp->gpp_index)
1445 break;
1446 }
1447 if (entry == NULL) {
1448 gctl_error(req, "%d index '%d'", ENOENT,
1449 gpp->gpp_index);
1450 return (ENOENT);
1451 }
1452 } else
1453 entry = NULL;
1454
1455 error = G_PART_SETUNSET(table, entry, gpp->gpp_attrib, set);
1456 if (error) {
1457 gctl_error(req, "%d attrib '%s'", error, gpp->gpp_attrib);
1458 return (error);
1459 }
1460
1461 /* Provide feedback if so requested. */
1462 if (gpp->gpp_parms & G_PART_PARM_OUTPUT) {
1463 sb = sbuf_new_auto();
1464 sbuf_printf(sb, "%s %sset on ", gpp->gpp_attrib,
1465 (set) ? "" : "un");
1466 if (entry)
1467 G_PART_FULLNAME(table, entry, sb, gp->name);
1468 else
1469 sbuf_cat(sb, gp->name);
1470 sbuf_cat(sb, "\n");
1471 sbuf_finish(sb);
1472 gctl_set_param(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1473 sbuf_delete(sb);
1474 }
1475 return (0);
1476 }
1477
1478 static int
1479 g_part_ctl_undo(struct gctl_req *req, struct g_part_parms *gpp)
1480 {
1481 struct g_consumer *cp;
1482 struct g_provider *pp;
1483 struct g_geom *gp;
1484 struct g_part_entry *entry, *tmp;
1485 struct g_part_table *table;
1486 int error, reprobe;
1487
1488 gp = gpp->gpp_geom;
1489 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, gp->name));
1490 g_topology_assert();
1491
1492 table = gp->softc;
1493 if (!table->gpt_opened) {
1494 gctl_error(req, "%d", EPERM);
1495 return (EPERM);
1496 }
1497
1498 cp = LIST_FIRST(&gp->consumer);
1499 LIST_FOREACH_SAFE(entry, &table->gpt_entry, gpe_entry, tmp) {
1500 entry->gpe_modified = 0;
1501 if (entry->gpe_created) {
1502 pp = entry->gpe_pp;
1503 if (pp != NULL) {
1504 pp->private = NULL;
1505 entry->gpe_pp = NULL;
1506 g_wither_provider(pp, ENXIO);
1507 }
1508 entry->gpe_deleted = 1;
1509 }
1510 if (entry->gpe_deleted) {
1511 LIST_REMOVE(entry, gpe_entry);
1512 g_free(entry);
1513 }
1514 }
1515
1516 g_topology_unlock();
1517
1518 reprobe = (table->gpt_scheme == &g_part_null_scheme ||
1519 table->gpt_created) ? 1 : 0;
1520
1521 if (reprobe) {
1522 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1523 if (entry->gpe_internal)
1524 continue;
1525 error = EBUSY;
1526 goto fail;
1527 }
1528 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
1529 LIST_REMOVE(entry, gpe_entry);
1530 g_free(entry);
1531 }
1532 error = g_part_probe(gp, cp, table->gpt_depth);
1533 if (error) {
1534 g_topology_lock();
1535 g_access(cp, -1, -1, -1);
1536 g_part_wither(gp, error);
1537 return (0);
1538 }
1539 table = gp->softc;
1540
1541 /*
1542 * Synthesize a disk geometry. Some partitioning schemes
1543 * depend on it and since some file systems need it even
1544 * when the partitition scheme doesn't, we do it here in
1545 * scheme-independent code.
1546 */
1547 pp = cp->provider;
1548 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
1549 }
1550
1551 error = G_PART_READ(table, cp);
1552 if (error)
1553 goto fail;
1554 error = g_part_check_integrity(table, cp);
1555 if (error)
1556 goto fail;
1557
1558 g_topology_lock();
1559 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
1560 if (!entry->gpe_internal)
1561 g_part_new_provider(gp, table, entry);
1562 }
1563
1564 table->gpt_opened = 0;
1565 g_access(cp, -1, -1, -1);
1566 return (0);
1567
1568 fail:
1569 g_topology_lock();
1570 gctl_error(req, "%d", error);
1571 return (error);
1572 }
1573
1574 static void
1575 g_part_wither(struct g_geom *gp, int error)
1576 {
1577 struct g_part_entry *entry;
1578 struct g_part_table *table;
1579 struct g_provider *pp;
1580
1581 table = gp->softc;
1582 if (table != NULL) {
1583 gp->softc = NULL;
1584 while ((entry = LIST_FIRST(&table->gpt_entry)) != NULL) {
1585 LIST_REMOVE(entry, gpe_entry);
1586 pp = entry->gpe_pp;
1587 entry->gpe_pp = NULL;
1588 if (pp != NULL) {
1589 pp->private = NULL;
1590 g_wither_provider(pp, error);
1591 }
1592 g_free(entry);
1593 }
1594 G_PART_DESTROY(table, NULL);
1595 kobj_delete((kobj_t)table, M_GEOM);
1596 }
1597 g_wither_geom(gp, error);
1598 }
1599
1600 /*
1601 * Class methods.
1602 */
1603
1604 static void
1605 g_part_ctlreq(struct gctl_req *req, struct g_class *mp, const char *verb)
1606 {
1607 struct g_part_parms gpp;
1608 struct g_part_table *table;
1609 struct gctl_req_arg *ap;
1610 enum g_part_ctl ctlreq;
1611 unsigned int i, mparms, oparms, parm;
1612 int auto_commit, close_on_error;
1613 int error, modifies;
1614
1615 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, verb));
1616 g_topology_assert();
1617
1618 ctlreq = G_PART_CTL_NONE;
1619 modifies = 1;
1620 mparms = 0;
1621 oparms = G_PART_PARM_FLAGS | G_PART_PARM_OUTPUT | G_PART_PARM_VERSION;
1622 switch (*verb) {
1623 case 'a':
1624 if (!strcmp(verb, "add")) {
1625 ctlreq = G_PART_CTL_ADD;
1626 mparms |= G_PART_PARM_GEOM | G_PART_PARM_SIZE |
1627 G_PART_PARM_START | G_PART_PARM_TYPE;
1628 oparms |= G_PART_PARM_INDEX | G_PART_PARM_LABEL;
1629 }
1630 break;
1631 case 'b':
1632 if (!strcmp(verb, "bootcode")) {
1633 ctlreq = G_PART_CTL_BOOTCODE;
1634 mparms |= G_PART_PARM_GEOM | G_PART_PARM_BOOTCODE;
1635 oparms |= G_PART_PARM_SKIP_DSN;
1636 }
1637 break;
1638 case 'c':
1639 if (!strcmp(verb, "commit")) {
1640 ctlreq = G_PART_CTL_COMMIT;
1641 mparms |= G_PART_PARM_GEOM;
1642 modifies = 0;
1643 } else if (!strcmp(verb, "create")) {
1644 ctlreq = G_PART_CTL_CREATE;
1645 mparms |= G_PART_PARM_PROVIDER | G_PART_PARM_SCHEME;
1646 oparms |= G_PART_PARM_ENTRIES;
1647 }
1648 break;
1649 case 'd':
1650 if (!strcmp(verb, "delete")) {
1651 ctlreq = G_PART_CTL_DELETE;
1652 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1653 } else if (!strcmp(verb, "destroy")) {
1654 ctlreq = G_PART_CTL_DESTROY;
1655 mparms |= G_PART_PARM_GEOM;
1656 oparms |= G_PART_PARM_FORCE;
1657 }
1658 break;
1659 case 'm':
1660 if (!strcmp(verb, "modify")) {
1661 ctlreq = G_PART_CTL_MODIFY;
1662 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1663 oparms |= G_PART_PARM_LABEL | G_PART_PARM_TYPE;
1664 } else if (!strcmp(verb, "move")) {
1665 ctlreq = G_PART_CTL_MOVE;
1666 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX;
1667 }
1668 break;
1669 case 'r':
1670 if (!strcmp(verb, "recover")) {
1671 ctlreq = G_PART_CTL_RECOVER;
1672 mparms |= G_PART_PARM_GEOM;
1673 } else if (!strcmp(verb, "resize")) {
1674 ctlreq = G_PART_CTL_RESIZE;
1675 mparms |= G_PART_PARM_GEOM | G_PART_PARM_INDEX |
1676 G_PART_PARM_SIZE;
1677 }
1678 break;
1679 case 's':
1680 if (!strcmp(verb, "set")) {
1681 ctlreq = G_PART_CTL_SET;
1682 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM;
1683 oparms |= G_PART_PARM_INDEX;
1684 }
1685 break;
1686 case 'u':
1687 if (!strcmp(verb, "undo")) {
1688 ctlreq = G_PART_CTL_UNDO;
1689 mparms |= G_PART_PARM_GEOM;
1690 modifies = 0;
1691 } else if (!strcmp(verb, "unset")) {
1692 ctlreq = G_PART_CTL_UNSET;
1693 mparms |= G_PART_PARM_ATTRIB | G_PART_PARM_GEOM;
1694 oparms |= G_PART_PARM_INDEX;
1695 }
1696 break;
1697 }
1698 if (ctlreq == G_PART_CTL_NONE) {
1699 gctl_error(req, "%d verb '%s'", EINVAL, verb);
1700 return;
1701 }
1702
1703 bzero(&gpp, sizeof(gpp));
1704 for (i = 0; i < req->narg; i++) {
1705 ap = &req->arg[i];
1706 parm = 0;
1707 switch (ap->name[0]) {
1708 case 'a':
1709 if (!strcmp(ap->name, "arg0")) {
1710 parm = mparms &
1711 (G_PART_PARM_GEOM | G_PART_PARM_PROVIDER);
1712 }
1713 if (!strcmp(ap->name, "attrib"))
1714 parm = G_PART_PARM_ATTRIB;
1715 break;
1716 case 'b':
1717 if (!strcmp(ap->name, "bootcode"))
1718 parm = G_PART_PARM_BOOTCODE;
1719 break;
1720 case 'c':
1721 if (!strcmp(ap->name, "class"))
1722 continue;
1723 break;
1724 case 'e':
1725 if (!strcmp(ap->name, "entries"))
1726 parm = G_PART_PARM_ENTRIES;
1727 break;
1728 case 'f':
1729 if (!strcmp(ap->name, "flags"))
1730 parm = G_PART_PARM_FLAGS;
1731 else if (!strcmp(ap->name, "force"))
1732 parm = G_PART_PARM_FORCE;
1733 break;
1734 case 'i':
1735 if (!strcmp(ap->name, "index"))
1736 parm = G_PART_PARM_INDEX;
1737 break;
1738 case 'l':
1739 if (!strcmp(ap->name, "label"))
1740 parm = G_PART_PARM_LABEL;
1741 break;
1742 case 'o':
1743 if (!strcmp(ap->name, "output"))
1744 parm = G_PART_PARM_OUTPUT;
1745 break;
1746 case 's':
1747 if (!strcmp(ap->name, "scheme"))
1748 parm = G_PART_PARM_SCHEME;
1749 else if (!strcmp(ap->name, "size"))
1750 parm = G_PART_PARM_SIZE;
1751 else if (!strcmp(ap->name, "start"))
1752 parm = G_PART_PARM_START;
1753 else if (!strcmp(ap->name, "skip_dsn"))
1754 parm = G_PART_PARM_SKIP_DSN;
1755 break;
1756 case 't':
1757 if (!strcmp(ap->name, "type"))
1758 parm = G_PART_PARM_TYPE;
1759 break;
1760 case 'v':
1761 if (!strcmp(ap->name, "verb"))
1762 continue;
1763 else if (!strcmp(ap->name, "version"))
1764 parm = G_PART_PARM_VERSION;
1765 break;
1766 }
1767 if ((parm & (mparms | oparms)) == 0) {
1768 gctl_error(req, "%d param '%s'", EINVAL, ap->name);
1769 return;
1770 }
1771 switch (parm) {
1772 case G_PART_PARM_ATTRIB:
1773 error = g_part_parm_str(req, ap->name,
1774 &gpp.gpp_attrib);
1775 break;
1776 case G_PART_PARM_BOOTCODE:
1777 error = g_part_parm_bootcode(req, ap->name,
1778 &gpp.gpp_codeptr, &gpp.gpp_codesize);
1779 break;
1780 case G_PART_PARM_ENTRIES:
1781 error = g_part_parm_intmax(req, ap->name,
1782 &gpp.gpp_entries);
1783 break;
1784 case G_PART_PARM_FLAGS:
1785 error = g_part_parm_str(req, ap->name, &gpp.gpp_flags);
1786 break;
1787 case G_PART_PARM_FORCE:
1788 error = g_part_parm_uint32(req, ap->name,
1789 &gpp.gpp_force);
1790 break;
1791 case G_PART_PARM_GEOM:
1792 error = g_part_parm_geom(req, ap->name, &gpp.gpp_geom);
1793 break;
1794 case G_PART_PARM_INDEX:
1795 error = g_part_parm_intmax(req, ap->name,
1796 &gpp.gpp_index);
1797 break;
1798 case G_PART_PARM_LABEL:
1799 error = g_part_parm_str(req, ap->name, &gpp.gpp_label);
1800 break;
1801 case G_PART_PARM_OUTPUT:
1802 error = 0; /* Write-only parameter */
1803 break;
1804 case G_PART_PARM_PROVIDER:
1805 error = g_part_parm_provider(req, ap->name,
1806 &gpp.gpp_provider);
1807 break;
1808 case G_PART_PARM_SCHEME:
1809 error = g_part_parm_scheme(req, ap->name,
1810 &gpp.gpp_scheme);
1811 break;
1812 case G_PART_PARM_SIZE:
1813 error = g_part_parm_quad(req, ap->name, &gpp.gpp_size);
1814 break;
1815 case G_PART_PARM_SKIP_DSN:
1816 error = g_part_parm_uint32(req, ap->name,
1817 &gpp.gpp_skip_dsn);
1818 break;
1819 case G_PART_PARM_START:
1820 error = g_part_parm_quad(req, ap->name,
1821 &gpp.gpp_start);
1822 break;
1823 case G_PART_PARM_TYPE:
1824 error = g_part_parm_str(req, ap->name, &gpp.gpp_type);
1825 break;
1826 case G_PART_PARM_VERSION:
1827 error = g_part_parm_uint32(req, ap->name,
1828 &gpp.gpp_version);
1829 break;
1830 default:
1831 error = EDOOFUS;
1832 gctl_error(req, "%d %s", error, ap->name);
1833 break;
1834 }
1835 if (error != 0) {
1836 if (error == ENOATTR) {
1837 gctl_error(req, "%d param '%s'", error,
1838 ap->name);
1839 }
1840 return;
1841 }
1842 gpp.gpp_parms |= parm;
1843 }
1844 if ((gpp.gpp_parms & mparms) != mparms) {
1845 parm = mparms - (gpp.gpp_parms & mparms);
1846 gctl_error(req, "%d param '%x'", ENOATTR, parm);
1847 return;
1848 }
1849
1850 /* Obtain permissions if possible/necessary. */
1851 close_on_error = 0;
1852 table = NULL;
1853 if (modifies && (gpp.gpp_parms & G_PART_PARM_GEOM)) {
1854 table = gpp.gpp_geom->softc;
1855 if (table != NULL && table->gpt_corrupt &&
1856 ctlreq != G_PART_CTL_DESTROY &&
1857 ctlreq != G_PART_CTL_RECOVER &&
1858 geom_part_check_integrity) {
1859 gctl_error(req, "%d table '%s' is corrupt",
1860 EPERM, gpp.gpp_geom->name);
1861 return;
1862 }
1863 if (table != NULL && !table->gpt_opened) {
1864 error = g_access(LIST_FIRST(&gpp.gpp_geom->consumer),
1865 1, 1, 1);
1866 if (error) {
1867 gctl_error(req, "%d geom '%s'", error,
1868 gpp.gpp_geom->name);
1869 return;
1870 }
1871 table->gpt_opened = 1;
1872 close_on_error = 1;
1873 }
1874 }
1875
1876 /* Allow the scheme to check or modify the parameters. */
1877 if (table != NULL) {
1878 error = G_PART_PRECHECK(table, ctlreq, &gpp);
1879 if (error) {
1880 gctl_error(req, "%d pre-check failed", error);
1881 goto out;
1882 }
1883 } else
1884 error = EDOOFUS; /* Prevent bogus uninit. warning. */
1885
1886 switch (ctlreq) {
1887 case G_PART_CTL_NONE:
1888 panic("%s", __func__);
1889 case G_PART_CTL_ADD:
1890 error = g_part_ctl_add(req, &gpp);
1891 break;
1892 case G_PART_CTL_BOOTCODE:
1893 error = g_part_ctl_bootcode(req, &gpp);
1894 break;
1895 case G_PART_CTL_COMMIT:
1896 error = g_part_ctl_commit(req, &gpp);
1897 break;
1898 case G_PART_CTL_CREATE:
1899 error = g_part_ctl_create(req, &gpp);
1900 break;
1901 case G_PART_CTL_DELETE:
1902 error = g_part_ctl_delete(req, &gpp);
1903 break;
1904 case G_PART_CTL_DESTROY:
1905 error = g_part_ctl_destroy(req, &gpp);
1906 break;
1907 case G_PART_CTL_MODIFY:
1908 error = g_part_ctl_modify(req, &gpp);
1909 break;
1910 case G_PART_CTL_MOVE:
1911 error = g_part_ctl_move(req, &gpp);
1912 break;
1913 case G_PART_CTL_RECOVER:
1914 error = g_part_ctl_recover(req, &gpp);
1915 break;
1916 case G_PART_CTL_RESIZE:
1917 error = g_part_ctl_resize(req, &gpp);
1918 break;
1919 case G_PART_CTL_SET:
1920 error = g_part_ctl_setunset(req, &gpp, 1);
1921 break;
1922 case G_PART_CTL_UNDO:
1923 error = g_part_ctl_undo(req, &gpp);
1924 break;
1925 case G_PART_CTL_UNSET:
1926 error = g_part_ctl_setunset(req, &gpp, 0);
1927 break;
1928 }
1929
1930 /* Implement automatic commit. */
1931 if (!error) {
1932 auto_commit = (modifies &&
1933 (gpp.gpp_parms & G_PART_PARM_FLAGS) &&
1934 strchr(gpp.gpp_flags, 'C') != NULL) ? 1 : 0;
1935 if (auto_commit) {
1936 KASSERT(gpp.gpp_parms & G_PART_PARM_GEOM, ("%s",
1937 __func__));
1938 error = g_part_ctl_commit(req, &gpp);
1939 }
1940 }
1941
1942 out:
1943 if (error && close_on_error) {
1944 g_access(LIST_FIRST(&gpp.gpp_geom->consumer), -1, -1, -1);
1945 table->gpt_opened = 0;
1946 }
1947 }
1948
1949 static int
1950 g_part_destroy_geom(struct gctl_req *req, struct g_class *mp,
1951 struct g_geom *gp)
1952 {
1953
1954 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, gp->name));
1955 g_topology_assert();
1956
1957 g_part_wither(gp, EINVAL);
1958 return (0);
1959 }
1960
1961 static struct g_geom *
1962 g_part_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
1963 {
1964 struct g_consumer *cp;
1965 struct g_geom *gp;
1966 struct g_part_entry *entry;
1967 struct g_part_table *table;
1968 struct root_hold_token *rht;
1969 int attr, depth;
1970 int error;
1971
1972 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s,%s)", __func__, mp->name, pp->name));
1973 g_topology_assert();
1974
1975 /* Skip providers that are already open for writing. */
1976 if (pp->acw > 0)
1977 return (NULL);
1978
1979 /*
1980 * Create a GEOM with consumer and hook it up to the provider.
1981 * With that we become part of the topology. Obtain read access
1982 * to the provider.
1983 */
1984 gp = g_new_geomf(mp, "%s", pp->name);
1985 cp = g_new_consumer(gp);
1986 cp->flags |= G_CF_DIRECT_SEND | G_CF_DIRECT_RECEIVE;
1987 error = g_attach(cp, pp);
1988 if (error == 0)
1989 error = g_access(cp, 1, 0, 0);
1990 if (error != 0) {
1991 if (cp->provider)
1992 g_detach(cp);
1993 g_destroy_consumer(cp);
1994 g_destroy_geom(gp);
1995 return (NULL);
1996 }
1997
1998 rht = root_mount_hold(mp->name);
1999 g_topology_unlock();
2000
2001 /*
2002 * Short-circuit the whole probing galore when there's no
2003 * media present.
2004 */
2005 if (pp->mediasize == 0 || pp->sectorsize == 0) {
2006 error = ENODEV;
2007 goto fail;
2008 }
2009
2010 /* Make sure we can nest and if so, determine our depth. */
2011 error = g_getattr("PART::isleaf", cp, &attr);
2012 if (!error && attr) {
2013 error = ENODEV;
2014 goto fail;
2015 }
2016 error = g_getattr("PART::depth", cp, &attr);
2017 depth = (!error) ? attr + 1 : 0;
2018
2019 error = g_part_probe(gp, cp, depth);
2020 if (error)
2021 goto fail;
2022
2023 table = gp->softc;
2024
2025 /*
2026 * Synthesize a disk geometry. Some partitioning schemes
2027 * depend on it and since some file systems need it even
2028 * when the partitition scheme doesn't, we do it here in
2029 * scheme-independent code.
2030 */
2031 g_part_geometry(table, cp, pp->mediasize / pp->sectorsize);
2032
2033 error = G_PART_READ(table, cp);
2034 if (error)
2035 goto fail;
2036 error = g_part_check_integrity(table, cp);
2037 if (error)
2038 goto fail;
2039
2040 g_topology_lock();
2041 LIST_FOREACH(entry, &table->gpt_entry, gpe_entry) {
2042 if (!entry->gpe_internal)
2043 g_part_new_provider(gp, table, entry);
2044 }
2045
2046 root_mount_rel(rht);
2047 g_access(cp, -1, 0, 0);
2048 return (gp);
2049
2050 fail:
2051 g_topology_lock();
2052 root_mount_rel(rht);
2053 g_access(cp, -1, 0, 0);
2054 g_detach(cp);
2055 g_destroy_consumer(cp);
2056 g_destroy_geom(gp);
2057 return (NULL);
2058 }
2059
2060 /*
2061 * Geom methods.
2062 */
2063
2064 static int
2065 g_part_access(struct g_provider *pp, int dr, int dw, int de)
2066 {
2067 struct g_consumer *cp;
2068
2069 G_PART_TRACE((G_T_ACCESS, "%s(%s,%d,%d,%d)", __func__, pp->name, dr,
2070 dw, de));
2071
2072 cp = LIST_FIRST(&pp->geom->consumer);
2073
2074 /* We always gain write-exclusive access. */
2075 return (g_access(cp, dr, dw, dw + de));
2076 }
2077
2078 static void
2079 g_part_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
2080 struct g_consumer *cp, struct g_provider *pp)
2081 {
2082 char buf[64];
2083 struct g_part_entry *entry;
2084 struct g_part_table *table;
2085
2086 KASSERT(sb != NULL && gp != NULL, ("%s", __func__));
2087 table = gp->softc;
2088
2089 if (indent == NULL) {
2090 KASSERT(cp == NULL && pp != NULL, ("%s", __func__));
2091 entry = pp->private;
2092 if (entry == NULL)
2093 return;
2094 sbuf_printf(sb, " i %u o %ju ty %s", entry->gpe_index,
2095 (uintmax_t)entry->gpe_offset,
2096 G_PART_TYPE(table, entry, buf, sizeof(buf)));
2097 /*
2098 * libdisk compatibility quirk - the scheme dumps the
2099 * slicer name and partition type in a way that is
2100 * compatible with libdisk. When libdisk is not used
2101 * anymore, this should go away.
2102 */
2103 G_PART_DUMPCONF(table, entry, sb, indent);
2104 } else if (cp != NULL) { /* Consumer configuration. */
2105 KASSERT(pp == NULL, ("%s", __func__));
2106 /* none */
2107 } else if (pp != NULL) { /* Provider configuration. */
2108 entry = pp->private;
2109 if (entry == NULL)
2110 return;
2111 sbuf_printf(sb, "%s<start>%ju</start>\n", indent,
2112 (uintmax_t)entry->gpe_start);
2113 sbuf_printf(sb, "%s<end>%ju</end>\n", indent,
2114 (uintmax_t)entry->gpe_end);
2115 sbuf_printf(sb, "%s<index>%u</index>\n", indent,
2116 entry->gpe_index);
2117 sbuf_printf(sb, "%s<type>%s</type>\n", indent,
2118 G_PART_TYPE(table, entry, buf, sizeof(buf)));
2119 sbuf_printf(sb, "%s<offset>%ju</offset>\n", indent,
2120 (uintmax_t)entry->gpe_offset);
2121 sbuf_printf(sb, "%s<length>%ju</length>\n", indent,
2122 (uintmax_t)pp->mediasize);
2123 G_PART_DUMPCONF(table, entry, sb, indent);
2124 } else { /* Geom configuration. */
2125 sbuf_printf(sb, "%s<scheme>%s</scheme>\n", indent,
2126 table->gpt_scheme->name);
2127 sbuf_printf(sb, "%s<entries>%u</entries>\n", indent,
2128 table->gpt_entries);
2129 sbuf_printf(sb, "%s<first>%ju</first>\n", indent,
2130 (uintmax_t)table->gpt_first);
2131 sbuf_printf(sb, "%s<last>%ju</last>\n", indent,
2132 (uintmax_t)table->gpt_last);
2133 sbuf_printf(sb, "%s<fwsectors>%u</fwsectors>\n", indent,
2134 table->gpt_sectors);
2135 sbuf_printf(sb, "%s<fwheads>%u</fwheads>\n", indent,
2136 table->gpt_heads);
2137 sbuf_printf(sb, "%s<state>%s</state>\n", indent,
2138 table->gpt_corrupt ? "CORRUPT": "OK");
2139 sbuf_printf(sb, "%s<modified>%s</modified>\n", indent,
2140 table->gpt_opened ? "true": "false");
2141 G_PART_DUMPCONF(table, NULL, sb, indent);
2142 }
2143 }
2144
2145 /*-
2146 * This start routine is only called for non-trivial requests, all the
2147 * trivial ones are handled autonomously by the slice code.
2148 * For requests we handle here, we must call the g_io_deliver() on the
2149 * bio, and return non-zero to indicate to the slice code that we did so.
2150 * This code executes in the "DOWN" I/O path, this means:
2151 * * No sleeping.
2152 * * Don't grab the topology lock.
2153 * * Don't call biowait, g_getattr(), g_setattr() or g_read_data()
2154 */
2155 static int
2156 g_part_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td)
2157 {
2158 struct g_part_table *table;
2159
2160 table = pp->geom->softc;
2161 return G_PART_IOCTL(table, pp, cmd, data, fflag, td);
2162 }
2163
2164 static void
2165 g_part_resize(struct g_consumer *cp)
2166 {
2167 struct g_part_table *table;
2168
2169 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name));
2170 g_topology_assert();
2171
2172 if (auto_resize == 0)
2173 return;
2174
2175 table = cp->geom->softc;
2176 if (table->gpt_opened == 0) {
2177 if (g_access(cp, 1, 1, 1) != 0)
2178 return;
2179 table->gpt_opened = 1;
2180 }
2181 if (G_PART_RESIZE(table, NULL, NULL) == 0)
2182 printf("GEOM_PART: %s was automatically resized.\n"
2183 " Use `gpart commit %s` to save changes or "
2184 "`gpart undo %s` to revert them.\n", cp->geom->name,
2185 cp->geom->name, cp->geom->name);
2186 if (g_part_check_integrity(table, cp) != 0) {
2187 g_access(cp, -1, -1, -1);
2188 table->gpt_opened = 0;
2189 g_part_wither(table->gpt_gp, ENXIO);
2190 }
2191 }
2192
2193 static void
2194 g_part_orphan(struct g_consumer *cp)
2195 {
2196 struct g_provider *pp;
2197 struct g_part_table *table;
2198
2199 pp = cp->provider;
2200 KASSERT(pp != NULL, ("%s", __func__));
2201 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, pp->name));
2202 g_topology_assert();
2203
2204 KASSERT(pp->error != 0, ("%s", __func__));
2205 table = cp->geom->softc;
2206 if (table != NULL && table->gpt_opened)
2207 g_access(cp, -1, -1, -1);
2208 g_part_wither(cp->geom, pp->error);
2209 }
2210
2211 static void
2212 g_part_spoiled(struct g_consumer *cp)
2213 {
2214
2215 G_PART_TRACE((G_T_TOPOLOGY, "%s(%s)", __func__, cp->provider->name));
2216 g_topology_assert();
2217
2218 cp->flags |= G_CF_ORPHAN;
2219 g_part_wither(cp->geom, ENXIO);
2220 }
2221
2222 static void
2223 g_part_start(struct bio *bp)
2224 {
2225 struct bio *bp2;
2226 struct g_consumer *cp;
2227 struct g_geom *gp;
2228 struct g_part_entry *entry;
2229 struct g_part_table *table;
2230 struct g_kerneldump *gkd;
2231 struct g_provider *pp;
2232 void (*done_func)(struct bio *) = g_std_done;
2233 char buf[64];
2234
2235 biotrack(bp, __func__);
2236
2237 pp = bp->bio_to;
2238 gp = pp->geom;
2239 table = gp->softc;
2240 cp = LIST_FIRST(&gp->consumer);
2241
2242 G_PART_TRACE((G_T_BIO, "%s: cmd=%d, provider=%s", __func__, bp->bio_cmd,
2243 pp->name));
2244
2245 entry = pp->private;
2246 if (entry == NULL) {
2247 g_io_deliver(bp, ENXIO);
2248 return;
2249 }
2250
2251 switch(bp->bio_cmd) {
2252 case BIO_DELETE:
2253 case BIO_READ:
2254 case BIO_WRITE:
2255 if (bp->bio_offset >= pp->mediasize) {
2256 g_io_deliver(bp, EIO);
2257 return;
2258 }
2259 bp2 = g_clone_bio(bp);
2260 if (bp2 == NULL) {
2261 g_io_deliver(bp, ENOMEM);
2262 return;
2263 }
2264 if (bp2->bio_offset + bp2->bio_length > pp->mediasize)
2265 bp2->bio_length = pp->mediasize - bp2->bio_offset;
2266 bp2->bio_done = g_std_done;
2267 bp2->bio_offset += entry->gpe_offset;
2268 g_io_request(bp2, cp);
2269 return;
2270 case BIO_SPEEDUP:
2271 case BIO_FLUSH:
2272 break;
2273 case BIO_GETATTR:
2274 if (g_handleattr_int(bp, "GEOM::fwheads", table->gpt_heads))
2275 return;
2276 if (g_handleattr_int(bp, "GEOM::fwsectors", table->gpt_sectors))
2277 return;
2278 /*
2279 * allow_nesting overrides "isleaf" to false _unless_ the
2280 * provider offset is zero, since otherwise we would recurse.
2281 */
2282 if (g_handleattr_int(bp, "PART::isleaf",
2283 table->gpt_isleaf &&
2284 (allow_nesting == 0 || entry->gpe_offset == 0)))
2285 return;
2286 if (g_handleattr_int(bp, "PART::depth", table->gpt_depth))
2287 return;
2288 if (g_handleattr_str(bp, "PART::scheme",
2289 table->gpt_scheme->name))
2290 return;
2291 if (g_handleattr_str(bp, "PART::type",
2292 G_PART_TYPE(table, entry, buf, sizeof(buf))))
2293 return;
2294 if (!strcmp("GEOM::physpath", bp->bio_attribute)) {
2295 done_func = g_part_get_physpath_done;
2296 break;
2297 }
2298 if (!strcmp("GEOM::kerneldump", bp->bio_attribute)) {
2299 /*
2300 * Check that the partition is suitable for kernel
2301 * dumps. Typically only swap partitions should be
2302 * used. If the request comes from the nested scheme
2303 * we allow dumping there as well.
2304 */
2305 if ((bp->bio_from == NULL ||
2306 bp->bio_from->geom->class != &g_part_class) &&
2307 G_PART_DUMPTO(table, entry) == 0) {
2308 g_io_deliver(bp, ENODEV);
2309 printf("GEOM_PART: Partition '%s' not suitable"
2310 " for kernel dumps (wrong type?)\n",
2311 pp->name);
2312 return;
2313 }
2314 gkd = (struct g_kerneldump *)bp->bio_data;
2315 if (gkd->offset >= pp->mediasize) {
2316 g_io_deliver(bp, EIO);
2317 return;
2318 }
2319 if (gkd->offset + gkd->length > pp->mediasize)
2320 gkd->length = pp->mediasize - gkd->offset;
2321 gkd->offset += entry->gpe_offset;
2322 }
2323 break;
2324 default:
2325 g_io_deliver(bp, EOPNOTSUPP);
2326 return;
2327 }
2328
2329 bp2 = g_clone_bio(bp);
2330 if (bp2 == NULL) {
2331 g_io_deliver(bp, ENOMEM);
2332 return;
2333 }
2334 bp2->bio_done = done_func;
2335 g_io_request(bp2, cp);
2336 }
2337
2338 static void
2339 g_part_init(struct g_class *mp)
2340 {
2341
2342 TAILQ_INSERT_HEAD(&g_part_schemes, &g_part_null_scheme, scheme_list);
2343 }
2344
2345 static void
2346 g_part_fini(struct g_class *mp)
2347 {
2348
2349 TAILQ_REMOVE(&g_part_schemes, &g_part_null_scheme, scheme_list);
2350 }
2351
2352 static void
2353 g_part_unload_event(void *arg, int flag)
2354 {
2355 struct g_consumer *cp;
2356 struct g_geom *gp;
2357 struct g_provider *pp;
2358 struct g_part_scheme *scheme;
2359 struct g_part_table *table;
2360 uintptr_t *xchg;
2361 int acc, error;
2362
2363 if (flag == EV_CANCEL)
2364 return;
2365
2366 xchg = arg;
2367 error = 0;
2368 scheme = (void *)(*xchg);
2369
2370 g_topology_assert();
2371
2372 LIST_FOREACH(gp, &g_part_class.geom, geom) {
2373 table = gp->softc;
2374 if (table->gpt_scheme != scheme)
2375 continue;
2376
2377 acc = 0;
2378 LIST_FOREACH(pp, &gp->provider, provider)
2379 acc += pp->acr + pp->acw + pp->ace;
2380 LIST_FOREACH(cp, &gp->consumer, consumer)
2381 acc += cp->acr + cp->acw + cp->ace;
2382
2383 if (!acc)
2384 g_part_wither(gp, ENOSYS);
2385 else
2386 error = EBUSY;
2387 }
2388
2389 if (!error)
2390 TAILQ_REMOVE(&g_part_schemes, scheme, scheme_list);
2391
2392 *xchg = error;
2393 }
2394
2395 int
2396 g_part_modevent(module_t mod, int type, struct g_part_scheme *scheme)
2397 {
2398 struct g_part_scheme *iter;
2399 uintptr_t arg;
2400 int error;
2401
2402 error = 0;
2403 switch (type) {
2404 case MOD_LOAD:
2405 TAILQ_FOREACH(iter, &g_part_schemes, scheme_list) {
2406 if (scheme == iter) {
2407 printf("GEOM_PART: scheme %s is already "
2408 "registered!\n", scheme->name);
2409 break;
2410 }
2411 }
2412 if (iter == NULL) {
2413 TAILQ_INSERT_TAIL(&g_part_schemes, scheme,
2414 scheme_list);
2415 g_retaste(&g_part_class);
2416 }
2417 break;
2418 case MOD_UNLOAD:
2419 arg = (uintptr_t)scheme;
2420 error = g_waitfor_event(g_part_unload_event, &arg, M_WAITOK,
2421 NULL);
2422 if (error == 0)
2423 error = arg;
2424 break;
2425 default:
2426 error = EOPNOTSUPP;
2427 break;
2428 }
2429
2430 return (error);
2431 }
Cache object: 56eb0383af000f00ce59ef0b5c0962b5
|