diff options
Diffstat (limited to 'fs/partitions')
-rw-r--r-- | fs/partitions/check.c | 70 |
1 files changed, 45 insertions, 25 deletions
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index e77fa144a07d..96c8bf41e455 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
@@ -314,19 +314,29 @@ static inline void disk_sysfs_add_subdirs(struct gendisk *disk) | |||
314 | kobject_put(k); | 314 | kobject_put(k); |
315 | } | 315 | } |
316 | 316 | ||
317 | static void delete_partition_rcu_cb(struct rcu_head *head) | ||
318 | { | ||
319 | struct hd_struct *part = container_of(head, struct hd_struct, rcu_head); | ||
320 | |||
321 | part->start_sect = 0; | ||
322 | part->nr_sects = 0; | ||
323 | part_stat_set_all(part, 0); | ||
324 | put_device(&part->dev); | ||
325 | } | ||
326 | |||
317 | void delete_partition(struct gendisk *disk, int partno) | 327 | void delete_partition(struct gendisk *disk, int partno) |
318 | { | 328 | { |
319 | struct hd_struct *p = disk->part[partno - 1]; | 329 | struct hd_struct *part; |
320 | 330 | ||
321 | if (!p) | 331 | part = disk->__part[partno-1]; |
332 | if (!part) | ||
322 | return; | 333 | return; |
323 | disk->part[partno - 1] = NULL; | 334 | |
324 | p->start_sect = 0; | 335 | rcu_assign_pointer(disk->__part[partno-1], NULL); |
325 | p->nr_sects = 0; | 336 | kobject_put(part->holder_dir); |
326 | part_stat_set_all(p, 0); | 337 | device_del(&part->dev); |
327 | kobject_put(p->holder_dir); | 338 | |
328 | device_del(&p->dev); | 339 | call_rcu(&part->rcu_head, delete_partition_rcu_cb); |
329 | put_device(&p->dev); | ||
330 | } | 340 | } |
331 | 341 | ||
332 | static ssize_t whole_disk_show(struct device *dev, | 342 | static ssize_t whole_disk_show(struct device *dev, |
@@ -343,7 +353,7 @@ int add_partition(struct gendisk *disk, int partno, | |||
343 | struct hd_struct *p; | 353 | struct hd_struct *p; |
344 | int err; | 354 | int err; |
345 | 355 | ||
346 | if (disk->part[partno - 1]) | 356 | if (disk->__part[partno - 1]) |
347 | return -EBUSY; | 357 | return -EBUSY; |
348 | 358 | ||
349 | p = kzalloc(sizeof(*p), GFP_KERNEL); | 359 | p = kzalloc(sizeof(*p), GFP_KERNEL); |
@@ -391,7 +401,8 @@ int add_partition(struct gendisk *disk, int partno, | |||
391 | } | 401 | } |
392 | 402 | ||
393 | /* everything is up and running, commence */ | 403 | /* everything is up and running, commence */ |
394 | disk->part[partno - 1] = p; | 404 | INIT_RCU_HEAD(&p->rcu_head); |
405 | rcu_assign_pointer(disk->__part[partno - 1], p); | ||
395 | 406 | ||
396 | /* suppress uevent if the disk supresses it */ | 407 | /* suppress uevent if the disk supresses it */ |
397 | if (!disk->dev.uevent_suppress) | 408 | if (!disk->dev.uevent_suppress) |
@@ -414,9 +425,9 @@ out_put: | |||
414 | void register_disk(struct gendisk *disk) | 425 | void register_disk(struct gendisk *disk) |
415 | { | 426 | { |
416 | struct block_device *bdev; | 427 | struct block_device *bdev; |
428 | struct disk_part_iter piter; | ||
429 | struct hd_struct *part; | ||
417 | char *s; | 430 | char *s; |
418 | int i; | ||
419 | struct hd_struct *p; | ||
420 | int err; | 431 | int err; |
421 | 432 | ||
422 | disk->dev.parent = disk->driverfs_dev; | 433 | disk->dev.parent = disk->driverfs_dev; |
@@ -466,16 +477,16 @@ exit: | |||
466 | kobject_uevent(&disk->dev.kobj, KOBJ_ADD); | 477 | kobject_uevent(&disk->dev.kobj, KOBJ_ADD); |
467 | 478 | ||
468 | /* announce possible partitions */ | 479 | /* announce possible partitions */ |
469 | for (i = 0; i < disk_max_parts(disk); i++) { | 480 | disk_part_iter_init(&piter, disk, 0); |
470 | p = disk->part[i]; | 481 | while ((part = disk_part_iter_next(&piter))) |
471 | if (!p || !p->nr_sects) | 482 | kobject_uevent(&part->dev.kobj, KOBJ_ADD); |
472 | continue; | 483 | disk_part_iter_exit(&piter); |
473 | kobject_uevent(&p->dev.kobj, KOBJ_ADD); | ||
474 | } | ||
475 | } | 484 | } |
476 | 485 | ||
477 | int rescan_partitions(struct gendisk *disk, struct block_device *bdev) | 486 | int rescan_partitions(struct gendisk *disk, struct block_device *bdev) |
478 | { | 487 | { |
488 | struct disk_part_iter piter; | ||
489 | struct hd_struct *part; | ||
479 | struct parsed_partitions *state; | 490 | struct parsed_partitions *state; |
480 | int p, res; | 491 | int p, res; |
481 | 492 | ||
@@ -485,8 +496,12 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) | |||
485 | if (res) | 496 | if (res) |
486 | return res; | 497 | return res; |
487 | bdev->bd_invalidated = 0; | 498 | bdev->bd_invalidated = 0; |
488 | for (p = 1; p <= disk_max_parts(disk); p++) | 499 | |
489 | delete_partition(disk, p); | 500 | disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); |
501 | while ((part = disk_part_iter_next(&piter))) | ||
502 | delete_partition(disk, part->partno); | ||
503 | disk_part_iter_exit(&piter); | ||
504 | |||
490 | if (disk->fops->revalidate_disk) | 505 | if (disk->fops->revalidate_disk) |
491 | disk->fops->revalidate_disk(disk); | 506 | disk->fops->revalidate_disk(disk); |
492 | if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) | 507 | if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) |
@@ -545,13 +560,18 @@ EXPORT_SYMBOL(read_dev_sector); | |||
545 | 560 | ||
546 | void del_gendisk(struct gendisk *disk) | 561 | void del_gendisk(struct gendisk *disk) |
547 | { | 562 | { |
548 | int p; | 563 | struct disk_part_iter piter; |
564 | struct hd_struct *part; | ||
549 | 565 | ||
550 | /* invalidate stuff */ | 566 | /* invalidate stuff */ |
551 | for (p = disk_max_parts(disk); p > 0; p--) { | 567 | disk_part_iter_init(&piter, disk, |
552 | invalidate_partition(disk, p); | 568 | DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE); |
553 | delete_partition(disk, p); | 569 | while ((part = disk_part_iter_next(&piter))) { |
570 | invalidate_partition(disk, part->partno); | ||
571 | delete_partition(disk, part->partno); | ||
554 | } | 572 | } |
573 | disk_part_iter_exit(&piter); | ||
574 | |||
555 | invalidate_partition(disk, 0); | 575 | invalidate_partition(disk, 0); |
556 | disk->capacity = 0; | 576 | disk->capacity = 0; |
557 | disk->flags &= ~GENHD_FL_UP; | 577 | disk->flags &= ~GENHD_FL_UP; |