summaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorJens Axboe <axboe@fb.com>2017-03-21 17:20:01 -0600
committerJens Axboe <axboe@fb.com>2017-03-21 17:20:01 -0600
commita83b576c9c25cf771fb0b15ec5eb2e7510ec2f5a (patch)
treebaf705377f5e7a1d330eb0ece93f68e1aafe2161 /block
parent34dbad5d26e2f4b88e60f0e9ad03f99480802812 (diff)
downloadlinux-a83b576c9c25cf771fb0b15ec5eb2e7510ec2f5a.tar.bz2
block: fix stacked driver stats init and free
If a driver allocates a queue for stacked usage, then it does not currently get stats allocated. This causes the later init of, eg, writeback throttling to blow up. Move the init to the queue allocation instead. Additionally, allow a NULL callback unregistration. This avoids having the caller check for that, fixing another oops on removal of a block device that doesn't have poll stats allocated. Fixes: 34dbad5d26e2 ("blk-stat: convert to callback-based statistics reporting") Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block')
-rw-r--r--block/blk-core.c10
-rw-r--r--block/blk-stat.c3
2 files changed, 8 insertions, 5 deletions
diff --git a/block/blk-core.c b/block/blk-core.c
index 78d04ddededc..ad388d5e309a 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -720,6 +720,10 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
if (!q->backing_dev_info)
goto fail_split;
+ q->stats = blk_alloc_queue_stats();
+ if (!q->stats)
+ goto fail_stats;
+
q->backing_dev_info->ra_pages =
(VM_MAX_READAHEAD * 1024) / PAGE_SIZE;
q->backing_dev_info->capabilities = BDI_CAP_CGROUP_WRITEBACK;
@@ -776,6 +780,8 @@ struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id)
fail_ref:
percpu_ref_exit(&q->q_usage_counter);
fail_bdi:
+ blk_free_queue_stats(q->stats);
+fail_stats:
bdi_put(q->backing_dev_info);
fail_split:
bioset_free(q->bio_split);
@@ -852,10 +858,6 @@ static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio);
int blk_init_allocated_queue(struct request_queue *q)
{
- q->stats = blk_alloc_queue_stats();
- if (!q->stats)
- return -ENOMEM;
-
q->fq = blk_alloc_flush_queue(q, NUMA_NO_NODE, q->cmd_size);
if (!q->fq)
return -ENOMEM;
diff --git a/block/blk-stat.c b/block/blk-stat.c
index 0d8721a60db9..188b535cf4d6 100644
--- a/block/blk-stat.c
+++ b/block/blk-stat.c
@@ -210,7 +210,8 @@ static void blk_stat_free_callback_rcu(struct rcu_head *head)
void blk_stat_free_callback(struct blk_stat_callback *cb)
{
- call_rcu(&cb->rcu, blk_stat_free_callback_rcu);
+ if (cb)
+ call_rcu(&cb->rcu, blk_stat_free_callback_rcu);
}
EXPORT_SYMBOL_GPL(blk_stat_free_callback);