diff options
author | Ming Lei <ming.lei@canonical.com> | 2015-08-09 03:41:50 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2015-08-15 11:45:19 -0400 |
commit | 596f5aad2a704b72934e5abec1b1b4114c16f45b (patch) | |
tree | 023d281a8921d55c79050e35117d4a67df53a485 | |
parent | 2ec3182f9c20a9eef0dacc0512cf2ca2df7be5ad (diff) |
blk-mq: fix buffer overflow when reading sysfs file of 'pending'
There may be lots of pending requests so that the buffer of PAGE_SIZE
can't hold them at all.
One typical example is scsi-mq, the queue depth(.can_queue) of
scsi_host and blk-mq is quite big but scsi_device's queue_depth
is a bit small(.cmd_per_lun), then it is quite easy to have lots
of pending requests in hw queue.
This patch fixes the following warning and the related memory
destruction.
[ 359.025101] fill_read_buffer: blk_mq_hw_sysfs_show+0x0/0x7d returned bad count^M
[ 359.055595] irq event stamp: 15537^M
[ 359.055606] general protection fault: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC ^M
[ 359.055614] Dumping ftrace buffer:^M
[ 359.055660] (ftrace buffer empty)^M
[ 359.055672] Modules linked in: nbd ipv6 kvm_intel kvm serio_raw^M
[ 359.055678] CPU: 4 PID: 21631 Comm: stress-ng-sysfs Not tainted 4.2.0-rc5-next-20150805 #434^M
[ 359.055679] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011^M
[ 359.055682] task: ffff8802161cc000 ti: ffff88021b4a8000 task.ti: ffff88021b4a8000^M
[ 359.055693] RIP: 0010:[<ffffffff811541c5>] [<ffffffff811541c5>] __kmalloc+0xe8/0x152^M
Cc: <stable@vger.kernel.org>
Signed-off-by: Ming Lei <ming.lei@canonical.com>
Signed-off-by: Jens Axboe <axboe@fb.com>
-rw-r--r-- | block/blk-mq-sysfs.c | 25 |
1 files changed, 18 insertions, 7 deletions
diff --git a/block/blk-mq-sysfs.c b/block/blk-mq-sysfs.c index b79685e06b70..279c5d674edf 100644 --- a/block/blk-mq-sysfs.c +++ b/block/blk-mq-sysfs.c | |||
@@ -141,15 +141,26 @@ static ssize_t blk_mq_sysfs_completed_show(struct blk_mq_ctx *ctx, char *page) | |||
141 | 141 | ||
142 | static ssize_t sysfs_list_show(char *page, struct list_head *list, char *msg) | 142 | static ssize_t sysfs_list_show(char *page, struct list_head *list, char *msg) |
143 | { | 143 | { |
144 | char *start_page = page; | ||
145 | struct request *rq; | 144 | struct request *rq; |
145 | int len = snprintf(page, PAGE_SIZE - 1, "%s:\n", msg); | ||
146 | |||
147 | list_for_each_entry(rq, list, queuelist) { | ||
148 | const int rq_len = 2 * sizeof(rq) + 2; | ||
149 | |||
150 | /* if the output will be truncated */ | ||
151 | if (PAGE_SIZE - 1 < len + rq_len) { | ||
152 | /* backspacing if it can't hold '\t...\n' */ | ||
153 | if (PAGE_SIZE - 1 < len + 5) | ||
154 | len -= rq_len; | ||
155 | len += snprintf(page + len, PAGE_SIZE - 1 - len, | ||
156 | "\t...\n"); | ||
157 | break; | ||
158 | } | ||
159 | len += snprintf(page + len, PAGE_SIZE - 1 - len, | ||
160 | "\t%p\n", rq); | ||
161 | } | ||
146 | 162 | ||
147 | page += sprintf(page, "%s:\n", msg); | 163 | return len; |
148 | |||
149 | list_for_each_entry(rq, list, queuelist) | ||
150 | page += sprintf(page, "\t%p\n", rq); | ||
151 | |||
152 | return page - start_page; | ||
153 | } | 164 | } |
154 | 165 | ||
155 | static ssize_t blk_mq_sysfs_rq_list_show(struct blk_mq_ctx *ctx, char *page) | 166 | static ssize_t blk_mq_sysfs_rq_list_show(struct blk_mq_ctx *ctx, char *page) |