mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-19 21:56:31 +00:00
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:
@@ -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)
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user