aboutsummaryrefslogtreecommitdiffstats
path: root/block
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2009-07-03 04:48:17 -0400
committerJens Axboe <jens.axboe@oracle.com>2009-09-11 08:33:30 -0400
commit80a761fd33cf812f771e212139157bf8f58d4b3f (patch)
tree21ea67ad749c15f25cb8a9278fe9bd7643c0ba31 /block
parenta82afdfcb8c0df09776b6458af6b68fc58b2e87b (diff)
block: implement mixed merge of different failfast requests
Failfast has characteristics from other attributes. When issuing, executing and successuflly completing requests, failfast doesn't make any difference. It only affects how a request is handled on failure. Allowing requests with different failfast settings to be merged cause normal IOs to fail prematurely while not allowing has performance penalties as failfast is used for read aheads which are likely to be located near in-flight or to-be-issued normal IOs. This patch introduces the concept of 'mixed merge'. A request is a mixed merge if it is merge of segments which require different handling on failure. Currently the only mixable attributes are failfast ones (or lack thereof). When a bio with different failfast settings is added to an existing request or requests of different failfast settings are merged, the merged request is marked mixed. Each bio carries failfast settings and the request always tracks failfast state of the first bio. When the request fails, blk_rq_err_bytes() can be used to determine how many bytes can be safely failed without crossing into an area which requires further retrials. This allows request merging regardless of failfast settings while keeping the failure handling correct. This patch only implements mixed merge but doesn't enable it. The next one will update SCSI to make use of mixed merge. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Niel Lambrechts <niel.lambrechts@gmail.com> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'block')
-rw-r--r--block/blk-core.c99
-rw-r--r--block/blk-merge.c43
-rw-r--r--block/blk.h1
3 files changed, 143 insertions, 0 deletions
diff --git a/block/blk-core.c b/block/blk-core.c
index 4daae1ee2b23..c822239bcc9d 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1157,6 +1157,7 @@ static int __make_request(struct request_queue *q, struct bio *bio)
1157 const unsigned short prio = bio_prio(bio); 1157 const unsigned short prio = bio_prio(bio);
1158 const int sync = bio_sync(bio); 1158 const int sync = bio_sync(bio);
1159 const int unplug = bio_unplug(bio); 1159 const int unplug = bio_unplug(bio);
1160 const unsigned int ff = bio->bi_rw & REQ_FAILFAST_MASK;
1160 int rw_flags; 1161 int rw_flags;
1161 1162
1162 if (bio_barrier(bio) && bio_has_data(bio) && 1163 if (bio_barrier(bio) && bio_has_data(bio) &&
@@ -1186,6 +1187,9 @@ static int __make_request(struct request_queue *q, struct bio *bio)
1186 1187
1187 trace_block_bio_backmerge(q, bio); 1188 trace_block_bio_backmerge(q, bio);
1188 1189
1190 if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff)
1191 blk_rq_set_mixed_merge(req);
1192
1189 req->biotail->bi_next = bio; 1193 req->biotail->bi_next = bio;
1190 req->biotail = bio; 1194 req->biotail = bio;
1191 req->__data_len += bytes; 1195 req->__data_len += bytes;
@@ -1205,6 +1209,12 @@ static int __make_request(struct request_queue *q, struct bio *bio)
1205 1209
1206 trace_block_bio_frontmerge(q, bio); 1210 trace_block_bio_frontmerge(q, bio);
1207 1211
1212 if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff) {
1213 blk_rq_set_mixed_merge(req);
1214 req->cmd_flags &= ~REQ_FAILFAST_MASK;
1215 req->cmd_flags |= ff;
1216 }
1217
1208 bio->bi_next = req->bio; 1218 bio->bi_next = req->bio;
1209 req->bio = bio; 1219 req->bio = bio;
1210 1220
@@ -1649,6 +1659,50 @@ int blk_insert_cloned_request(struct request_queue *q, struct request *rq)
1649} 1659}
1650EXPORT_SYMBOL_GPL(blk_insert_cloned_request); 1660EXPORT_SYMBOL_GPL(blk_insert_cloned_request);
1651 1661
1662/**
1663 * blk_rq_err_bytes - determine number of bytes till the next failure boundary
1664 * @rq: request to examine
1665 *
1666 * Description:
1667 * A request could be merge of IOs which require different failure
1668 * handling. This function determines the number of bytes which
1669 * can be failed from the beginning of the request without
1670 * crossing into area which need to be retried further.
1671 *
1672 * Return:
1673 * The number of bytes to fail.
1674 *
1675 * Context:
1676 * queue_lock must be held.
1677 */
1678unsigned int blk_rq_err_bytes(const struct request *rq)
1679{
1680 unsigned int ff = rq->cmd_flags & REQ_FAILFAST_MASK;
1681 unsigned int bytes = 0;
1682 struct bio *bio;
1683
1684 if (!(rq->cmd_flags & REQ_MIXED_MERGE))
1685 return blk_rq_bytes(rq);
1686
1687 /*
1688 * Currently the only 'mixing' which can happen is between
1689 * different fastfail types. We can safely fail portions
1690 * which have all the failfast bits that the first one has -
1691 * the ones which are at least as eager to fail as the first
1692 * one.
1693 */
1694 for (bio = rq->bio; bio; bio = bio->bi_next) {
1695 if ((bio->bi_rw & ff) != ff)
1696 break;
1697 bytes += bio->bi_size;
1698 }
1699
1700 /* this could lead to infinite loop */
1701 BUG_ON(blk_rq_bytes(rq) && !bytes);
1702 return bytes;
1703}
1704EXPORT_SYMBOL_GPL(blk_rq_err_bytes);
1705
1652static void blk_account_io_completion(struct request *req, unsigned int bytes) 1706static void blk_account_io_completion(struct request *req, unsigned int bytes)
1653{ 1707{
1654 if (blk_do_io_stat(req)) { 1708 if (blk_do_io_stat(req)) {
@@ -1995,6 +2049,12 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
1995 if (blk_fs_request(req) || blk_discard_rq(req)) 2049 if (blk_fs_request(req) || blk_discard_rq(req))
1996 req->__sector += total_bytes >> 9; 2050 req->__sector += total_bytes >> 9;
1997 2051
2052 /* mixed attributes always follow the first bio */
2053 if (req->cmd_flags & REQ_MIXED_MERGE) {
2054 req->cmd_flags &= ~REQ_FAILFAST_MASK;
2055 req->cmd_flags |= req->bio->bi_rw & REQ_FAILFAST_MASK;
2056 }
2057
1998 /* 2058 /*
1999 * If total number of sectors is less than the first segment 2059 * If total number of sectors is less than the first segment
2000 * size, something has gone terribly wrong. 2060 * size, something has gone terribly wrong.
@@ -2174,6 +2234,25 @@ bool blk_end_request_cur(struct request *rq, int error)
2174EXPORT_SYMBOL(blk_end_request_cur); 2234EXPORT_SYMBOL(blk_end_request_cur);
2175 2235
2176/** 2236/**
2237 * blk_end_request_err - Finish a request till the next failure boundary.
2238 * @rq: the request to finish till the next failure boundary for
2239 * @error: must be negative errno
2240 *
2241 * Description:
2242 * Complete @rq till the next failure boundary.
2243 *
2244 * Return:
2245 * %false - we are done with this request
2246 * %true - still buffers pending for this request
2247 */
2248bool blk_end_request_err(struct request *rq, int error)
2249{
2250 WARN_ON(error >= 0);
2251 return blk_end_request(rq, error, blk_rq_err_bytes(rq));
2252}
2253EXPORT_SYMBOL_GPL(blk_end_request_err);
2254
2255/**
2177 * __blk_end_request - Helper function for drivers to complete the request. 2256 * __blk_end_request - Helper function for drivers to complete the request.
2178 * @rq: the request being processed 2257 * @rq: the request being processed
2179 * @error: %0 for success, < %0 for error 2258 * @error: %0 for success, < %0 for error
@@ -2232,6 +2311,26 @@ bool __blk_end_request_cur(struct request *rq, int error)
2232} 2311}
2233EXPORT_SYMBOL(__blk_end_request_cur); 2312EXPORT_SYMBOL(__blk_end_request_cur);
2234 2313
2314/**
2315 * __blk_end_request_err - Finish a request till the next failure boundary.
2316 * @rq: the request to finish till the next failure boundary for
2317 * @error: must be negative errno
2318 *
2319 * Description:
2320 * Complete @rq till the next failure boundary. Must be called
2321 * with queue lock held.
2322 *
2323 * Return:
2324 * %false - we are done with this request
2325 * %true - still buffers pending for this request
2326 */
2327bool __blk_end_request_err(struct request *rq, int error)
2328{
2329 WARN_ON(error >= 0);
2330 return __blk_end_request(rq, error, blk_rq_err_bytes(rq));
2331}
2332EXPORT_SYMBOL_GPL(__blk_end_request_err);
2333
2235void blk_rq_bio_prep(struct request_queue *q, struct request *rq, 2334void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
2236 struct bio *bio) 2335 struct bio *bio)
2237{ 2336{
diff --git a/block/blk-merge.c b/block/blk-merge.c
index e1999679a4d5..7c9ca01baa45 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -311,6 +311,36 @@ static int ll_merge_requests_fn(struct request_queue *q, struct request *req,
311 return 1; 311 return 1;
312} 312}
313 313
314/**
315 * blk_rq_set_mixed_merge - mark a request as mixed merge
316 * @rq: request to mark as mixed merge
317 *
318 * Description:
319 * @rq is about to be mixed merged. Make sure the attributes
320 * which can be mixed are set in each bio and mark @rq as mixed
321 * merged.
322 */
323void blk_rq_set_mixed_merge(struct request *rq)
324{
325 unsigned int ff = rq->cmd_flags & REQ_FAILFAST_MASK;
326 struct bio *bio;
327
328 if (rq->cmd_flags & REQ_MIXED_MERGE)
329 return;
330
331 /*
332 * @rq will no longer represent mixable attributes for all the
333 * contained bios. It will just track those of the first one.
334 * Distributes the attributs to each bio.
335 */
336 for (bio = rq->bio; bio; bio = bio->bi_next) {
337 WARN_ON_ONCE((bio->bi_rw & REQ_FAILFAST_MASK) &&
338 (bio->bi_rw & REQ_FAILFAST_MASK) != ff);
339 bio->bi_rw |= ff;
340 }
341 rq->cmd_flags |= REQ_MIXED_MERGE;
342}
343
314static void blk_account_io_merge(struct request *req) 344static void blk_account_io_merge(struct request *req)
315{ 345{
316 if (blk_do_io_stat(req)) { 346 if (blk_do_io_stat(req)) {
@@ -366,6 +396,19 @@ static int attempt_merge(struct request_queue *q, struct request *req,
366 return 0; 396 return 0;
367 397
368 /* 398 /*
399 * If failfast settings disagree or any of the two is already
400 * a mixed merge, mark both as mixed before proceeding. This
401 * makes sure that all involved bios have mixable attributes
402 * set properly.
403 */
404 if ((req->cmd_flags | next->cmd_flags) & REQ_MIXED_MERGE ||
405 (req->cmd_flags & REQ_FAILFAST_MASK) !=
406 (next->cmd_flags & REQ_FAILFAST_MASK)) {
407 blk_rq_set_mixed_merge(req);
408 blk_rq_set_mixed_merge(next);
409 }
410
411 /*
369 * At this point we have either done a back merge 412 * At this point we have either done a back merge
370 * or front merge. We need the smaller start_time of 413 * or front merge. We need the smaller start_time of
371 * the merged requests to be the current request 414 * the merged requests to be the current request
diff --git a/block/blk.h b/block/blk.h
index 3fae6add5430..5ee3d7e72feb 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -104,6 +104,7 @@ int ll_front_merge_fn(struct request_queue *q, struct request *req,
104int attempt_back_merge(struct request_queue *q, struct request *rq); 104int attempt_back_merge(struct request_queue *q, struct request *rq);
105int attempt_front_merge(struct request_queue *q, struct request *rq); 105int attempt_front_merge(struct request_queue *q, struct request *rq);
106void blk_recalc_rq_segments(struct request *rq); 106void blk_recalc_rq_segments(struct request *rq);
107void blk_rq_set_mixed_merge(struct request *rq);
107 108
108void blk_queue_congestion_threshold(struct request_queue *q); 109void blk_queue_congestion_threshold(struct request_queue *q);
109 110