summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--block/genhd.c6
-rw-r--r--block/partition-generic.c9
-rw-r--r--include/linux/genhd.h27
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
235void __delete_partition(struct hd_struct *part) 235void __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
260static ssize_t whole_disk_show(struct device *dev, 261static 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
361out_free_info: 362out_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);
614extern void __delete_partition(struct hd_struct *); 615extern void __delete_partition(struct percpu_ref *);
615extern void delete_partition(struct gendisk *, int); 616extern void delete_partition(struct gendisk *, int);
616extern void printk_all_partitions(void); 617extern 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
643static inline void hd_ref_init(struct hd_struct *part) 644static 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
649static inline void hd_struct_get(struct hd_struct *part) 652static 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
655static inline int hd_struct_try_get(struct hd_struct *part) 657static 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
660static inline void hd_struct_put(struct hd_struct *part) 662static 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
667static inline void hd_struct_kill(struct hd_struct *part)
668{
669 percpu_ref_kill(&part->ref);
664} 670}
665 671
666static inline void hd_free_part(struct hd_struct *part) 672static 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/*