aboutsummaryrefslogtreecommitdiffstats
path: root/block/cfq-iosched.c
diff options
context:
space:
mode:
authorJens Axboe <jens.axboe@oracle.com>2007-04-25 05:53:48 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-04-25 11:41:48 -0400
commit5044eed48886b105a123333fe7ca97c6bd496120 (patch)
tree76233c2b177d9be75d3e1278b89ea5d3f7d87fcf /block/cfq-iosched.c
parenta23cf14b161b8deeb0f701d577a0e8be6365e247 (diff)
cfq-iosched: fix alias + front merge bug
There's a really rare and obscure bug in CFQ, that causes a crash in cfq_dispatch_insert() due to rq == NULL. One example of the resulting oops is seen here: http://lkml.org/lkml/2007/4/15/41 Neil correctly diagnosed the situation for how this can happen: if two concurrent requests with the exact same sector number (due to direct IO or aliasing between MD and the raw device access), the alias handling will add the request to the sortlist, but next_rq remains NULL. Read the more complete analysis at: http://lkml.org/lkml/2007/4/25/57 This looks like it requires md to trigger, even though it should potentially be possible to due with O_DIRECT (at least if you edit the kernel and doctor some of the unplug calls). The fix is to move the ->next_rq update to when we add a request to the rbtree. Then we remove the possibility for a request to exist in the rbtree code, but not have ->next_rq correctly updated. Signed-off-by: Jens Axboe <jens.axboe@oracle.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r--block/cfq-iosched.c12
1 files changed, 6 insertions, 6 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index 9e3797167c81..f92ba2a869b4 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -532,6 +532,12 @@ static void cfq_add_rq_rb(struct request *rq)
532 532
533 if (!cfq_cfqq_on_rr(cfqq)) 533 if (!cfq_cfqq_on_rr(cfqq))
534 cfq_add_cfqq_rr(cfqd, cfqq); 534 cfq_add_cfqq_rr(cfqd, cfqq);
535
536 /*
537 * check if this request is a better next-serve candidate
538 */
539 cfqq->next_rq = cfq_choose_req(cfqd, cfqq->next_rq, rq);
540 BUG_ON(!cfqq->next_rq);
535} 541}
536 542
537static inline void 543static inline void
@@ -1639,12 +1645,6 @@ cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
1639 cfqq->meta_pending++; 1645 cfqq->meta_pending++;
1640 1646
1641 /* 1647 /*
1642 * check if this request is a better next-serve candidate)) {
1643 */
1644 cfqq->next_rq = cfq_choose_req(cfqd, cfqq->next_rq, rq);
1645 BUG_ON(!cfqq->next_rq);
1646
1647 /*
1648 * we never wait for an async request and we don't allow preemption 1648 * we never wait for an async request and we don't allow preemption
1649 * of an async request. so just return early 1649 * of an async request. so just return early
1650 */ 1650 */