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, §ors) != 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, §ors) != 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;
|
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}
|