aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorJeff Moyer <jmoyer@redhat.com>2015-11-03 10:40:06 -0500
committerJens Axboe <axboe@fb.com>2015-11-03 10:42:19 -0500
commit2404e607a9ee36db361bebe32787dafa1f7d6c00 (patch)
tree38f0de79314cdf010e331897684f7097a28dbe51 /block
parentcdea01b2bf98affb7e9c44530108a4a28535eee8 (diff)
blk-mq: avoid excessive boot delays with large lun counts
Hi, Zhangqing Luo reported long boot times on a system with thousands of LUNs when scsi-mq was enabled. He narrowed the problem down to blk_mq_add_queue_tag_set, where every queue is frozen in order to set the BLK_MQ_F_TAG_SHARED flag. Each added device will freeze all queues added before it in sequence, which involves waiting for an RCU grace period for each one. We don't need to do this. After the second queue is added, only new queues need to be initialized with the shared tag. We can do that by percolating the flag up to the blk_mq_tag_set, and updating the newly added queue's hctxs if the flag is set. This problem was introduced by commit 0d2602ca30e41 (blk-mq: improve support for shared tags maps). Reported-and-tested-by: Jason Luo <zhangqing.luo@oracle.com> Reviewed-by: Ming Lei <ming.lei@canonical.com> Signed-off-by: Jeff Moyer <jmoyer@redhat.com> Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block')
-rw-r--r--block/blk-mq.c47
1 files changed, 30 insertions, 17 deletions
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 159e69bd2c3c..22db728dbe24 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -1695,7 +1695,7 @@ static int blk_mq_init_hctx(struct request_queue *q,
1695 INIT_LIST_HEAD(&hctx->dispatch); 1695 INIT_LIST_HEAD(&hctx->dispatch);
1696 hctx->queue = q; 1696 hctx->queue = q;
1697 hctx->queue_num = hctx_idx; 1697 hctx->queue_num = hctx_idx;
1698 hctx->flags = set->flags; 1698 hctx->flags = set->flags & ~BLK_MQ_F_TAG_SHARED;
1699 1699
1700 blk_mq_init_cpu_notifier(&hctx->cpu_notifier, 1700 blk_mq_init_cpu_notifier(&hctx->cpu_notifier,
1701 blk_mq_hctx_notify, hctx); 1701 blk_mq_hctx_notify, hctx);
@@ -1882,27 +1882,26 @@ static void blk_mq_map_swqueue(struct request_queue *q,
1882 } 1882 }
1883} 1883}
1884 1884
1885static void blk_mq_update_tag_set_depth(struct blk_mq_tag_set *set) 1885static void queue_set_hctx_shared(struct request_queue *q, bool shared)
1886{ 1886{
1887 struct blk_mq_hw_ctx *hctx; 1887 struct blk_mq_hw_ctx *hctx;
1888 struct request_queue *q;
1889 bool shared;
1890 int i; 1888 int i;
1891 1889
1892 if (set->tag_list.next == set->tag_list.prev) 1890 queue_for_each_hw_ctx(q, hctx, i) {
1893 shared = false; 1891 if (shared)
1894 else 1892 hctx->flags |= BLK_MQ_F_TAG_SHARED;
1895 shared = true; 1893 else
1894 hctx->flags &= ~BLK_MQ_F_TAG_SHARED;
1895 }
1896}
1897
1898static void blk_mq_update_tag_set_depth(struct blk_mq_tag_set *set, bool shared)
1899{
1900 struct request_queue *q;
1896 1901
1897 list_for_each_entry(q, &set->tag_list, tag_set_list) { 1902 list_for_each_entry(q, &set->tag_list, tag_set_list) {
1898 blk_mq_freeze_queue(q); 1903 blk_mq_freeze_queue(q);
1899 1904 queue_set_hctx_shared(q, shared);
1900 queue_for_each_hw_ctx(q, hctx, i) {
1901 if (shared)
1902 hctx->flags |= BLK_MQ_F_TAG_SHARED;
1903 else
1904 hctx->flags &= ~BLK_MQ_F_TAG_SHARED;
1905 }
1906 blk_mq_unfreeze_queue(q); 1905 blk_mq_unfreeze_queue(q);
1907 } 1906 }
1908} 1907}
@@ -1913,7 +1912,12 @@ static void blk_mq_del_queue_tag_set(struct request_queue *q)
1913 1912
1914 mutex_lock(&set->tag_list_lock); 1913 mutex_lock(&set->tag_list_lock);
1915 list_del_init(&q->tag_set_list); 1914 list_del_init(&q->tag_set_list);
1916 blk_mq_update_tag_set_depth(set); 1915 if (list_is_singular(&set->tag_list)) {
1916 /* just transitioned to unshared */
1917 set->flags &= ~BLK_MQ_F_TAG_SHARED;
1918 /* update existing queue */
1919 blk_mq_update_tag_set_depth(set, false);
1920 }
1917 mutex_unlock(&set->tag_list_lock); 1921 mutex_unlock(&set->tag_list_lock);
1918} 1922}
1919 1923
@@ -1923,8 +1927,17 @@ static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set,
1923 q->tag_set = set; 1927 q->tag_set = set;
1924 1928
1925 mutex_lock(&set->tag_list_lock); 1929 mutex_lock(&set->tag_list_lock);
1930
1931 /* Check to see if we're transitioning to shared (from 1 to 2 queues). */
1932 if (!list_empty(&set->tag_list) && !(set->flags & BLK_MQ_F_TAG_SHARED)) {
1933 set->flags |= BLK_MQ_F_TAG_SHARED;
1934 /* update existing queue */
1935 blk_mq_update_tag_set_depth(set, true);
1936 }
1937 if (set->flags & BLK_MQ_F_TAG_SHARED)
1938 queue_set_hctx_shared(q, true);
1926 list_add_tail(&q->tag_set_list, &set->tag_list); 1939 list_add_tail(&q->tag_set_list, &set->tag_list);
1927 blk_mq_update_tag_set_depth(set); 1940
1928 mutex_unlock(&set->tag_list_lock); 1941 mutex_unlock(&set->tag_list_lock);
1929} 1942}
1930 1943