scst: Avoid that scst_write_same() crashes for large data len

A quote from SBC-3 about WRITE SAME (10): "If the number of
logical blocks specified to be unmapped or written exceeds the value
indicated in the MAXIMUM WRITE SAME LENGTH field in the Block Limits
VPD page (see 6.6.3), then the device server shall terminate the command
with CHECK CONDITION status with the sense key set to ILLEGAL REQUEST
and the additional sense code set to INVALID FIELD IN CDB."

This patch fixes the following crash since with the current implementation
data_len >= 2**63 makes (unsigned)ws_sg_cnt >= 2**31 and this causes
sg_init_table() to crash as follows:

BUG: unable to handle kernel paging request at 00000027ffffffe8
IP: [<ffffffff8120d51e>] sg_init_table+0x5e/0x90
CPU: 1 PID: 10297 Comm: disk014_1 Tainted: G           O 3.11.0-debug+ #1
RIP: 0010:[<ffffffff8120d51e>]  [<ffffffff8120d51e>] sg_init_table+0x5e/0x90
Call Trace:
 [<ffffffffa02e4b46>] scst_write_same+0x236/0x340 [scst]
 [<ffffffffa034db30>] ? vdisk_exec_write_same_unmap.isra.35+0x170/0x170 [scst_vdisk]
 [<ffffffffa034dba4>] vdisk_exec_write_same+0x74/0x170 [scst_vdisk]
 [<ffffffffa034824e>] vdev_do_job+0x15e/0x390 [scst_vdisk]
 [<ffffffffa03484a5>] vdisk_exec+0x25/0x70 [scst_vdisk]
 [<ffffffffa02cafb5>] scst_do_real_exec+0xa5/0x3d0 [scst]
 [<ffffffffa02ce2da>] scst_exec_check_blocking+0xea/0x310 [scst]
 [<ffffffffa02ce695>] scst_exec_check_sn+0x195/0x2f0 [scst]
 [<ffffffffa02cff31>] scst_process_active_cmd+0x521/0x750 [scst]
 [<ffffffffa02d01e1>] scst_do_job_active+0x81/0x1a0 [scst]
 [<ffffffffa02d0537>] scst_cmd_thread+0x157/0x340 [scst]
 [<ffffffff81069ea6>] kthread+0xd6/0xe0
 [<ffffffff814debfc>] ret_from_fork+0x7c/0xb0

Signed-off-by: Bart Van Assche <bvanassche@acm.org>



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@5122 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2013-11-19 05:51:39 +00:00
parent 41f25c3e2e
commit 93eb067bef
4 changed files with 16 additions and 3 deletions

View File

@@ -2501,6 +2501,9 @@ struct scst_device {
/* List of blocked commands, protected by dev_lock. */
struct list_head blocked_cmd_list;
/* MAXIMUM WRITE SAME LENGTH in bytes */
uint64_t max_write_same_len;
/* A list entry used during TM */
struct list_head tm_dev_list_entry;

View File

@@ -2558,8 +2558,9 @@ static enum compl_status_e vdisk_exec_inquiry(struct vdisk_cmd_params *p)
}
}
/* MAXIMUM WRITE SAME LENGTH (512MB) */
put_unaligned_be64((512*1024*1024) >> dev->block_shift, &buf[36]);
/* MAXIMUM WRITE SAME LENGTH (measured in blocks) */
put_unaligned_be64(dev->max_write_same_len >>
dev->block_shift, &buf[36]);
resp_len = buf[3] + 4;
} else if ((0xB1 == cmd->cdb[2]) && (dev->type == TYPE_DISK)) {

View File

@@ -4870,7 +4870,7 @@ void scst_write_same(struct scst_cmd *cmd)
}
if (cmd->sg_cnt != 1) {
PRINT_ERROR("WRITE SAME must contain only single block of data "
PRINT_WARNING("WRITE SAME must contain only single block of data "
"in a single SG (cmd %p)", cmd);
scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_parameter_value_invalid));
goto out_done;
@@ -4881,6 +4881,14 @@ void scst_write_same(struct scst_cmd *cmd)
goto out_done;
}
if (unlikely((uint64_t)cmd->data_len > cmd->dev->max_write_same_len)) {
PRINT_WARNING("Invalid WRITE SAME data len %lld (max allowed "
"%lld)", (long long)cmd->data_len,
(long long)cmd->dev->max_write_same_len);
scst_set_invalid_field_in_cdb(cmd, cmd->len_off, 0);
goto out_done;
}
wsp = kzalloc(sizeof(*wsp), GFP_KERNEL);
if (wsp == NULL) {
PRINT_ERROR("Unable to allocate ws_priv (size %zd, cmd %p)",

View File

@@ -2080,6 +2080,7 @@ assign:
dev->threads_num = handler->threads_num;
dev->threads_pool_type = handler->threads_pool_type;
dev->max_write_same_len = 512 * 1024 * 1024; /* 512 MB */
if (handler->attach) {
TRACE_DBG("Calling new dev handler's attach(%p)", dev);