If NDOB is set we don't have a buffer. We will then crash when trying to access the t_data_sg. This has us allocate a page to use for the data buffer that gets passed to vfs_iter_write. Signed-off-by: Mike Christie <michael.christie@xxxxxxxxxx> --- drivers/target/target_core_file.c | 32 +++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index e68f1cc8ef98..2011836ab7f4 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -433,6 +433,9 @@ fd_execute_write_same(struct se_cmd *cmd) struct fd_dev *fd_dev = FD_DEV(se_dev); loff_t pos = cmd->t_task_lba * se_dev->dev_attrib.block_size; sector_t nolb = sbc_get_write_same_sectors(cmd); + bool ndob = cmd->t_task_cdb[1] & 0x01; + struct scatterlist *sg, ndob_sg; + struct page *pg = NULL; struct iov_iter iter; struct bio_vec *bvec; unsigned int len = 0, i; @@ -447,13 +450,13 @@ fd_execute_write_same(struct se_cmd *cmd) " backends not supported\n"); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } + sg = &cmd->t_data_sg[0]; if (cmd->t_data_nents > 1 || - cmd->t_data_sg[0].length != cmd->se_dev->dev_attrib.block_size) { + (sg && sg->length != cmd->se_dev->dev_attrib.block_size)) { pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u" " block_size: %u\n", - cmd->t_data_nents, - cmd->t_data_sg[0].length, + cmd->t_data_nents, sg->length, cmd->se_dev->dev_attrib.block_size); return TCM_INVALID_CDB_FIELD; } @@ -462,10 +465,23 @@ fd_execute_write_same(struct se_cmd *cmd) if (!bvec) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + if (ndob) { + pg = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!pg) { + kfree(bvec); + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; + } + + sg_init_table(&ndob_sg, 1); + sg_set_page(&ndob_sg, pg, cmd->se_dev->dev_attrib.block_size, + 0); + sg = &ndob_sg; + } + for (i = 0; i < nolb; i++) { - bvec[i].bv_page = sg_page(&cmd->t_data_sg[0]); - bvec[i].bv_len = cmd->t_data_sg[0].length; - bvec[i].bv_offset = cmd->t_data_sg[0].offset; + bvec[i].bv_page = sg_page(sg); + bvec[i].bv_len = sg->length; + bvec[i].bv_offset = sg->offset; len += se_dev->dev_attrib.block_size; } @@ -474,6 +490,10 @@ fd_execute_write_same(struct se_cmd *cmd) ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos, 0); kfree(bvec); + + if (pg) + __free_page(pg); + if (ret < 0 || ret != len) { pr_err("vfs_iter_write() returned %zd for write same\n", ret); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; -- 2.25.1