diff --git a/scst/include/scst.h b/scst/include/scst.h index e4886e843..5daaa8fcb 100644 --- a/scst/include/scst.h +++ b/scst/include/scst.h @@ -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) diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index bc76e8b26..457191282 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -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. */ diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index e9c70bb1b..1330caa71 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -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);