aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2017-02-02 09:56:51 -0500
committerJens Axboe <axboe@fb.com>2017-02-02 10:20:50 -0500
commitd03f6cdc1fc422accb734c7c07a661a0018d8631 (patch)
treefe3500795df51b8ad11a0f76dddfa27d60fecf13
parentdc3b17cc8bf21307c7e076e7c778d5db756f7871 (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.c12
-rw-r--r--block/blk-sysfs.c2
-rw-r--r--include/linux/backing-dev-defs.h2
-rw-r--r--include/linux/backing-dev.h10
-rw-r--r--include/linux/blkdev.h1
-rw-r--r--mm/backing-dev.c34
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)
713struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) 713struct 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)
789fail_ref: 787fail_ref:
790 percpu_ref_exit(&q->q_usage_counter); 788 percpu_ref_exit(&q->q_usage_counter);
791fail_bdi: 789fail_bdi:
792 bdi_destroy(q->backing_dev_info); 790 bdi_put(q->backing_dev_info);
793fail_split: 791fail_split:
794 bioset_free(q->bio_split); 792 bioset_free(q->bio_split);
795fail_id: 793fail_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
14struct page; 15struct page;
15struct device; 16struct 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
20int __must_check bdi_init(struct backing_dev_info *bdi); 20int __must_check bdi_init(struct backing_dev_info *bdi);
21void bdi_exit(struct backing_dev_info *bdi); 21
22static inline struct backing_dev_info *bdi_get(struct backing_dev_info *bdi)
23{
24 kref_get(&bdi->refcnt);
25 return bdi;
26}
27
28void bdi_put(struct backing_dev_info *bdi);
22 29
23__printf(3, 4) 30__printf(3, 4)
24int bdi_register(struct backing_dev_info *bdi, struct device *parent, 31int bdi_register(struct backing_dev_info *bdi, struct device *parent,
@@ -29,6 +36,7 @@ void bdi_unregister(struct backing_dev_info *bdi);
29 36
30int __must_check bdi_setup_and_register(struct backing_dev_info *, char *); 37int __must_check bdi_setup_and_register(struct backing_dev_info *, char *);
31void bdi_destroy(struct backing_dev_info *bdi); 38void bdi_destroy(struct backing_dev_info *bdi);
39struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id);
32 40
33void wb_start_writeback(struct bdi_writeback *wb, long nr_pages, 41void 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}
242postcore_initcall(bdi_class_init); 243postcore_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}
792EXPORT_SYMBOL(bdi_init); 794EXPORT_SYMBOL(bdi_init);
793 795
796struct 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
794int bdi_register(struct backing_dev_info *bdi, struct device *parent, 812int 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
874void bdi_exit(struct backing_dev_info *bdi) 892static 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
898static 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
907void bdi_put(struct backing_dev_info *bdi)
908{
909 kref_put(&bdi->refcnt, release_bdi);
910}
911
880void bdi_destroy(struct backing_dev_info *bdi) 912void bdi_destroy(struct backing_dev_info *bdi)
881{ 913{
882 bdi_unregister(bdi); 914 bdi_unregister(bdi);