Modified patch from Bart Van Assche <bvanassche@acm.org>:

The range unmapped by the scst_vdisk handler when processing an UNMAP command
is not correct. The patch below fixes that and also prevents that the following
kernel crash can be triggered on the target:

Call Trace:
 [<ffffffffa06b5350>] ? srpt_post_send+0xd0/0x140 [ib_srpt]
 [<ffffffff811bb595>] ? cpumask_next_and+0x35/0x50
 [<ffffffff810e6296>] shmem_truncate_range+0x7a6/0xa50
 [<ffffffffa0612ceb>] ? scst_get_buf_full+0x16b/0x270 [scst]
 [<ffffffffa069beb6>] vdisk_exec_unmap+0x1d6/0x4b0 [scst_vdisk]
 [<ffffffff813c0cb6>] ? _raw_spin_unlock+0x16/0x40
 [<ffffffffa069dadc>] vdisk_do_job+0x5fc/0x950 [scst_vdisk]
 [<ffffffffa0605402>] scst_do_real_exec+0xb2/0x400 [scst]
 [<ffffffffa06076a7>] scst_exec+0xd7/0x240 [scst]
 [<ffffffffa06079b6>] scst_send_for_exec+0x1a6/0x2f0 [scst]
 [<ffffffffa06086f8>] scst_process_active_cmd+0x4f8/0x790 [scst]
 [<ffffffffa0608a29>] scst_do_job_active+0x99/0x170 [scst]
 [<ffffffffa060a3da>] scst_cmd_thread+0x15a/0x3b0 [scst]
 [<ffffffff81047470>] ? default_wake_function+0x0/0x20
 [<ffffffffa060a280>] ? scst_cmd_thread+0x0/0x3b0 [scst]
 [<ffffffff8106dc26>] kthread+0x96/0xa0
 [<ffffffff81003cd4>] kernel_thread_helper+0x4/0x10
 [<ffffffff8103db01>] ? finish_task_switch+0x51/0xb0
 [<ffffffff813c0c7c>] ? _raw_spin_unlock_irq+0x1c/0x40
 [<ffffffff813c18b1>] ? restore_args+0x0/0x30
 [<ffffffff8106db90>] ? kthread+0x0/0xa0
 [<ffffffff81003cd0>] ? kernel_thread_helper+0x0/0x10

Invoking truncate_range() with an end len that is not page-size aligned
triggers it. In other words, with a block size that is below
PAGE_CACHE_SIZE some UNMAP commands could trigger a kernel bug. I think
it's better to print an error message and to skip an UNMAP command
instead of triggering a kernel oops.



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@3799 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2011-08-05 02:07:35 +00:00
parent 47170d1578
commit 2fa4898b5e

View File

@@ -1370,12 +1370,22 @@ static void vdisk_exec_unmap(struct scst_cmd *cmd, struct scst_vdisk_thr *thr)
goto out_put;
#endif
} else {
const int block_shift = virt_dev->block_shift;
/*
* We are guaranteed by thin_provisioned flag
* that truncate_range is not NULL.
*/
if (((start + len) << block_shift) &
(PAGE_CACHE_SIZE - 1)) {
PRINT_ERROR("Invalid UNMAP range [%llu, %llu); "
"block size = %d", start, start + len,
virt_dev->block_size);
goto out_put;
}
inode->i_op->truncate_range(inode,
start, start + len);
start << block_shift,
((start + len) << block_shift) - 1);
}
}