diff options
-rw-r--r-- | block/genhd.c | 6 | ||||
-rw-r--r-- | block/partition-generic.c | 9 | ||||
-rw-r--r-- | include/linux/genhd.h | 27 |
3 files changed, 27 insertions, 15 deletions
diff --git a/block/genhd.c b/block/genhd.c index 85df45292dba..0c706f33a599 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -1284,7 +1284,11 @@ struct gendisk *alloc_disk_node(int minors, int node_id) | |||
1284 | * converted to make use of bd_mutex and sequence counters. | 1284 | * converted to make use of bd_mutex and sequence counters. |
1285 | */ | 1285 | */ |
1286 | seqcount_init(&disk->part0.nr_sects_seq); | 1286 | seqcount_init(&disk->part0.nr_sects_seq); |
1287 | hd_ref_init(&disk->part0); | 1287 | if (hd_ref_init(&disk->part0)) { |
1288 | hd_free_part(&disk->part0); | ||
1289 | kfree(disk); | ||
1290 | return NULL; | ||
1291 | } | ||
1288 | 1292 | ||
1289 | disk->minors = minors; | 1293 | disk->minors = minors; |
1290 | rand_initialize_disk(disk); | 1294 | rand_initialize_disk(disk); |
diff --git a/block/partition-generic.c b/block/partition-generic.c index eca0d02a607c..e7711133284e 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c | |||
@@ -232,8 +232,9 @@ static void delete_partition_rcu_cb(struct rcu_head *head) | |||
232 | put_device(part_to_dev(part)); | 232 | put_device(part_to_dev(part)); |
233 | } | 233 | } |
234 | 234 | ||
235 | void __delete_partition(struct hd_struct *part) | 235 | void __delete_partition(struct percpu_ref *ref) |
236 | { | 236 | { |
237 | struct hd_struct *part = container_of(ref, struct hd_struct, ref); | ||
237 | call_rcu(&part->rcu_head, delete_partition_rcu_cb); | 238 | call_rcu(&part->rcu_head, delete_partition_rcu_cb); |
238 | } | 239 | } |
239 | 240 | ||
@@ -254,7 +255,7 @@ void delete_partition(struct gendisk *disk, int partno) | |||
254 | kobject_put(part->holder_dir); | 255 | kobject_put(part->holder_dir); |
255 | device_del(part_to_dev(part)); | 256 | device_del(part_to_dev(part)); |
256 | 257 | ||
257 | hd_struct_put(part); | 258 | hd_struct_kill(part); |
258 | } | 259 | } |
259 | 260 | ||
260 | static ssize_t whole_disk_show(struct device *dev, | 261 | static ssize_t whole_disk_show(struct device *dev, |
@@ -355,8 +356,8 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, | |||
355 | if (!dev_get_uevent_suppress(ddev)) | 356 | if (!dev_get_uevent_suppress(ddev)) |
356 | kobject_uevent(&pdev->kobj, KOBJ_ADD); | 357 | kobject_uevent(&pdev->kobj, KOBJ_ADD); |
357 | 358 | ||
358 | hd_ref_init(p); | 359 | if (!hd_ref_init(p)) |
359 | return p; | 360 | return p; |
360 | 361 | ||
361 | out_free_info: | 362 | out_free_info: |
362 | free_part_info(p); | 363 | free_part_info(p); |
diff --git a/include/linux/genhd.h b/include/linux/genhd.h index a221220ffcb2..2adbfa6d02bc 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/kdev_t.h> | 13 | #include <linux/kdev_t.h> |
14 | #include <linux/rcupdate.h> | 14 | #include <linux/rcupdate.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/percpu-refcount.h> | ||
16 | 17 | ||
17 | #ifdef CONFIG_BLOCK | 18 | #ifdef CONFIG_BLOCK |
18 | 19 | ||
@@ -124,7 +125,7 @@ struct hd_struct { | |||
124 | #else | 125 | #else |
125 | struct disk_stats dkstats; | 126 | struct disk_stats dkstats; |
126 | #endif | 127 | #endif |
127 | atomic_t ref; | 128 | struct percpu_ref ref; |
128 | struct rcu_head rcu_head; | 129 | struct rcu_head rcu_head; |
129 | }; | 130 | }; |
130 | 131 | ||
@@ -611,7 +612,7 @@ extern struct hd_struct * __must_check add_partition(struct gendisk *disk, | |||
611 | sector_t len, int flags, | 612 | sector_t len, int flags, |
612 | struct partition_meta_info | 613 | struct partition_meta_info |
613 | *info); | 614 | *info); |
614 | extern void __delete_partition(struct hd_struct *); | 615 | extern void __delete_partition(struct percpu_ref *); |
615 | extern void delete_partition(struct gendisk *, int); | 616 | extern void delete_partition(struct gendisk *, int); |
616 | extern void printk_all_partitions(void); | 617 | extern void printk_all_partitions(void); |
617 | 618 | ||
@@ -640,33 +641,39 @@ extern ssize_t part_fail_store(struct device *dev, | |||
640 | const char *buf, size_t count); | 641 | const char *buf, size_t count); |
641 | #endif /* CONFIG_FAIL_MAKE_REQUEST */ | 642 | #endif /* CONFIG_FAIL_MAKE_REQUEST */ |
642 | 643 | ||
643 | static inline void hd_ref_init(struct hd_struct *part) | 644 | static inline int hd_ref_init(struct hd_struct *part) |
644 | { | 645 | { |
645 | atomic_set(&part->ref, 1); | 646 | if (percpu_ref_init(&part->ref, __delete_partition, 0, |
646 | smp_mb(); | 647 | GFP_KERNEL)) |
648 | return -ENOMEM; | ||
649 | return 0; | ||
647 | } | 650 | } |
648 | 651 | ||
649 | static inline void hd_struct_get(struct hd_struct *part) | 652 | static inline void hd_struct_get(struct hd_struct *part) |
650 | { | 653 | { |
651 | atomic_inc(&part->ref); | 654 | percpu_ref_get(&part->ref); |
652 | smp_mb__after_atomic(); | ||
653 | } | 655 | } |
654 | 656 | ||
655 | static inline int hd_struct_try_get(struct hd_struct *part) | 657 | static inline int hd_struct_try_get(struct hd_struct *part) |
656 | { | 658 | { |
657 | return atomic_inc_not_zero(&part->ref); | 659 | return percpu_ref_tryget_live(&part->ref); |
658 | } | 660 | } |
659 | 661 | ||
660 | static inline void hd_struct_put(struct hd_struct *part) | 662 | static inline void hd_struct_put(struct hd_struct *part) |
661 | { | 663 | { |
662 | if (atomic_dec_and_test(&part->ref)) | 664 | percpu_ref_put(&part->ref); |
663 | __delete_partition(part); | 665 | } |
666 | |||
667 | static inline void hd_struct_kill(struct hd_struct *part) | ||
668 | { | ||
669 | percpu_ref_kill(&part->ref); | ||
664 | } | 670 | } |
665 | 671 | ||
666 | static inline void hd_free_part(struct hd_struct *part) | 672 | static inline void hd_free_part(struct hd_struct *part) |
667 | { | 673 | { |
668 | free_part_stats(part); | 674 | free_part_stats(part); |
669 | free_part_info(part); | 675 | free_part_info(part); |
676 | percpu_ref_exit(&part->ref); | ||
670 | } | 677 | } |
671 | 678 | ||
672 | /* | 679 | /* |