diff options
Diffstat (limited to 'fs/partitions/check.c')
| -rw-r--r-- | fs/partitions/check.c | 272 |
1 files changed, 159 insertions, 113 deletions
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 7d6b34e201db..7408227c49c9 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
| @@ -120,22 +120,21 @@ static int (*check_part[])(struct parsed_partitions *, struct block_device *) = | |||
| 120 | * a pointer to that same buffer (for convenience). | 120 | * a pointer to that same buffer (for convenience). |
| 121 | */ | 121 | */ |
| 122 | 122 | ||
| 123 | char *disk_name(struct gendisk *hd, int part, char *buf) | 123 | char *disk_name(struct gendisk *hd, int partno, char *buf) |
| 124 | { | 124 | { |
| 125 | if (!part) | 125 | if (!partno) |
| 126 | snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name); | 126 | snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name); |
| 127 | else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) | 127 | else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) |
| 128 | snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, part); | 128 | snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno); |
| 129 | else | 129 | else |
| 130 | snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, part); | 130 | snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno); |
| 131 | 131 | ||
| 132 | return buf; | 132 | return buf; |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | const char *bdevname(struct block_device *bdev, char *buf) | 135 | const char *bdevname(struct block_device *bdev, char *buf) |
| 136 | { | 136 | { |
| 137 | int part = MINOR(bdev->bd_dev) - bdev->bd_disk->first_minor; | 137 | return disk_name(bdev->bd_disk, bdev->bd_part->partno, buf); |
| 138 | return disk_name(bdev->bd_disk, part, buf); | ||
| 139 | } | 138 | } |
| 140 | 139 | ||
| 141 | EXPORT_SYMBOL(bdevname); | 140 | EXPORT_SYMBOL(bdevname); |
| @@ -169,7 +168,7 @@ check_partition(struct gendisk *hd, struct block_device *bdev) | |||
| 169 | if (isdigit(state->name[strlen(state->name)-1])) | 168 | if (isdigit(state->name[strlen(state->name)-1])) |
| 170 | sprintf(state->name, "p"); | 169 | sprintf(state->name, "p"); |
| 171 | 170 | ||
| 172 | state->limit = hd->minors; | 171 | state->limit = disk_max_parts(hd); |
| 173 | i = res = err = 0; | 172 | i = res = err = 0; |
| 174 | while (!res && check_part[i]) { | 173 | while (!res && check_part[i]) { |
| 175 | memset(&state->parts, 0, sizeof(state->parts)); | 174 | memset(&state->parts, 0, sizeof(state->parts)); |
| @@ -204,21 +203,22 @@ static ssize_t part_start_show(struct device *dev, | |||
| 204 | return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect); | 203 | return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect); |
| 205 | } | 204 | } |
| 206 | 205 | ||
| 207 | static ssize_t part_size_show(struct device *dev, | 206 | ssize_t part_size_show(struct device *dev, |
| 208 | struct device_attribute *attr, char *buf) | 207 | struct device_attribute *attr, char *buf) |
| 209 | { | 208 | { |
| 210 | struct hd_struct *p = dev_to_part(dev); | 209 | struct hd_struct *p = dev_to_part(dev); |
| 211 | return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects); | 210 | return sprintf(buf, "%llu\n",(unsigned long long)p->nr_sects); |
| 212 | } | 211 | } |
| 213 | 212 | ||
| 214 | static ssize_t part_stat_show(struct device *dev, | 213 | ssize_t part_stat_show(struct device *dev, |
| 215 | struct device_attribute *attr, char *buf) | 214 | struct device_attribute *attr, char *buf) |
| 216 | { | 215 | { |
| 217 | struct hd_struct *p = dev_to_part(dev); | 216 | struct hd_struct *p = dev_to_part(dev); |
| 217 | int cpu; | ||
| 218 | 218 | ||
| 219 | preempt_disable(); | 219 | cpu = part_stat_lock(); |
| 220 | part_round_stats(p); | 220 | part_round_stats(cpu, p); |
| 221 | preempt_enable(); | 221 | part_stat_unlock(); |
| 222 | return sprintf(buf, | 222 | return sprintf(buf, |
| 223 | "%8lu %8lu %8llu %8u " | 223 | "%8lu %8lu %8llu %8u " |
| 224 | "%8lu %8lu %8llu %8u " | 224 | "%8lu %8lu %8llu %8u " |
| @@ -238,17 +238,17 @@ static ssize_t part_stat_show(struct device *dev, | |||
| 238 | } | 238 | } |
| 239 | 239 | ||
| 240 | #ifdef CONFIG_FAIL_MAKE_REQUEST | 240 | #ifdef CONFIG_FAIL_MAKE_REQUEST |
| 241 | static ssize_t part_fail_show(struct device *dev, | 241 | ssize_t part_fail_show(struct device *dev, |
| 242 | struct device_attribute *attr, char *buf) | 242 | struct device_attribute *attr, char *buf) |
| 243 | { | 243 | { |
| 244 | struct hd_struct *p = dev_to_part(dev); | 244 | struct hd_struct *p = dev_to_part(dev); |
| 245 | 245 | ||
| 246 | return sprintf(buf, "%d\n", p->make_it_fail); | 246 | return sprintf(buf, "%d\n", p->make_it_fail); |
| 247 | } | 247 | } |
| 248 | 248 | ||
| 249 | static ssize_t part_fail_store(struct device *dev, | 249 | ssize_t part_fail_store(struct device *dev, |
| 250 | struct device_attribute *attr, | 250 | struct device_attribute *attr, |
| 251 | const char *buf, size_t count) | 251 | const char *buf, size_t count) |
| 252 | { | 252 | { |
| 253 | struct hd_struct *p = dev_to_part(dev); | 253 | struct hd_struct *p = dev_to_part(dev); |
| 254 | int i; | 254 | int i; |
| @@ -300,40 +300,34 @@ struct device_type part_type = { | |||
| 300 | .release = part_release, | 300 | .release = part_release, |
| 301 | }; | 301 | }; |
| 302 | 302 | ||
| 303 | static inline void partition_sysfs_add_subdir(struct hd_struct *p) | 303 | static void delete_partition_rcu_cb(struct rcu_head *head) |
| 304 | { | ||
| 305 | struct kobject *k; | ||
| 306 | |||
| 307 | k = kobject_get(&p->dev.kobj); | ||
| 308 | p->holder_dir = kobject_create_and_add("holders", k); | ||
| 309 | kobject_put(k); | ||
| 310 | } | ||
| 311 | |||
| 312 | static inline void disk_sysfs_add_subdirs(struct gendisk *disk) | ||
| 313 | { | 304 | { |
| 314 | struct kobject *k; | 305 | struct hd_struct *part = container_of(head, struct hd_struct, rcu_head); |
| 315 | 306 | ||
| 316 | k = kobject_get(&disk->dev.kobj); | 307 | part->start_sect = 0; |
| 317 | disk->holder_dir = kobject_create_and_add("holders", k); | 308 | part->nr_sects = 0; |
| 318 | disk->slave_dir = kobject_create_and_add("slaves", k); | 309 | part_stat_set_all(part, 0); |
| 319 | kobject_put(k); | 310 | put_device(part_to_dev(part)); |
| 320 | } | 311 | } |
| 321 | 312 | ||
| 322 | void delete_partition(struct gendisk *disk, int part) | 313 | void delete_partition(struct gendisk *disk, int partno) |
| 323 | { | 314 | { |
| 324 | struct hd_struct *p = disk->part[part-1]; | 315 | struct disk_part_tbl *ptbl = disk->part_tbl; |
| 316 | struct hd_struct *part; | ||
| 325 | 317 | ||
| 326 | if (!p) | 318 | if (partno >= ptbl->len) |
| 327 | return; | 319 | return; |
| 328 | if (!p->nr_sects) | 320 | |
| 321 | part = ptbl->part[partno]; | ||
| 322 | if (!part) | ||
| 329 | return; | 323 | return; |
| 330 | disk->part[part-1] = NULL; | 324 | |
| 331 | p->start_sect = 0; | 325 | blk_free_devt(part_devt(part)); |
| 332 | p->nr_sects = 0; | 326 | rcu_assign_pointer(ptbl->part[partno], NULL); |
| 333 | part_stat_set_all(p, 0); | 327 | kobject_put(part->holder_dir); |
| 334 | kobject_put(p->holder_dir); | 328 | device_del(part_to_dev(part)); |
| 335 | device_del(&p->dev); | 329 | |
| 336 | put_device(&p->dev); | 330 | call_rcu(&part->rcu_head, delete_partition_rcu_cb); |
| 337 | } | 331 | } |
| 338 | 332 | ||
| 339 | static ssize_t whole_disk_show(struct device *dev, | 333 | static ssize_t whole_disk_show(struct device *dev, |
| @@ -344,102 +338,132 @@ static ssize_t whole_disk_show(struct device *dev, | |||
| 344 | static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH, | 338 | static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH, |
| 345 | whole_disk_show, NULL); | 339 | whole_disk_show, NULL); |
| 346 | 340 | ||
| 347 | int add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags) | 341 | int add_partition(struct gendisk *disk, int partno, |
| 342 | sector_t start, sector_t len, int flags) | ||
| 348 | { | 343 | { |
| 349 | struct hd_struct *p; | 344 | struct hd_struct *p; |
| 345 | dev_t devt = MKDEV(0, 0); | ||
| 346 | struct device *ddev = disk_to_dev(disk); | ||
| 347 | struct device *pdev; | ||
| 348 | struct disk_part_tbl *ptbl; | ||
| 349 | const char *dname; | ||
| 350 | int err; | 350 | int err; |
| 351 | 351 | ||
| 352 | err = disk_expand_part_tbl(disk, partno); | ||
| 353 | if (err) | ||
| 354 | return err; | ||
| 355 | ptbl = disk->part_tbl; | ||
| 356 | |||
| 357 | if (ptbl->part[partno]) | ||
| 358 | return -EBUSY; | ||
| 359 | |||
| 352 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 360 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
| 353 | if (!p) | 361 | if (!p) |
| 354 | return -ENOMEM; | 362 | return -ENOMEM; |
| 355 | 363 | ||
| 356 | if (!init_part_stats(p)) { | 364 | if (!init_part_stats(p)) { |
| 357 | err = -ENOMEM; | 365 | err = -ENOMEM; |
| 358 | goto out0; | 366 | goto out_free; |
| 359 | } | 367 | } |
| 368 | pdev = part_to_dev(p); | ||
| 369 | |||
| 360 | p->start_sect = start; | 370 | p->start_sect = start; |
| 361 | p->nr_sects = len; | 371 | p->nr_sects = len; |
| 362 | p->partno = part; | 372 | p->partno = partno; |
| 363 | p->policy = disk->policy; | 373 | p->policy = get_disk_ro(disk); |
| 364 | 374 | ||
| 365 | if (isdigit(disk->dev.bus_id[strlen(disk->dev.bus_id)-1])) | 375 | dname = dev_name(ddev); |
| 366 | snprintf(p->dev.bus_id, BUS_ID_SIZE, | 376 | if (isdigit(dname[strlen(dname) - 1])) |
| 367 | "%sp%d", disk->dev.bus_id, part); | 377 | snprintf(pdev->bus_id, BUS_ID_SIZE, "%sp%d", dname, partno); |
| 368 | else | 378 | else |
| 369 | snprintf(p->dev.bus_id, BUS_ID_SIZE, | 379 | snprintf(pdev->bus_id, BUS_ID_SIZE, "%s%d", dname, partno); |
| 370 | "%s%d", disk->dev.bus_id, part); | 380 | |
| 381 | device_initialize(pdev); | ||
| 382 | pdev->class = &block_class; | ||
| 383 | pdev->type = &part_type; | ||
| 384 | pdev->parent = ddev; | ||
| 371 | 385 | ||
| 372 | device_initialize(&p->dev); | 386 | err = blk_alloc_devt(p, &devt); |
| 373 | p->dev.devt = MKDEV(disk->major, disk->first_minor + part); | 387 | if (err) |
| 374 | p->dev.class = &block_class; | 388 | goto out_free; |
| 375 | p->dev.type = &part_type; | 389 | pdev->devt = devt; |
| 376 | p->dev.parent = &disk->dev; | ||
| 377 | disk->part[part-1] = p; | ||
| 378 | 390 | ||
| 379 | /* delay uevent until 'holders' subdir is created */ | 391 | /* delay uevent until 'holders' subdir is created */ |
| 380 | p->dev.uevent_suppress = 1; | 392 | pdev->uevent_suppress = 1; |
| 381 | err = device_add(&p->dev); | 393 | err = device_add(pdev); |
| 382 | if (err) | 394 | if (err) |
| 383 | goto out1; | 395 | goto out_put; |
| 384 | partition_sysfs_add_subdir(p); | 396 | |
| 385 | p->dev.uevent_suppress = 0; | 397 | err = -ENOMEM; |
| 398 | p->holder_dir = kobject_create_and_add("holders", &pdev->kobj); | ||
| 399 | if (!p->holder_dir) | ||
| 400 | goto out_del; | ||
| 401 | |||
| 402 | pdev->uevent_suppress = 0; | ||
| 386 | if (flags & ADDPART_FLAG_WHOLEDISK) { | 403 | if (flags & ADDPART_FLAG_WHOLEDISK) { |
| 387 | err = device_create_file(&p->dev, &dev_attr_whole_disk); | 404 | err = device_create_file(pdev, &dev_attr_whole_disk); |
| 388 | if (err) | 405 | if (err) |
| 389 | goto out2; | 406 | goto out_del; |
| 390 | } | 407 | } |
| 391 | 408 | ||
| 409 | /* everything is up and running, commence */ | ||
| 410 | INIT_RCU_HEAD(&p->rcu_head); | ||
| 411 | rcu_assign_pointer(ptbl->part[partno], p); | ||
| 412 | |||
| 392 | /* suppress uevent if the disk supresses it */ | 413 | /* suppress uevent if the disk supresses it */ |
| 393 | if (!disk->dev.uevent_suppress) | 414 | if (!ddev->uevent_suppress) |
| 394 | kobject_uevent(&p->dev.kobj, KOBJ_ADD); | 415 | kobject_uevent(&pdev->kobj, KOBJ_ADD); |
| 395 | 416 | ||
| 396 | return 0; | 417 | return 0; |
| 397 | 418 | ||
| 398 | out2: | 419 | out_free: |
| 399 | device_del(&p->dev); | ||
| 400 | out1: | ||
| 401 | put_device(&p->dev); | ||
| 402 | free_part_stats(p); | ||
| 403 | out0: | ||
| 404 | kfree(p); | 420 | kfree(p); |
| 405 | return err; | 421 | return err; |
| 422 | out_del: | ||
| 423 | kobject_put(p->holder_dir); | ||
| 424 | device_del(pdev); | ||
| 425 | out_put: | ||
| 426 | put_device(pdev); | ||
| 427 | blk_free_devt(devt); | ||
| 428 | return err; | ||
| 406 | } | 429 | } |
| 407 | 430 | ||
| 408 | /* Not exported, helper to add_disk(). */ | 431 | /* Not exported, helper to add_disk(). */ |
| 409 | void register_disk(struct gendisk *disk) | 432 | void register_disk(struct gendisk *disk) |
| 410 | { | 433 | { |
| 434 | struct device *ddev = disk_to_dev(disk); | ||
| 411 | struct block_device *bdev; | 435 | struct block_device *bdev; |
| 436 | struct disk_part_iter piter; | ||
| 437 | struct hd_struct *part; | ||
| 412 | char *s; | 438 | char *s; |
| 413 | int i; | ||
| 414 | struct hd_struct *p; | ||
| 415 | int err; | 439 | int err; |
| 416 | 440 | ||
| 417 | disk->dev.parent = disk->driverfs_dev; | 441 | ddev->parent = disk->driverfs_dev; |
| 418 | disk->dev.devt = MKDEV(disk->major, disk->first_minor); | ||
| 419 | 442 | ||
| 420 | strlcpy(disk->dev.bus_id, disk->disk_name, BUS_ID_SIZE); | 443 | strlcpy(ddev->bus_id, disk->disk_name, BUS_ID_SIZE); |
| 421 | /* ewww... some of these buggers have / in the name... */ | 444 | /* ewww... some of these buggers have / in the name... */ |
| 422 | s = strchr(disk->dev.bus_id, '/'); | 445 | s = strchr(ddev->bus_id, '/'); |
| 423 | if (s) | 446 | if (s) |
| 424 | *s = '!'; | 447 | *s = '!'; |
| 425 | 448 | ||
| 426 | /* delay uevents, until we scanned partition table */ | 449 | /* delay uevents, until we scanned partition table */ |
| 427 | disk->dev.uevent_suppress = 1; | 450 | ddev->uevent_suppress = 1; |
| 428 | 451 | ||
| 429 | if (device_add(&disk->dev)) | 452 | if (device_add(ddev)) |
| 430 | return; | 453 | return; |
| 431 | #ifndef CONFIG_SYSFS_DEPRECATED | 454 | #ifndef CONFIG_SYSFS_DEPRECATED |
| 432 | err = sysfs_create_link(block_depr, &disk->dev.kobj, | 455 | err = sysfs_create_link(block_depr, &ddev->kobj, |
| 433 | kobject_name(&disk->dev.kobj)); | 456 | kobject_name(&ddev->kobj)); |
| 434 | if (err) { | 457 | if (err) { |
| 435 | device_del(&disk->dev); | 458 | device_del(ddev); |
| 436 | return; | 459 | return; |
| 437 | } | 460 | } |
| 438 | #endif | 461 | #endif |
| 439 | disk_sysfs_add_subdirs(disk); | 462 | disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj); |
| 463 | disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); | ||
| 440 | 464 | ||
| 441 | /* No minors to use for partitions */ | 465 | /* No minors to use for partitions */ |
| 442 | if (disk->minors == 1) | 466 | if (!disk_partitionable(disk)) |
| 443 | goto exit; | 467 | goto exit; |
| 444 | 468 | ||
| 445 | /* No such device (e.g., media were just removed) */ | 469 | /* No such device (e.g., media were just removed) */ |
| @@ -458,50 +482,66 @@ void register_disk(struct gendisk *disk) | |||
| 458 | 482 | ||
| 459 | exit: | 483 | exit: |
| 460 | /* announce disk after possible partitions are created */ | 484 | /* announce disk after possible partitions are created */ |
| 461 | disk->dev.uevent_suppress = 0; | 485 | ddev->uevent_suppress = 0; |
| 462 | kobject_uevent(&disk->dev.kobj, KOBJ_ADD); | 486 | kobject_uevent(&ddev->kobj, KOBJ_ADD); |
| 463 | 487 | ||
| 464 | /* announce possible partitions */ | 488 | /* announce possible partitions */ |
| 465 | for (i = 1; i < disk->minors; i++) { | 489 | disk_part_iter_init(&piter, disk, 0); |
| 466 | p = disk->part[i-1]; | 490 | while ((part = disk_part_iter_next(&piter))) |
| 467 | if (!p || !p->nr_sects) | 491 | kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD); |
| 468 | continue; | 492 | disk_part_iter_exit(&piter); |
| 469 | kobject_uevent(&p->dev.kobj, KOBJ_ADD); | ||
| 470 | } | ||
| 471 | } | 493 | } |
| 472 | 494 | ||
| 473 | int rescan_partitions(struct gendisk *disk, struct block_device *bdev) | 495 | int rescan_partitions(struct gendisk *disk, struct block_device *bdev) |
| 474 | { | 496 | { |
| 497 | struct disk_part_iter piter; | ||
| 498 | struct hd_struct *part; | ||
| 475 | struct parsed_partitions *state; | 499 | struct parsed_partitions *state; |
| 476 | int p, res; | 500 | int p, highest, res; |
| 477 | 501 | ||
| 478 | if (bdev->bd_part_count) | 502 | if (bdev->bd_part_count) |
| 479 | return -EBUSY; | 503 | return -EBUSY; |
| 480 | res = invalidate_partition(disk, 0); | 504 | res = invalidate_partition(disk, 0); |
| 481 | if (res) | 505 | if (res) |
| 482 | return res; | 506 | return res; |
| 483 | bdev->bd_invalidated = 0; | 507 | |
| 484 | for (p = 1; p < disk->minors; p++) | 508 | disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); |
| 485 | delete_partition(disk, p); | 509 | while ((part = disk_part_iter_next(&piter))) |
| 510 | delete_partition(disk, part->partno); | ||
| 511 | disk_part_iter_exit(&piter); | ||
| 512 | |||
| 486 | if (disk->fops->revalidate_disk) | 513 | if (disk->fops->revalidate_disk) |
| 487 | disk->fops->revalidate_disk(disk); | 514 | disk->fops->revalidate_disk(disk); |
| 515 | check_disk_size_change(disk, bdev); | ||
| 516 | bdev->bd_invalidated = 0; | ||
| 488 | if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) | 517 | if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) |
| 489 | return 0; | 518 | return 0; |
| 490 | if (IS_ERR(state)) /* I/O error reading the partition table */ | 519 | if (IS_ERR(state)) /* I/O error reading the partition table */ |
| 491 | return -EIO; | 520 | return -EIO; |
| 492 | 521 | ||
| 493 | /* tell userspace that the media / partition table may have changed */ | 522 | /* tell userspace that the media / partition table may have changed */ |
| 494 | kobject_uevent(&disk->dev.kobj, KOBJ_CHANGE); | 523 | kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE); |
| 495 | 524 | ||
| 525 | /* Detect the highest partition number and preallocate | ||
| 526 | * disk->part_tbl. This is an optimization and not strictly | ||
| 527 | * necessary. | ||
| 528 | */ | ||
| 529 | for (p = 1, highest = 0; p < state->limit; p++) | ||
| 530 | if (state->parts[p].size) | ||
| 531 | highest = p; | ||
| 532 | |||
| 533 | disk_expand_part_tbl(disk, highest); | ||
| 534 | |||
| 535 | /* add partitions */ | ||
| 496 | for (p = 1; p < state->limit; p++) { | 536 | for (p = 1; p < state->limit; p++) { |
| 497 | sector_t size = state->parts[p].size; | 537 | sector_t size = state->parts[p].size; |
| 498 | sector_t from = state->parts[p].from; | 538 | sector_t from = state->parts[p].from; |
| 499 | if (!size) | 539 | if (!size) |
| 500 | continue; | 540 | continue; |
| 501 | if (from + size > get_capacity(disk)) { | 541 | if (from + size > get_capacity(disk)) { |
| 502 | printk(KERN_ERR " %s: p%d exceeds device capacity\n", | 542 | printk(KERN_WARNING |
| 543 | "%s: p%d exceeds device capacity\n", | ||
| 503 | disk->disk_name, p); | 544 | disk->disk_name, p); |
| 504 | continue; | ||
| 505 | } | 545 | } |
| 506 | res = add_partition(disk, p, from, size, state->parts[p].flags); | 546 | res = add_partition(disk, p, from, size, state->parts[p].flags); |
| 507 | if (res) { | 547 | if (res) { |
| @@ -541,25 +581,31 @@ EXPORT_SYMBOL(read_dev_sector); | |||
| 541 | 581 | ||
| 542 | void del_gendisk(struct gendisk *disk) | 582 | void del_gendisk(struct gendisk *disk) |
| 543 | { | 583 | { |
| 544 | int p; | 584 | struct disk_part_iter piter; |
| 585 | struct hd_struct *part; | ||
| 545 | 586 | ||
| 546 | /* invalidate stuff */ | 587 | /* invalidate stuff */ |
| 547 | for (p = disk->minors - 1; p > 0; p--) { | 588 | disk_part_iter_init(&piter, disk, |
| 548 | invalidate_partition(disk, p); | 589 | DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE); |
| 549 | delete_partition(disk, p); | 590 | while ((part = disk_part_iter_next(&piter))) { |
| 591 | invalidate_partition(disk, part->partno); | ||
| 592 | delete_partition(disk, part->partno); | ||
| 550 | } | 593 | } |
| 594 | disk_part_iter_exit(&piter); | ||
| 595 | |||
| 551 | invalidate_partition(disk, 0); | 596 | invalidate_partition(disk, 0); |
| 552 | disk->capacity = 0; | 597 | blk_free_devt(disk_to_dev(disk)->devt); |
| 598 | set_capacity(disk, 0); | ||
| 553 | disk->flags &= ~GENHD_FL_UP; | 599 | disk->flags &= ~GENHD_FL_UP; |
| 554 | unlink_gendisk(disk); | 600 | unlink_gendisk(disk); |
| 555 | disk_stat_set_all(disk, 0); | 601 | part_stat_set_all(&disk->part0, 0); |
| 556 | disk->stamp = 0; | 602 | disk->part0.stamp = 0; |
| 557 | 603 | ||
| 558 | kobject_put(disk->holder_dir); | 604 | kobject_put(disk->part0.holder_dir); |
| 559 | kobject_put(disk->slave_dir); | 605 | kobject_put(disk->slave_dir); |
| 560 | disk->driverfs_dev = NULL; | 606 | disk->driverfs_dev = NULL; |
| 561 | #ifndef CONFIG_SYSFS_DEPRECATED | 607 | #ifndef CONFIG_SYSFS_DEPRECATED |
| 562 | sysfs_remove_link(block_depr, disk->dev.bus_id); | 608 | sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); |
| 563 | #endif | 609 | #endif |
| 564 | device_del(&disk->dev); | 610 | device_del(disk_to_dev(disk)); |
| 565 | } | 611 | } |
