Fixes possible NULL cmd dereference in vdisk_fsync() noticed by Bart Van

Assche + possible calls of VERIFY commands for BLOCKIO devices



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@3921 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2011-11-16 00:00:40 +00:00
parent 7ac9532359
commit 1e547f1aae
3 changed files with 35 additions and 15 deletions
+5
View File
@@ -3863,6 +3863,11 @@ static inline int scst_get_out_buf_count(struct scst_cmd *cmd)
int scst_get_buf_full(struct scst_cmd *cmd, uint8_t **buf);
void scst_put_buf_full(struct scst_cmd *cmd, uint8_t *buf);
static inline gfp_t scst_cmd_get_gfp_flags(struct scst_cmd *cmd)
{
return cmd->noio_mem_alloc ? GFP_NOIO : GFP_KERNEL;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) && !defined(BACKPORT_LINUX_WORKQUEUE_TO_2_6_19)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20))
static inline int cancel_delayed_work_sync(struct delayed_work *work)
+29 -14
View File
@@ -228,7 +228,8 @@ static void vdisk_exec_read_toc(struct scst_cmd *cmd);
static void vdisk_exec_prevent_allow_medium_removal(struct scst_cmd *cmd);
static void vdisk_exec_unmap(struct scst_cmd *cmd, struct scst_vdisk_thr *thr);
static int vdisk_fsync(struct scst_vdisk_thr *thr, loff_t loff,
loff_t len, struct scst_cmd *cmd, struct scst_device *dev);
loff_t len, struct scst_device *dev, gfp_t gfp_flags,
struct scst_cmd *cmd);
#ifdef CONFIG_SCST_PROC
static int vdisk_read_proc(struct seq_file *seq,
struct scst_dev_type *dev_type);
@@ -957,7 +958,7 @@ static int vdisk_do_job(struct scst_cmd *cmd)
d = scst_find_thr_data(tgt_dev);
if (unlikely(d == NULL)) {
thr = vdisk_init_thr_data(tgt_dev,
cmd->noio_mem_alloc ? GFP_NOIO : GFP_KERNEL);
scst_cmd_get_gfp_flags(cmd));
if (thr == NULL) {
scst_set_busy(cmd);
goto out_compl;
@@ -1074,7 +1075,8 @@ static int vdisk_do_job(struct scst_cmd *cmd)
vdisk_exec_write(cmd, thr, loff);
/* O_SYNC flag is used for WT devices */
if (fua)
vdisk_fsync(thr, loff, data_len, cmd, dev);
vdisk_fsync(thr, loff, data_len, dev,
scst_cmd_get_gfp_flags(cmd), cmd);
break;
}
case WRITE_VERIFY:
@@ -1082,6 +1084,8 @@ static int vdisk_do_job(struct scst_cmd *cmd)
case WRITE_VERIFY_16:
{
/* ToDo: BLOCKIO VERIFY */
if (virt_dev->blockio)
goto out_invalid_opcode;
vdisk_exec_write(cmd, thr, loff);
/* O_SYNC flag is used for WT devices */
if (scsi_status_is_good(cmd->status))
@@ -1100,12 +1104,14 @@ static int vdisk_do_job(struct scst_cmd *cmd)
cmd->completed = 1;
cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT,
SCST_CONTEXT_SAME);
vdisk_fsync(thr, loff, data_len, NULL, dev);
vdisk_fsync(thr, loff, data_len, dev,
scst_cmd_get_gfp_flags(cmd), NULL);
/* ToDo: vdisk_fsync() error processing */
scst_cmd_put(cmd);
goto out_thr;
} else {
vdisk_fsync(thr, loff, data_len, cmd, dev);
vdisk_fsync(thr, loff, data_len, dev,
scst_cmd_get_gfp_flags(cmd), cmd);
break;
}
}
@@ -1134,7 +1140,8 @@ static int vdisk_do_job(struct scst_cmd *cmd)
vdisk_exec_read_toc(cmd);
break;
case START_STOP:
vdisk_fsync(thr, 0, virt_dev->file_size, cmd, dev);
vdisk_fsync(thr, 0, virt_dev->file_size, dev,
scst_cmd_get_gfp_flags(cmd), cmd);
break;
case RESERVE:
case RESERVE_10:
@@ -1353,7 +1360,7 @@ static void vdisk_exec_unmap(struct scst_cmd *cmd, struct scst_vdisk_thr *thr)
if (virt_dev->blockio) {
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27)
gfp_t gfp = cmd->noio_mem_alloc ? GFP_NOIO : GFP_KERNEL;
gfp_t gfp = scst_cmd_get_gfp_flags(cmd);
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 31)
err = blkdev_issue_discard(inode->i_bdev, start, len,
gfp);
@@ -2633,7 +2640,8 @@ static void vdisk_exec_prevent_allow_medium_removal(struct scst_cmd *cmd)
}
static int vdisk_fsync(struct scst_vdisk_thr *thr, loff_t loff,
loff_t len, struct scst_cmd *cmd, struct scst_device *dev)
loff_t len, struct scst_device *dev, gfp_t gfp_flags,
struct scst_cmd *cmd)
{
int res = 0;
struct scst_vdisk_dev *virt_dev = dev->dh_priv;
@@ -2641,14 +2649,18 @@ static int vdisk_fsync(struct scst_vdisk_thr *thr, loff_t loff,
TRACE_ENTRY();
/* Hopefully, the compiler will generate the single comparison */
/**
** !!! CAUTION !!!: cmd can be NULL here! Don't use it for
** anything without checking for NULL at first !!!
**/
/* It should be generated by compiler as a single comparison */
if (virt_dev->nv_cache || virt_dev->wt_flag ||
virt_dev->o_direct_flag || virt_dev->nullio)
goto out;
if (virt_dev->blockio) {
res = vdisk_blockio_flush(thr->bdev,
(cmd->noio_mem_alloc ? GFP_NOIO : GFP_KERNEL), true);
res = vdisk_blockio_flush(thr->bdev, gfp_flags, true);
goto out;
}
@@ -3043,7 +3055,7 @@ static void blockio_exec_rw(struct scst_cmd *cmd, struct scst_vdisk_thr *thr,
int need_new_bio;
struct scst_blockio_work *blockio_work;
int bios = 0;
gfp_t gfp_mask = (cmd->noio_mem_alloc ? GFP_NOIO : GFP_KERNEL);
gfp_t gfp_mask = scst_cmd_get_gfp_flags(cmd);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
struct blk_plug plug;
#endif
@@ -3229,14 +3241,17 @@ static void vdisk_exec_verify(struct scst_cmd *cmd,
TRACE_ENTRY();
if (vdisk_fsync(thr, loff, cmd->bufflen, cmd, cmd->dev) != 0)
sBUG_ON(virt_dev->blockio);
if (vdisk_fsync(thr, loff, cmd->bufflen, cmd->dev,
scst_cmd_get_gfp_flags(cmd), cmd) != 0)
goto out;
/*
* Until the cache is cleared prior the verifying, there is not
* much point in this code. ToDo.
*
* Nevertherless, this code is valuable if the data have not read
* Nevertherless, this code is valuable if the data have not been read
* from the file/disk yet.
*/
+1 -1
View File
@@ -4736,7 +4736,7 @@ int scst_scsi_exec_async(struct scst_cmd *cmd, void *data,
struct request *rq;
struct scsi_io_context *sioc;
int write = (cmd->data_direction & SCST_DATA_WRITE) ? WRITE : READ;
gfp_t gfp = cmd->noio_mem_alloc ? GFP_NOIO : GFP_KERNEL;
gfp_t gfp = scst_cmd_get_gfp_flags(cmd);
int cmd_len = cmd->cdb_len;
sioc = kmem_cache_zalloc(scsi_io_context_cache, gfp);