Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

block: partition: convert percpu ref

Percpu refcount is the perfect match for partition's case,
and the conversion is quite straight.

With the convertion, one pair of atomic inc/dec can be saved
for accounting block I/O, which is run in hot path of block I/O.

Signed-off-by: Ming Lei <tom.leiming@gmail.com>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@fb.com>

authored by

Ming Lei and committed by
Jens Axboe
6c71013e b54e5ed8

+27 -15
+5 -1
block/genhd.c
··· 1284 1284 * converted to make use of bd_mutex and sequence counters. 1285 1285 */ 1286 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 1293 disk->minors = minors; 1290 1294 rand_initialize_disk(disk);
+5 -4
block/partition-generic.c
··· 232 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 238 call_rcu(&part->rcu_head, delete_partition_rcu_cb); 238 239 } 239 240 ··· 255 254 kobject_put(part->holder_dir); 256 255 device_del(part_to_dev(part)); 257 256 258 - hd_struct_put(part); 257 + hd_struct_kill(part); 259 258 } 260 259 261 260 static ssize_t whole_disk_show(struct device *dev, ··· 356 355 if (!dev_get_uevent_suppress(ddev)) 357 356 kobject_uevent(&pdev->kobj, KOBJ_ADD); 358 357 359 - hd_ref_init(p); 360 - return p; 358 + if (!hd_ref_init(p)) 359 + return p; 361 360 362 361 out_free_info: 363 362 free_part_info(p);
+17 -10
include/linux/genhd.h
··· 13 13 #include <linux/kdev_t.h> 14 14 #include <linux/rcupdate.h> 15 15 #include <linux/slab.h> 16 + #include <linux/percpu-refcount.h> 16 17 17 18 #ifdef CONFIG_BLOCK 18 19 ··· 125 124 #else 126 125 struct disk_stats dkstats; 127 126 #endif 128 - atomic_t ref; 127 + struct percpu_ref ref; 129 128 struct rcu_head rcu_head; 130 129 }; 131 130 ··· 612 611 sector_t len, int flags, 613 612 struct partition_meta_info 614 613 *info); 615 - extern void __delete_partition(struct hd_struct *); 614 + extern void __delete_partition(struct percpu_ref *); 616 615 extern void delete_partition(struct gendisk *, int); 617 616 extern void printk_all_partitions(void); 618 617 ··· 641 640 const char *buf, size_t count); 642 641 #endif /* CONFIG_FAIL_MAKE_REQUEST */ 643 642 644 - static inline void hd_ref_init(struct hd_struct *part) 643 + static inline int hd_ref_init(struct hd_struct *part) 645 644 { 646 - atomic_set(&part->ref, 1); 647 - smp_mb(); 645 + if (percpu_ref_init(&part->ref, __delete_partition, 0, 646 + GFP_KERNEL)) 647 + return -ENOMEM; 648 + return 0; 648 649 } 649 650 650 651 static inline void hd_struct_get(struct hd_struct *part) 651 652 { 652 - atomic_inc(&part->ref); 653 - smp_mb__after_atomic(); 653 + percpu_ref_get(&part->ref); 654 654 } 655 655 656 656 static inline int hd_struct_try_get(struct hd_struct *part) 657 657 { 658 - return atomic_inc_not_zero(&part->ref); 658 + return percpu_ref_tryget_live(&part->ref); 659 659 } 660 660 661 661 static inline void hd_struct_put(struct hd_struct *part) 662 662 { 663 - if (atomic_dec_and_test(&part->ref)) 664 - __delete_partition(part); 663 + percpu_ref_put(&part->ref); 664 + } 665 + 666 + static inline void hd_struct_kill(struct hd_struct *part) 667 + { 668 + percpu_ref_kill(&part->ref); 665 669 } 666 670 667 671 static inline void hd_free_part(struct hd_struct *part) 668 672 { 669 673 free_part_stats(part); 670 674 free_part_info(part); 675 + percpu_ref_exit(&part->ref); 671 676 } 672 677 673 678 /*