vdisk_blockio: Make COMPARE AND WRITE compatible with the scsi_debug driver

This patch fixes the following kernel oops:

BUG: unable to handle kernel paging request at ffffeae380000690
Call Trace:
 [<ffffffff812f69f9>] sg_miter_next+0x9/0xd0
 [<ffffffff812f6b60>] sg_copy_buffer+0xa0/0x100
 [<ffffffffa0507fc6>] do_device_access.isra.8+0xa6/0x150 [scsi_debug]
 [<ffffffffa05085f4>] resp_read+0xe4/0x240 [scsi_debug]
 [<ffffffffa050b285>] scsi_debug_queuecommand_lck+0x11e5/0x2060 [scsi_debug]
 [<ffffffffa050c130>] scsi_debug_queuecommand+0x30/0x48 [scsi_debug]
 [<ffffffff813fe23f>] scsi_dispatch_cmd+0xaf/0x260
 [<ffffffff814068ed>] scsi_request_fn+0x32d/0x540
 [<ffffffff812bda2a>] __blk_run_queue+0x2a/0x40
 [<ffffffff812c25a4>] blk_queue_bio+0x274/0x350
 [<ffffffff812bd878>] generic_make_request+0xa8/0xf0
 [<ffffffff812bd92c>] submit_bio+0x6c/0x140
 [<ffffffffa06247f6>] blockio_rw_sync.isra.29+0x106/0x170 [scst_vdisk]
 [<ffffffffa0629bf9>] vdisk_exec_caw+0xd9/0x3c0 [scst_vdisk]
 [<ffffffffa061ff5e>] vdev_do_job+0x9e/0x320 [scst_vdisk]
 [<ffffffffa0622c47>] non_fileio_exec+0x57/0xd0 [scst_vdisk]
 [<ffffffffa054cde2>] scst_do_real_exec+0x92/0x3b0 [scst]
 [<ffffffffa05502d2>] scst_exec_check_blocking+0xe2/0x300 [scst]
 [<ffffffffa055066b>] scst_exec_check_sn+0x17b/0x2d0 [scst]
 [<ffffffffa0553231>] scst_process_active_cmd+0x431/0x770 [scst]
 [<ffffffffa0554a0a>] scst_do_job_active+0xea/0x180 [scst]
 [<ffffffffa0554bc6>] scst_cmd_thread+0x126/0x290 [scst]
 [<ffffffff81075241>] kthread+0xc1/0xe0
 [<ffffffff81598ccc>] ret_from_fork+0x7c/0xb0

Reported-by: Sebastian Herbszt <herbszt@gmx.de>


git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5449 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Bart Van Assche
2014-04-19 11:52:34 +00:00
parent f5fd6f5375
commit 1a809721fc
+5 -2
View File
@@ -4870,8 +4870,10 @@ static ssize_t blockio_rw_sync(struct scst_vdisk_dev *virt_dev, void *buf,
{
DECLARE_COMPLETION_ONSTACK(c);
struct block_device *bdev = virt_dev->bdev;
const bool is_vmalloc = is_vmalloc_addr(buf);
struct bio *bio;
void *p;
struct page *q;
int max_nr_vecs, rc;
unsigned bytes, off;
ssize_t ret = -ENOMEM;
@@ -4898,8 +4900,9 @@ static ssize_t blockio_rw_sync(struct scst_vdisk_dev *virt_dev, void *buf,
#endif
for (p = buf; p < buf + len; p += bytes) {
off = offset_in_page(p);
bytes = PAGE_SIZE - off;
rc = bio_add_page(bio, virt_to_page(p), bytes, off);
bytes = min_t(size_t, PAGE_SIZE - off, buf + len - p);
q = is_vmalloc ? vmalloc_to_page(p) : virt_to_page(p);
rc = bio_add_page(bio, q, bytes, off);
if (WARN_ON_ONCE(rc < bytes))
goto free;
}