From 2fa4898b5e8e37a1cc829c2ff4e0b7f962e00fd5 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Fri, 5 Aug 2011 02:07:35 +0000 Subject: [PATCH] Modified patch from Bart Van Assche : 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: [] ? srpt_post_send+0xd0/0x140 [ib_srpt] [] ? cpumask_next_and+0x35/0x50 [] shmem_truncate_range+0x7a6/0xa50 [] ? scst_get_buf_full+0x16b/0x270 [scst] [] vdisk_exec_unmap+0x1d6/0x4b0 [scst_vdisk] [] ? _raw_spin_unlock+0x16/0x40 [] vdisk_do_job+0x5fc/0x950 [scst_vdisk] [] scst_do_real_exec+0xb2/0x400 [scst] [] scst_exec+0xd7/0x240 [scst] [] scst_send_for_exec+0x1a6/0x2f0 [scst] [] scst_process_active_cmd+0x4f8/0x790 [scst] [] scst_do_job_active+0x99/0x170 [scst] [] scst_cmd_thread+0x15a/0x3b0 [scst] [] ? default_wake_function+0x0/0x20 [] ? scst_cmd_thread+0x0/0x3b0 [scst] [] kthread+0x96/0xa0 [] kernel_thread_helper+0x4/0x10 [] ? finish_task_switch+0x51/0xb0 [] ? _raw_spin_unlock_irq+0x1c/0x40 [] ? restore_args+0x0/0x30 [] ? kthread+0x0/0xa0 [] ? 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 --- scst/src/dev_handlers/scst_vdisk.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 302f25b87..a9e94581c 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -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); } }