diff options
| author | Jan Kara <jack@suse.cz> | 2017-02-02 09:56:51 -0500 |
|---|---|---|
| committer | Jens Axboe <axboe@fb.com> | 2017-02-02 10:20:50 -0500 |
| commit | d03f6cdc1fc422accb734c7c07a661a0018d8631 (patch) | |
| tree | fe3500795df51b8ad11a0f76dddfa27d60fecf13 | |
| parent | dc3b17cc8bf21307c7e076e7c778d5db756f7871 (diff) | |
block: Dynamically allocate and refcount backing_dev_info
Instead of storing backing_dev_info inside struct request_queue,
allocate it dynamically, reference count it, and free it when the last
reference is dropped. Currently only request_queue holds the reference
but in the following patch we add other users referencing
backing_dev_info.
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Jens Axboe <axboe@fb.com>
| -rw-r--r-- | block/blk-core.c | 12 | ||||
| -rw-r--r-- | block/blk-sysfs.c | 2 | ||||
| -rw-r--r-- | include/linux/backing-dev-defs.h | 2 | ||||
| -rw-r--r-- | include/linux/backing-dev.h | 10 | ||||
| -rw-r--r-- | include/linux/blkdev.h | 1 | ||||
| -rw-r--r-- | mm/backing-dev.c | 34 |
6 files changed, 50 insertions, 11 deletions
diff --git a/block/blk-core.c b/block/blk-core.c index dcac0352c14c..d2bba4700e65 100644 --- a/block/blk-core.c +++ b/block/blk-core.c | |||
| @@ -713,7 +713,6 @@ static void blk_rq_timed_out_timer(unsigned long data) | |||
| 713 | struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) | 713 | struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) |
| 714 | { | 714 | { |
| 715 | struct request_queue *q; | 715 | struct request_queue *q; |
| 716 | int err; | ||
| 717 | 716 | ||
| 718 | q = kmem_cache_alloc_node(blk_requestq_cachep, | 717 | q = kmem_cache_alloc_node(blk_requestq_cachep, |
| 719 | gfp_mask | __GFP_ZERO, node_id); | 718 | gfp_mask | __GFP_ZERO, node_id); |
| @@ -728,17 +727,16 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) | |||
| 728 | if (!q->bio_split) | 727 | if (!q->bio_split) |
| 729 | goto fail_id; | 728 | goto fail_id; |
| 730 | 729 | ||
| 731 | q->backing_dev_info = &q->_backing_dev_info; | 730 | q->backing_dev_info = bdi_alloc_node(gfp_mask, node_id); |
| 731 | if (!q->backing_dev_info) | ||
| 732 | goto fail_split; | ||
| 733 | |||
| 732 | q->backing_dev_info->ra_pages = | 734 | q->backing_dev_info->ra_pages = |
| 733 | (VM_MAX_READAHEAD * 1024) / PAGE_SIZE; | 735 | (VM_MAX_READAHEAD * 1024) / PAGE_SIZE; |
| 734 | q->backing_dev_info->capabilities = BDI_CAP_CGROUP_WRITEBACK; | 736 | q->backing_dev_info->capabilities = BDI_CAP_CGROUP_WRITEBACK; |
| 735 | q->backing_dev_info->name = "block"; | 737 | q->backing_dev_info->name = "block"; |
| 736 | q->node = node_id; | 738 | q->node = node_id; |
| 737 | 739 | ||
| 738 | err = bdi_init(q->backing_dev_info); | ||
| 739 | if (err) | ||
| 740 | goto fail_split; | ||
| 741 | |||
| 742 | setup_timer(&q->backing_dev_info->laptop_mode_wb_timer, | 740 | setup_timer(&q->backing_dev_info->laptop_mode_wb_timer, |
| 743 | laptop_mode_timer_fn, (unsigned long) q); | 741 | laptop_mode_timer_fn, (unsigned long) q); |
| 744 | setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q); | 742 | setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q); |
| @@ -789,7 +787,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) | |||
| 789 | fail_ref: | 787 | fail_ref: |
| 790 | percpu_ref_exit(&q->q_usage_counter); | 788 | percpu_ref_exit(&q->q_usage_counter); |
| 791 | fail_bdi: | 789 | fail_bdi: |
| 792 | bdi_destroy(q->backing_dev_info); | 790 | bdi_put(q->backing_dev_info); |
| 793 | fail_split: | 791 | fail_split: |
| 794 | bioset_free(q->bio_split); | 792 | bioset_free(q->bio_split); |
| 795 | fail_id: | 793 | fail_id: |
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 05841be1f30f..3e204789b8d3 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c | |||
| @@ -799,7 +799,7 @@ static void blk_release_queue(struct kobject *kobj) | |||
| 799 | container_of(kobj, struct request_queue, kobj); | 799 | container_of(kobj, struct request_queue, kobj); |
| 800 | 800 | ||
| 801 | wbt_exit(q); | 801 | wbt_exit(q); |
| 802 | bdi_exit(q->backing_dev_info); | 802 | bdi_put(q->backing_dev_info); |
| 803 | blkcg_exit_queue(q); | 803 | blkcg_exit_queue(q); |
| 804 | 804 | ||
| 805 | if (q->elevator) { | 805 | if (q->elevator) { |
diff --git a/include/linux/backing-dev-defs.h b/include/linux/backing-dev-defs.h index e850e76acaaf..ad955817916d 100644 --- a/include/linux/backing-dev-defs.h +++ b/include/linux/backing-dev-defs.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <linux/flex_proportions.h> | 10 | #include <linux/flex_proportions.h> |
| 11 | #include <linux/timer.h> | 11 | #include <linux/timer.h> |
| 12 | #include <linux/workqueue.h> | 12 | #include <linux/workqueue.h> |
| 13 | #include <linux/kref.h> | ||
| 13 | 14 | ||
| 14 | struct page; | 15 | struct page; |
| 15 | struct device; | 16 | struct device; |
| @@ -144,6 +145,7 @@ struct backing_dev_info { | |||
| 144 | 145 | ||
| 145 | char *name; | 146 | char *name; |
| 146 | 147 | ||
| 148 | struct kref refcnt; /* Reference counter for the structure */ | ||
| 147 | unsigned int capabilities; /* Device capabilities */ | 149 | unsigned int capabilities; /* Device capabilities */ |
| 148 | unsigned int min_ratio; | 150 | unsigned int min_ratio; |
| 149 | unsigned int max_ratio, max_prop_frac; | 151 | unsigned int max_ratio, max_prop_frac; |
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h index 43b93a947e61..efb6ca992d05 100644 --- a/include/linux/backing-dev.h +++ b/include/linux/backing-dev.h | |||
| @@ -18,7 +18,14 @@ | |||
| 18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 19 | 19 | ||
| 20 | int __must_check bdi_init(struct backing_dev_info *bdi); | 20 | int __must_check bdi_init(struct backing_dev_info *bdi); |
| 21 | void bdi_exit(struct backing_dev_info *bdi); | 21 | |
| 22 | static inline struct backing_dev_info *bdi_get(struct backing_dev_info *bdi) | ||
| 23 | { | ||
| 24 | kref_get(&bdi->refcnt); | ||
| 25 | return bdi; | ||
| 26 | } | ||
| 27 | |||
| 28 | void bdi_put(struct backing_dev_info *bdi); | ||
| 22 | 29 | ||
| 23 | __printf(3, 4) | 30 | __printf(3, 4) |
| 24 | int bdi_register(struct backing_dev_info *bdi, struct device *parent, | 31 | int bdi_register(struct backing_dev_info *bdi, struct device *parent, |
| @@ -29,6 +36,7 @@ void bdi_unregister(struct backing_dev_info *bdi); | |||
| 29 | 36 | ||
| 30 | int __must_check bdi_setup_and_register(struct backing_dev_info *, char *); | 37 | int __must_check bdi_setup_and_register(struct backing_dev_info *, char *); |
| 31 | void bdi_destroy(struct backing_dev_info *bdi); | 38 | void bdi_destroy(struct backing_dev_info *bdi); |
| 39 | struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id); | ||
| 32 | 40 | ||
| 33 | void wb_start_writeback(struct bdi_writeback *wb, long nr_pages, | 41 | void wb_start_writeback(struct bdi_writeback *wb, long nr_pages, |
| 34 | bool range_cyclic, enum wb_reason reason); | 42 | bool range_cyclic, enum wb_reason reason); |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index a75e42de34ab..e77c1039fd0e 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
| @@ -433,7 +433,6 @@ struct request_queue { | |||
| 433 | struct delayed_work delay_work; | 433 | struct delayed_work delay_work; |
| 434 | 434 | ||
| 435 | struct backing_dev_info *backing_dev_info; | 435 | struct backing_dev_info *backing_dev_info; |
| 436 | struct backing_dev_info _backing_dev_info; | ||
| 437 | 436 | ||
| 438 | /* | 437 | /* |
| 439 | * The queue owner gets to use this for whatever they like. | 438 | * The queue owner gets to use this for whatever they like. |
diff --git a/mm/backing-dev.c b/mm/backing-dev.c index 3bfed5ab2475..28ce6cf7b2ff 100644 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c | |||
| @@ -237,6 +237,7 @@ static __init int bdi_class_init(void) | |||
| 237 | 237 | ||
| 238 | bdi_class->dev_groups = bdi_dev_groups; | 238 | bdi_class->dev_groups = bdi_dev_groups; |
| 239 | bdi_debug_init(); | 239 | bdi_debug_init(); |
| 240 | |||
| 240 | return 0; | 241 | return 0; |
| 241 | } | 242 | } |
| 242 | postcore_initcall(bdi_class_init); | 243 | postcore_initcall(bdi_class_init); |
| @@ -776,6 +777,7 @@ int bdi_init(struct backing_dev_info *bdi) | |||
| 776 | 777 | ||
| 777 | bdi->dev = NULL; | 778 | bdi->dev = NULL; |
| 778 | 779 | ||
| 780 | kref_init(&bdi->refcnt); | ||
| 779 | bdi->min_ratio = 0; | 781 | bdi->min_ratio = 0; |
| 780 | bdi->max_ratio = 100; | 782 | bdi->max_ratio = 100; |
| 781 | bdi->max_prop_frac = FPROP_FRAC_BASE; | 783 | bdi->max_prop_frac = FPROP_FRAC_BASE; |
| @@ -791,6 +793,22 @@ int bdi_init(struct backing_dev_info *bdi) | |||
| 791 | } | 793 | } |
| 792 | EXPORT_SYMBOL(bdi_init); | 794 | EXPORT_SYMBOL(bdi_init); |
| 793 | 795 | ||
| 796 | struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id) | ||
| 797 | { | ||
| 798 | struct backing_dev_info *bdi; | ||
| 799 | |||
| 800 | bdi = kmalloc_node(sizeof(struct backing_dev_info), | ||
| 801 | gfp_mask | __GFP_ZERO, node_id); | ||
| 802 | if (!bdi) | ||
| 803 | return NULL; | ||
| 804 | |||
| 805 | if (bdi_init(bdi)) { | ||
| 806 | kfree(bdi); | ||
| 807 | return NULL; | ||
| 808 | } | ||
| 809 | return bdi; | ||
| 810 | } | ||
| 811 | |||
| 794 | int bdi_register(struct backing_dev_info *bdi, struct device *parent, | 812 | int bdi_register(struct backing_dev_info *bdi, struct device *parent, |
| 795 | const char *fmt, ...) | 813 | const char *fmt, ...) |
| 796 | { | 814 | { |
| @@ -871,12 +889,26 @@ void bdi_unregister(struct backing_dev_info *bdi) | |||
| 871 | } | 889 | } |
| 872 | } | 890 | } |
| 873 | 891 | ||
| 874 | void bdi_exit(struct backing_dev_info *bdi) | 892 | static void bdi_exit(struct backing_dev_info *bdi) |
| 875 | { | 893 | { |
| 876 | WARN_ON_ONCE(bdi->dev); | 894 | WARN_ON_ONCE(bdi->dev); |
| 877 | wb_exit(&bdi->wb); | 895 | wb_exit(&bdi->wb); |
| 878 | } | 896 | } |
| 879 | 897 | ||
| 898 | static void release_bdi(struct kref *ref) | ||
| 899 | { | ||
| 900 | struct backing_dev_info *bdi = | ||
| 901 | container_of(ref, struct backing_dev_info, refcnt); | ||
| 902 | |||
| 903 | bdi_exit(bdi); | ||
| 904 | kfree(bdi); | ||
| 905 | } | ||
| 906 | |||
| 907 | void bdi_put(struct backing_dev_info *bdi) | ||
| 908 | { | ||
| 909 | kref_put(&bdi->refcnt, release_bdi); | ||
| 910 | } | ||
| 911 | |||
| 880 | void bdi_destroy(struct backing_dev_info *bdi) | 912 | void bdi_destroy(struct backing_dev_info *bdi) |
| 881 | { | 913 | { |
| 882 | bdi_unregister(bdi); | 914 | bdi_unregister(bdi); |
