diff --git a/scst/src/dev_handlers/scst_vdisk.c b/scst/src/dev_handlers/scst_vdisk.c index 5c5baa22c..56fd89639 100644 --- a/scst/src/dev_handlers/scst_vdisk.c +++ b/scst/src/dev_handlers/scst_vdisk.c @@ -3234,6 +3234,24 @@ static enum scst_exec_res fileio_exec(struct scst_cmd *cmd) return vdev_do_job(cmd, ops); } +struct scst_verify_work { + struct work_struct work; + struct scst_cmd *cmd; +}; + +static void scst_do_verify_work(struct work_struct *work) +{ + struct scst_verify_work *w = container_of(work, typeof(*w), work); + struct scst_cmd *cmd = w->cmd; + struct scst_device *dev = cmd->dev; + loff_t loff = scst_cmd_get_lba(cmd) << dev->block_shift; + + kfree(w); + WARN_ON_ONCE(vdev_verify(cmd, loff) != CMD_SUCCEEDED); + cmd->completed = 1; + cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME); +} + #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) static bool do_fileio_async(const struct vdisk_cmd_params *p) { @@ -3280,14 +3298,27 @@ static void fileio_async_complete(struct kiocb *iocb, long ret, long ret2) WARN_ON_ONCE(ret >= 0 && ret != cmd->bufflen); if (ret < 0 && - scst_cmd_get_data_direction(cmd) & SCST_DATA_WRITE) + scst_cmd_get_data_direction(cmd) & SCST_DATA_WRITE) { scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_write_error)); - else if (ret < 0) + } else if (ret < 0) { scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); - else + } else if (cmd->do_verify) { + struct scst_verify_work *w = kmalloc(sizeof(*w), GFP_ATOMIC); + + cmd->do_verify = false; + if (w) { + INIT_WORK(&w->work, scst_do_verify_work); + w->cmd = cmd; + schedule_work(&w->work); + return; + } else { + scst_set_busy(cmd); + } + } else { scst_set_resp_data_len(cmd, ret); + } cmd->completed = 1; cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME); } @@ -6257,24 +6288,6 @@ out_nomem: goto out; } -struct scst_verify_work { - struct work_struct work; - struct scst_cmd *cmd; -}; - -static void scst_do_verify_work(struct work_struct *work) -{ - struct scst_verify_work *w = container_of(work, typeof(*w), work); - struct scst_cmd *cmd = w->cmd; - struct scst_device *dev = cmd->dev; - loff_t loff = scst_cmd_get_lba(cmd) << dev->block_shift; - - kfree(w); - WARN_ON_ONCE(vdev_verify(cmd, loff) != CMD_SUCCEEDED); - cmd->completed = 1; - cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT, SCST_CONTEXT_SAME); -} - struct scst_blockio_work { atomic_t bios_inflight; struct scst_cmd *cmd; @@ -7246,7 +7259,13 @@ static enum compl_status_e blockio_exec_write_verify(struct vdisk_cmd_params *p) static enum compl_status_e fileio_exec_write_verify(struct vdisk_cmd_params *p) { - fileio_exec_write(p); + enum compl_status_e ret; + + p->cmd->do_verify = true; + ret = fileio_exec_write(p); + if (ret != CMD_SUCCEEDED) + return ret; + p->cmd->do_verify = false; /* O_DSYNC flag is used for WT devices */ if (scsi_status_is_good(p->cmd->status)) vdev_exec_verify(p);