Commit d03f6cdc authored by Jan Kara's avatar Jan Kara Committed by Jens Axboe

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: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarJens Axboe <axboe@fb.com>
parent dc3b17cc
...@@ -713,7 +713,6 @@ static void blk_rq_timed_out_timer(unsigned long data) ...@@ -713,7 +713,6 @@ static void blk_rq_timed_out_timer(unsigned long data)
struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
{ {
struct request_queue *q; struct request_queue *q;
int err;
q = kmem_cache_alloc_node(blk_requestq_cachep, q = kmem_cache_alloc_node(blk_requestq_cachep,
gfp_mask | __GFP_ZERO, node_id); 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,17 +727,16 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
if (!q->bio_split) if (!q->bio_split)
goto fail_id; goto fail_id;
q->backing_dev_info = &q->_backing_dev_info; q->backing_dev_info = bdi_alloc_node(gfp_mask, node_id);
if (!q->backing_dev_info)
goto fail_split;
q->backing_dev_info->ra_pages = q->backing_dev_info->ra_pages =
(VM_MAX_READAHEAD * 1024) / PAGE_SIZE; (VM_MAX_READAHEAD * 1024) / PAGE_SIZE;
q->backing_dev_info->capabilities = BDI_CAP_CGROUP_WRITEBACK; q->backing_dev_info->capabilities = BDI_CAP_CGROUP_WRITEBACK;
q->backing_dev_info->name = "block"; q->backing_dev_info->name = "block";
q->node = node_id; q->node = node_id;
err = bdi_init(q->backing_dev_info);
if (err)
goto fail_split;
setup_timer(&q->backing_dev_info->laptop_mode_wb_timer, setup_timer(&q->backing_dev_info->laptop_mode_wb_timer,
laptop_mode_timer_fn, (unsigned long) q); laptop_mode_timer_fn, (unsigned long) q);
setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q); 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,7 +787,7 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
fail_ref: fail_ref:
percpu_ref_exit(&q->q_usage_counter); percpu_ref_exit(&q->q_usage_counter);
fail_bdi: fail_bdi:
bdi_destroy(q->backing_dev_info); bdi_put(q->backing_dev_info);
fail_split: fail_split:
bioset_free(q->bio_split); bioset_free(q->bio_split);
fail_id: fail_id:
......
...@@ -799,7 +799,7 @@ static void blk_release_queue(struct kobject *kobj) ...@@ -799,7 +799,7 @@ static void blk_release_queue(struct kobject *kobj)
container_of(kobj, struct request_queue, kobj); container_of(kobj, struct request_queue, kobj);
wbt_exit(q); wbt_exit(q);
bdi_exit(q->backing_dev_info); bdi_put(q->backing_dev_info);
blkcg_exit_queue(q); blkcg_exit_queue(q);
if (q->elevator) { if (q->elevator) {
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/flex_proportions.h> #include <linux/flex_proportions.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/kref.h>
struct page; struct page;
struct device; struct device;
...@@ -144,6 +145,7 @@ struct backing_dev_info { ...@@ -144,6 +145,7 @@ struct backing_dev_info {
char *name; char *name;
struct kref refcnt; /* Reference counter for the structure */
unsigned int capabilities; /* Device capabilities */ unsigned int capabilities; /* Device capabilities */
unsigned int min_ratio; unsigned int min_ratio;
unsigned int max_ratio, max_prop_frac; unsigned int max_ratio, max_prop_frac;
......
...@@ -18,7 +18,14 @@ ...@@ -18,7 +18,14 @@
#include <linux/slab.h> #include <linux/slab.h>
int __must_check bdi_init(struct backing_dev_info *bdi); int __must_check bdi_init(struct backing_dev_info *bdi);
void bdi_exit(struct backing_dev_info *bdi);
static inline struct backing_dev_info *bdi_get(struct backing_dev_info *bdi)
{
kref_get(&bdi->refcnt);
return bdi;
}
void bdi_put(struct backing_dev_info *bdi);
__printf(3, 4) __printf(3, 4)
int bdi_register(struct backing_dev_info *bdi, struct device *parent, int bdi_register(struct backing_dev_info *bdi, struct device *parent,
...@@ -29,6 +36,7 @@ void bdi_unregister(struct backing_dev_info *bdi); ...@@ -29,6 +36,7 @@ void bdi_unregister(struct backing_dev_info *bdi);
int __must_check bdi_setup_and_register(struct backing_dev_info *, char *); int __must_check bdi_setup_and_register(struct backing_dev_info *, char *);
void bdi_destroy(struct backing_dev_info *bdi); void bdi_destroy(struct backing_dev_info *bdi);
struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id);
void wb_start_writeback(struct bdi_writeback *wb, long nr_pages, void wb_start_writeback(struct bdi_writeback *wb, long nr_pages,
bool range_cyclic, enum wb_reason reason); bool range_cyclic, enum wb_reason reason);
......
...@@ -433,7 +433,6 @@ struct request_queue { ...@@ -433,7 +433,6 @@ struct request_queue {
struct delayed_work delay_work; struct delayed_work delay_work;
struct backing_dev_info *backing_dev_info; struct backing_dev_info *backing_dev_info;
struct backing_dev_info _backing_dev_info;
/* /*
* The queue owner gets to use this for whatever they like. * The queue owner gets to use this for whatever they like.
......
...@@ -237,6 +237,7 @@ static __init int bdi_class_init(void) ...@@ -237,6 +237,7 @@ static __init int bdi_class_init(void)
bdi_class->dev_groups = bdi_dev_groups; bdi_class->dev_groups = bdi_dev_groups;
bdi_debug_init(); bdi_debug_init();
return 0; return 0;
} }
postcore_initcall(bdi_class_init); postcore_initcall(bdi_class_init);
...@@ -776,6 +777,7 @@ int bdi_init(struct backing_dev_info *bdi) ...@@ -776,6 +777,7 @@ int bdi_init(struct backing_dev_info *bdi)
bdi->dev = NULL; bdi->dev = NULL;
kref_init(&bdi->refcnt);
bdi->min_ratio = 0; bdi->min_ratio = 0;
bdi->max_ratio = 100; bdi->max_ratio = 100;
bdi->max_prop_frac = FPROP_FRAC_BASE; bdi->max_prop_frac = FPROP_FRAC_BASE;
...@@ -791,6 +793,22 @@ int bdi_init(struct backing_dev_info *bdi) ...@@ -791,6 +793,22 @@ int bdi_init(struct backing_dev_info *bdi)
} }
EXPORT_SYMBOL(bdi_init); EXPORT_SYMBOL(bdi_init);
struct backing_dev_info *bdi_alloc_node(gfp_t gfp_mask, int node_id)
{
struct backing_dev_info *bdi;
bdi = kmalloc_node(sizeof(struct backing_dev_info),
gfp_mask | __GFP_ZERO, node_id);
if (!bdi)
return NULL;
if (bdi_init(bdi)) {
kfree(bdi);
return NULL;
}
return bdi;
}
int bdi_register(struct backing_dev_info *bdi, struct device *parent, int bdi_register(struct backing_dev_info *bdi, struct device *parent,
const char *fmt, ...) const char *fmt, ...)
{ {
...@@ -871,12 +889,26 @@ void bdi_unregister(struct backing_dev_info *bdi) ...@@ -871,12 +889,26 @@ void bdi_unregister(struct backing_dev_info *bdi)
} }
} }
void bdi_exit(struct backing_dev_info *bdi) static void bdi_exit(struct backing_dev_info *bdi)
{ {
WARN_ON_ONCE(bdi->dev); WARN_ON_ONCE(bdi->dev);
wb_exit(&bdi->wb); wb_exit(&bdi->wb);
} }
static void release_bdi(struct kref *ref)
{
struct backing_dev_info *bdi =
container_of(ref, struct backing_dev_info, refcnt);
bdi_exit(bdi);
kfree(bdi);
}
void bdi_put(struct backing_dev_info *bdi)
{
kref_put(&bdi->refcnt, release_bdi);
}
void bdi_destroy(struct backing_dev_info *bdi) void bdi_destroy(struct backing_dev_info *bdi)
{ {
bdi_unregister(bdi); bdi_unregister(bdi);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment