aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShaohua Li <shli@fb.com>2015-05-08 13:51:33 -0400
committerJens Axboe <axboe@fb.com>2015-05-08 16:17:23 -0400
commit5b3f341f098d60da2970758db6a05bd851eb6b39 (patch)
treefd25ff2f67ac583a02f2cd288b7419609d373d00
parentf984df1f0f71ef96254411fc3576a10ae561be71 (diff)
blk-mq: make plug work for mutiple disks and queues
Last patch makes plug work for multiple queue case. However it only works for single disk case, because it assumes only one request in the plug list. If a task is accessing multiple disks, eg MD/DM, the assumption is wrong. Let blk_attempt_plug_merge() record request from the same queue. V2: use NULL parameter in !mq case. Fix a bug. Add comments in blk_attempt_plug_merge to make it less (hopefully) confusion. Cc: Jens Axboe <axboe@fb.com> Cc: Christoph Hellwig <hch@lst.de> Signed-off-by: Shaohua Li <shli@fb.com> Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r--block/blk-core.c15
-rw-r--r--block/blk-mq.c14
-rw-r--r--block/blk.h3
3 files changed, 23 insertions, 9 deletions
diff --git a/block/blk-core.c b/block/blk-core.c
index 9dcfb8ec554b..f0be754c7781 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1522,7 +1522,8 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req,
1522 * Caller must ensure !blk_queue_nomerges(q) beforehand. 1522 * Caller must ensure !blk_queue_nomerges(q) beforehand.
1523 */ 1523 */
1524bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio, 1524bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio,
1525 unsigned int *request_count) 1525 unsigned int *request_count,
1526 struct request **same_queue_rq)
1526{ 1527{
1527 struct blk_plug *plug; 1528 struct blk_plug *plug;
1528 struct request *rq; 1529 struct request *rq;
@@ -1542,8 +1543,16 @@ bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio,
1542 list_for_each_entry_reverse(rq, plug_list, queuelist) { 1543 list_for_each_entry_reverse(rq, plug_list, queuelist) {
1543 int el_ret; 1544 int el_ret;
1544 1545
1545 if (rq->q == q) 1546 if (rq->q == q) {
1546 (*request_count)++; 1547 (*request_count)++;
1548 /*
1549 * Only blk-mq multiple hardware queues case checks the
1550 * rq in the same queue, there should be only one such
1551 * rq in a queue
1552 **/
1553 if (same_queue_rq)
1554 *same_queue_rq = rq;
1555 }
1547 1556
1548 if (rq->q != q || !blk_rq_merge_ok(rq, bio)) 1557 if (rq->q != q || !blk_rq_merge_ok(rq, bio))
1549 continue; 1558 continue;
@@ -1608,7 +1617,7 @@ void blk_queue_bio(struct request_queue *q, struct bio *bio)
1608 * any locks. 1617 * any locks.
1609 */ 1618 */
1610 if (!blk_queue_nomerges(q) && 1619 if (!blk_queue_nomerges(q) &&
1611 blk_attempt_plug_merge(q, bio, &request_count)) 1620 blk_attempt_plug_merge(q, bio, &request_count, NULL))
1612 return; 1621 return;
1613 1622
1614 spin_lock_irq(q->queue_lock); 1623 spin_lock_irq(q->queue_lock);
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 902c2eb9a0e7..31df47443699 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -1269,6 +1269,7 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
1269 struct request *rq; 1269 struct request *rq;
1270 unsigned int request_count = 0; 1270 unsigned int request_count = 0;
1271 struct blk_plug *plug; 1271 struct blk_plug *plug;
1272 struct request *same_queue_rq = NULL;
1272 1273
1273 blk_queue_bounce(q, &bio); 1274 blk_queue_bounce(q, &bio);
1274 1275
@@ -1278,7 +1279,7 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
1278 } 1279 }
1279 1280
1280 if (!is_flush_fua && !blk_queue_nomerges(q) && 1281 if (!is_flush_fua && !blk_queue_nomerges(q) &&
1281 blk_attempt_plug_merge(q, bio, &request_count)) 1282 blk_attempt_plug_merge(q, bio, &request_count, &same_queue_rq))
1282 return; 1283 return;
1283 1284
1284 rq = blk_mq_map_request(q, bio, &data); 1285 rq = blk_mq_map_request(q, bio, &data);
@@ -1309,9 +1310,12 @@ static void blk_mq_make_request(struct request_queue *q, struct bio *bio)
1309 * issued. So the plug list will have one request at most 1310 * issued. So the plug list will have one request at most
1310 */ 1311 */
1311 if (plug) { 1312 if (plug) {
1312 if (!list_empty(&plug->mq_list)) { 1313 /*
1313 old_rq = list_first_entry(&plug->mq_list, 1314 * The plug list might get flushed before this. If that
1314 struct request, queuelist); 1315 * happens, same_queue_rq is invalid and plug list is empty
1316 **/
1317 if (same_queue_rq && !list_empty(&plug->mq_list)) {
1318 old_rq = same_queue_rq;
1315 list_del_init(&old_rq->queuelist); 1319 list_del_init(&old_rq->queuelist);
1316 } 1320 }
1317 list_add_tail(&rq->queuelist, &plug->mq_list); 1321 list_add_tail(&rq->queuelist, &plug->mq_list);
@@ -1360,7 +1364,7 @@ static void blk_sq_make_request(struct request_queue *q, struct bio *bio)
1360 } 1364 }
1361 1365
1362 if (!is_flush_fua && !blk_queue_nomerges(q) && 1366 if (!is_flush_fua && !blk_queue_nomerges(q) &&
1363 blk_attempt_plug_merge(q, bio, &request_count)) 1367 blk_attempt_plug_merge(q, bio, &request_count, NULL))
1364 return; 1368 return;
1365 1369
1366 rq = blk_mq_map_request(q, bio, &data); 1370 rq = blk_mq_map_request(q, bio, &data);
diff --git a/block/blk.h b/block/blk.h
index 4b48d55e588e..026d9594142b 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -78,7 +78,8 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req,
78bool bio_attempt_back_merge(struct request_queue *q, struct request *req, 78bool bio_attempt_back_merge(struct request_queue *q, struct request *req,
79 struct bio *bio); 79 struct bio *bio);
80bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio, 80bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio,
81 unsigned int *request_count); 81 unsigned int *request_count,
82 struct request **same_queue_rq);
82 83
83void blk_account_io_start(struct request *req, bool new_io); 84void blk_account_io_start(struct request *req, bool new_io);
84void blk_account_io_completion(struct request *req, unsigned int bytes); 85void blk_account_io_completion(struct request *req, unsigned int bytes);