aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorJianpeng Ma <majianpeng@gmail.com>2013-07-03 07:25:24 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-08-20 11:43:03 -0400
commita6ad83fce072869921cef7c6f4e86bd91639dc34 (patch)
tree4530efd7361b1a8e95229a84ccb2229e1035aba1 /include
parentdead45bd0527751cc9e71c0547d8f19f498441ed (diff)
elevator: Fix a race in elevator switching
commit d50235b7bc3ee0a0427984d763ea7534149531b4 upstream. There's a race between elevator switching and normal io operation. Because the allocation of struct elevator_queue and struct elevator_data don't in a atomic operation.So there are have chance to use NULL ->elevator_data. For example: Thread A: Thread B blk_queu_bio elevator_switch spin_lock_irq(q->queue_block) elevator_alloc elv_merge elevator_init_fn Because call elevator_alloc, it can't hold queue_lock and the ->elevator_data is NULL.So at the same time, threadA call elv_merge and nedd some info of elevator_data.So the crash happened. Move the elevator_alloc into func elevator_init_fn, it make the operations in a atomic operation. Using the follow method can easy reproduce this bug 1:dd if=/dev/sdb of=/dev/null 2:while true;do echo noop > scheduler;echo deadline > scheduler;done The test method also use this method. Signed-off-by: Jianpeng Ma <majianpeng@gmail.com> Signed-off-by: Jens Axboe <axboe@kernel.dk> Cc: Jonghwan Choi <jhbird.choi@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'include')
-rw-r--r--include/linux/elevator.h6
1 files changed, 5 insertions, 1 deletions
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index acd0312d46fb..306dd8cd0b6f 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -7,6 +7,7 @@
7#ifdef CONFIG_BLOCK 7#ifdef CONFIG_BLOCK
8 8
9struct io_cq; 9struct io_cq;
10struct elevator_type;
10 11
11typedef int (elevator_merge_fn) (struct request_queue *, struct request **, 12typedef int (elevator_merge_fn) (struct request_queue *, struct request **,
12 struct bio *); 13 struct bio *);
@@ -35,7 +36,8 @@ typedef void (elevator_put_req_fn) (struct request *);
35typedef void (elevator_activate_req_fn) (struct request_queue *, struct request *); 36typedef void (elevator_activate_req_fn) (struct request_queue *, struct request *);
36typedef void (elevator_deactivate_req_fn) (struct request_queue *, struct request *); 37typedef void (elevator_deactivate_req_fn) (struct request_queue *, struct request *);
37 38
38typedef int (elevator_init_fn) (struct request_queue *); 39typedef int (elevator_init_fn) (struct request_queue *,
40 struct elevator_type *e);
39typedef void (elevator_exit_fn) (struct elevator_queue *); 41typedef void (elevator_exit_fn) (struct elevator_queue *);
40 42
41struct elevator_ops 43struct elevator_ops
@@ -155,6 +157,8 @@ extern int elevator_init(struct request_queue *, char *);
155extern void elevator_exit(struct elevator_queue *); 157extern void elevator_exit(struct elevator_queue *);
156extern int elevator_change(struct request_queue *, const char *); 158extern int elevator_change(struct request_queue *, const char *);
157extern bool elv_rq_merge_ok(struct request *, struct bio *); 159extern bool elv_rq_merge_ok(struct request *, struct bio *);
160extern struct elevator_queue *elevator_alloc(struct request_queue *,
161 struct elevator_type *);
158 162
159/* 163/*
160 * Helper functions. 164 * Helper functions.