diff options
author | Tejun Heo <tj@kernel.org> | 2012-03-23 09:02:53 -0400 |
---|---|---|
committer | Jens Axboe <axboe@kernel.dk> | 2012-03-23 09:02:53 -0400 |
commit | eb7d8c07f9c5fca6190b0d328179551122d1b8a3 (patch) | |
tree | b75cd8a91faee93990ec03f0044d24111e51a918 /block/cfq-iosched.c | |
parent | 2b566fa55b9a94b53217c2818e6c5e5756eeb1a1 (diff) |
cfq: fix cfqg ref handling when BLK_CGROUP && !CFQ_GROUP_IOSCHED
When BLK_CGROUP is enabled but CFQ_GROUP_IOSCHED is, cfq ends up
calling blkg_get/put() on dummy cfqg leading to the following crash.
BUG: unable to handle kernel NULL pointer dereference at 00000000000000b0
IP: [<ffffffff813d44d8>] cfq_init_queue+0x258/0x430
PGD 0
Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC
CPU 0
Modules linked in:
Pid: 1, comm: swapper/0 Not tainted 3.3.0-rc6-work+ #125 Bochs Bochs
RIP: 0010:[<ffffffff813d44d8>] [<ffffffff813d44d8>] cfq_init_queue+0x258/0x430
RSP: 0018:ffff88001f9dfd80 EFLAGS: 00010046
RAX: ffff88001aefbbf0 RBX: ffff88001aeedbf0 RCX: 0000000000000100
RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffffffff820ffd40
RBP: ffff88001f9dfdd0 R08: 0000000000000000 R09: 0000000000000001
R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000000
R13: 0000000000000009 R14: ffff88001aefbc30 R15: 0000000000000003
FS: 0000000000000000(0000) GS:ffff88001fc00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
CR2: 00000000000000b0 CR3: 000000000206f000 CR4: 00000000000006f0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process swapper/0 (pid: 1, threadinfo ffff88001f9de000, task ffff88001f9dc040)
Stack:
ffff88001aeedbf0 ffff88001aefbdb0 ffff88001aef1548 ffff88001aefbbf0
ffff88001f9dfdd0 ffff88001aef1548 ffffffff820d6320 ffffffff8165ce30
ffffffff82c555e0 ffff88001aeebbf0 ffff88001f9dfe00 ffffffff813b0507
Call Trace:
[<ffffffff813b0507>] elevator_init+0xd7/0x140
[<ffffffff813b83d5>] blk_init_allocated_queue+0x125/0x150
[<ffffffff813b94d3>] blk_init_queue_node+0x43/0x80
[<ffffffff813b9523>] blk_init_queue+0x13/0x20
[<ffffffff821aec00>] floppy_init+0x82/0xec7
[<ffffffff810001d2>] do_one_initcall+0x42/0x170
[<ffffffff821835fc>] kernel_init+0xcb/0x14f
[<ffffffff81b40b24>] kernel_thread_helper+0x4/0x10
Code: 00 e8 1d 9e 76 00 48 8b 43 48 48 85 c0 48 89 83 28 03 00 00 74 07 4c 8b a0 10 ff ff ff 8b 15 b0 2e d0 00 85 d2 0f 85 49 01 00 00 <41> 8b 84 24 b0 00 00 00 85 c0 0f 8e 8c 01 00 00 83 e8 01 85 c0
RIP [<ffffffff813d44d8>] cfq_init_queue+0x258/0x430
Because cfq's blkcg support has a on/off switch, CFQ_GROUP_IOSCHED,
separate from BLK_CGROUP, blkg access through cfqg needs to be
conditioned on it.
* Make blkg_to_cfqg() and cfqg_to_blkg() conditioned on
CFQ_GROUP_IOSCHED. If disabled, they always return %NULL.
* Introduce cfqg_get() and cfqg_put() conditioned on
CFQ_GROUP_IOSCHED. If disabled, they are noops.
Reported-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/cfq-iosched.c')
-rw-r--r-- | block/cfq-iosched.c | 52 |
1 files changed, 35 insertions, 17 deletions
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c index 7c3893d4447a..39c43307dc6c 100644 --- a/block/cfq-iosched.c +++ b/block/cfq-iosched.c | |||
@@ -306,16 +306,6 @@ struct cfq_data { | |||
306 | unsigned long last_delayed_sync; | 306 | unsigned long last_delayed_sync; |
307 | }; | 307 | }; |
308 | 308 | ||
309 | static inline struct cfq_group *blkg_to_cfqg(struct blkio_group *blkg) | ||
310 | { | ||
311 | return blkg_to_pdata(blkg, &blkio_policy_cfq); | ||
312 | } | ||
313 | |||
314 | static inline struct blkio_group *cfqg_to_blkg(struct cfq_group *cfqg) | ||
315 | { | ||
316 | return pdata_to_blkg(cfqg, &blkio_policy_cfq); | ||
317 | } | ||
318 | |||
319 | static struct cfq_group *cfq_get_next_cfqg(struct cfq_data *cfqd); | 309 | static struct cfq_group *cfq_get_next_cfqg(struct cfq_data *cfqd); |
320 | 310 | ||
321 | static struct cfq_rb_root *service_tree_for(struct cfq_group *cfqg, | 311 | static struct cfq_rb_root *service_tree_for(struct cfq_group *cfqg, |
@@ -377,6 +367,26 @@ CFQ_CFQQ_FNS(wait_busy); | |||
377 | #undef CFQ_CFQQ_FNS | 367 | #undef CFQ_CFQQ_FNS |
378 | 368 | ||
379 | #ifdef CONFIG_CFQ_GROUP_IOSCHED | 369 | #ifdef CONFIG_CFQ_GROUP_IOSCHED |
370 | static inline struct cfq_group *blkg_to_cfqg(struct blkio_group *blkg) | ||
371 | { | ||
372 | return blkg_to_pdata(blkg, &blkio_policy_cfq); | ||
373 | } | ||
374 | |||
375 | static inline struct blkio_group *cfqg_to_blkg(struct cfq_group *cfqg) | ||
376 | { | ||
377 | return pdata_to_blkg(cfqg, &blkio_policy_cfq); | ||
378 | } | ||
379 | |||
380 | static inline void cfqg_get(struct cfq_group *cfqg) | ||
381 | { | ||
382 | return blkg_get(cfqg_to_blkg(cfqg)); | ||
383 | } | ||
384 | |||
385 | static inline void cfqg_put(struct cfq_group *cfqg) | ||
386 | { | ||
387 | return blkg_put(cfqg_to_blkg(cfqg)); | ||
388 | } | ||
389 | |||
380 | #define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \ | 390 | #define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \ |
381 | blk_add_trace_msg((cfqd)->queue, "cfq%d%c %s " fmt, (cfqq)->pid, \ | 391 | blk_add_trace_msg((cfqd)->queue, "cfq%d%c %s " fmt, (cfqq)->pid, \ |
382 | cfq_cfqq_sync((cfqq)) ? 'S' : 'A', \ | 392 | cfq_cfqq_sync((cfqq)) ? 'S' : 'A', \ |
@@ -386,11 +396,19 @@ CFQ_CFQQ_FNS(wait_busy); | |||
386 | blk_add_trace_msg((cfqd)->queue, "%s " fmt, \ | 396 | blk_add_trace_msg((cfqd)->queue, "%s " fmt, \ |
387 | blkg_path(cfqg_to_blkg((cfqg))), ##args) \ | 397 | blkg_path(cfqg_to_blkg((cfqg))), ##args) \ |
388 | 398 | ||
389 | #else | 399 | #else /* CONFIG_CFQ_GROUP_IOSCHED */ |
400 | |||
401 | static inline struct cfq_group *blkg_to_cfqg(struct blkio_group *blkg) { return NULL; } | ||
402 | static inline struct blkio_group *cfqg_to_blkg(struct cfq_group *cfqg) { return NULL; } | ||
403 | static inline void cfqg_get(struct cfq_group *cfqg) { } | ||
404 | static inline void cfqg_put(struct cfq_group *cfqg) { } | ||
405 | |||
390 | #define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \ | 406 | #define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \ |
391 | blk_add_trace_msg((cfqd)->queue, "cfq%d " fmt, (cfqq)->pid, ##args) | 407 | blk_add_trace_msg((cfqd)->queue, "cfq%d " fmt, (cfqq)->pid, ##args) |
392 | #define cfq_log_cfqg(cfqd, cfqg, fmt, args...) do {} while (0) | 408 | #define cfq_log_cfqg(cfqd, cfqg, fmt, args...) do {} while (0) |
393 | #endif | 409 | |
410 | #endif /* CONFIG_CFQ_GROUP_IOSCHED */ | ||
411 | |||
394 | #define cfq_log(cfqd, fmt, args...) \ | 412 | #define cfq_log(cfqd, fmt, args...) \ |
395 | blk_add_trace_msg((cfqd)->queue, "cfq " fmt, ##args) | 413 | blk_add_trace_msg((cfqd)->queue, "cfq " fmt, ##args) |
396 | 414 | ||
@@ -1090,7 +1108,7 @@ static void cfq_link_cfqq_cfqg(struct cfq_queue *cfqq, struct cfq_group *cfqg) | |||
1090 | 1108 | ||
1091 | cfqq->cfqg = cfqg; | 1109 | cfqq->cfqg = cfqg; |
1092 | /* cfqq reference on cfqg */ | 1110 | /* cfqq reference on cfqg */ |
1093 | blkg_get(cfqg_to_blkg(cfqg)); | 1111 | cfqg_get(cfqg); |
1094 | } | 1112 | } |
1095 | 1113 | ||
1096 | #else /* GROUP_IOSCHED */ | 1114 | #else /* GROUP_IOSCHED */ |
@@ -2505,7 +2523,7 @@ static void cfq_put_queue(struct cfq_queue *cfqq) | |||
2505 | 2523 | ||
2506 | BUG_ON(cfq_cfqq_on_rr(cfqq)); | 2524 | BUG_ON(cfq_cfqq_on_rr(cfqq)); |
2507 | kmem_cache_free(cfq_pool, cfqq); | 2525 | kmem_cache_free(cfq_pool, cfqq); |
2508 | blkg_put(cfqg_to_blkg(cfqg)); | 2526 | cfqg_put(cfqg); |
2509 | } | 2527 | } |
2510 | 2528 | ||
2511 | static void cfq_put_cooperator(struct cfq_queue *cfqq) | 2529 | static void cfq_put_cooperator(struct cfq_queue *cfqq) |
@@ -3276,7 +3294,7 @@ static void cfq_put_request(struct request *rq) | |||
3276 | cfqq->allocated[rw]--; | 3294 | cfqq->allocated[rw]--; |
3277 | 3295 | ||
3278 | /* Put down rq reference on cfqg */ | 3296 | /* Put down rq reference on cfqg */ |
3279 | blkg_put(cfqg_to_blkg(RQ_CFQG(rq))); | 3297 | cfqg_put(RQ_CFQG(rq)); |
3280 | rq->elv.priv[0] = NULL; | 3298 | rq->elv.priv[0] = NULL; |
3281 | rq->elv.priv[1] = NULL; | 3299 | rq->elv.priv[1] = NULL; |
3282 | 3300 | ||
@@ -3364,7 +3382,7 @@ new_queue: | |||
3364 | cfqq->allocated[rw]++; | 3382 | cfqq->allocated[rw]++; |
3365 | 3383 | ||
3366 | cfqq->ref++; | 3384 | cfqq->ref++; |
3367 | blkg_get(cfqg_to_blkg(cfqq->cfqg)); | 3385 | cfqg_get(cfqq->cfqg); |
3368 | rq->elv.priv[0] = cfqq; | 3386 | rq->elv.priv[0] = cfqq; |
3369 | rq->elv.priv[1] = cfqq->cfqg; | 3387 | rq->elv.priv[1] = cfqq->cfqg; |
3370 | spin_unlock_irq(q->queue_lock); | 3388 | spin_unlock_irq(q->queue_lock); |
@@ -3545,7 +3563,7 @@ static int cfq_init_queue(struct request_queue *q) | |||
3545 | 3563 | ||
3546 | spin_lock_irq(q->queue_lock); | 3564 | spin_lock_irq(q->queue_lock); |
3547 | cfq_link_cfqq_cfqg(&cfqd->oom_cfqq, cfqd->root_group); | 3565 | cfq_link_cfqq_cfqg(&cfqd->oom_cfqq, cfqd->root_group); |
3548 | blkg_put(cfqg_to_blkg(cfqd->root_group)); | 3566 | cfqg_put(cfqd->root_group); |
3549 | spin_unlock_irq(q->queue_lock); | 3567 | spin_unlock_irq(q->queue_lock); |
3550 | 3568 | ||
3551 | init_timer(&cfqd->idle_slice_timer); | 3569 | init_timer(&cfqd->idle_slice_timer); |