From d4c5dcacfaffb7493d161d5cd0fbb7b1190b7bd5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 22 Feb 2015 08:48:42 -0800 Subject: target: rewrite fd_execute_write_same With the new bio_vec backed iov_iter helpers we can simply set up on bio_vec per LBA, all pointing to the same initiator-supplied buffer. Signed-off-by: Christoph Hellwig Reviewed-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_file.c | 100 +++++++++----------------------------- 1 file changed, 22 insertions(+), 78 deletions(-) (limited to 'drivers/target') diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index ea6e14e3ac5a..8800d54f743b 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -433,59 +433,17 @@ fd_execute_sync_cache(struct se_cmd *cmd) return 0; } -static unsigned char * -fd_setup_write_same_buf(struct se_cmd *cmd, struct scatterlist *sg, - unsigned int len) -{ - struct se_device *se_dev = cmd->se_dev; - unsigned int block_size = se_dev->dev_attrib.block_size; - unsigned int i = 0, end; - unsigned char *buf, *p, *kmap_buf; - - buf = kzalloc(min_t(unsigned int, len, PAGE_SIZE), GFP_KERNEL); - if (!buf) { - pr_err("Unable to allocate fd_execute_write_same buf\n"); - return NULL; - } - - kmap_buf = kmap(sg_page(sg)) + sg->offset; - if (!kmap_buf) { - pr_err("kmap() failed in fd_setup_write_same\n"); - kfree(buf); - return NULL; - } - /* - * Fill local *buf to contain multiple WRITE_SAME blocks up to - * min(len, PAGE_SIZE) - */ - p = buf; - end = min_t(unsigned int, len, PAGE_SIZE); - - while (i < end) { - memcpy(p, kmap_buf, block_size); - - i += block_size; - p += block_size; - } - kunmap(sg_page(sg)); - - return buf; -} - static sense_reason_t fd_execute_write_same(struct se_cmd *cmd) { struct se_device *se_dev = cmd->se_dev; struct fd_dev *fd_dev = FD_DEV(se_dev); - struct file *f = fd_dev->fd_file; - struct scatterlist *sg; - struct iovec *iov; - mm_segment_t old_fs; - sector_t nolb = sbc_get_write_same_sectors(cmd); loff_t pos = cmd->t_task_lba * se_dev->dev_attrib.block_size; - unsigned int len, len_tmp, iov_num; - int i, rc; - unsigned char *buf; + sector_t nolb = sbc_get_write_same_sectors(cmd); + struct iov_iter iter; + struct bio_vec *bvec; + unsigned int len = 0, i; + ssize_t ret; if (!nolb) { target_complete_cmd(cmd, SAM_STAT_GOOD); @@ -496,49 +454,35 @@ 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 || - sg->length != cmd->se_dev->dev_attrib.block_size) { + cmd->t_data_sg[0].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, sg->length, + " block_size: %u\n", + cmd->t_data_nents, + cmd->t_data_sg[0].length, cmd->se_dev->dev_attrib.block_size); return TCM_INVALID_CDB_FIELD; } - len = len_tmp = nolb * se_dev->dev_attrib.block_size; - iov_num = DIV_ROUND_UP(len, PAGE_SIZE); - - buf = fd_setup_write_same_buf(cmd, sg, len); - if (!buf) + bvec = kcalloc(nolb, sizeof(struct bio_vec), GFP_KERNEL); + if (!bvec) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - iov = vzalloc(sizeof(struct iovec) * iov_num); - if (!iov) { - pr_err("Unable to allocate fd_execute_write_same iovecs\n"); - kfree(buf); - return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - } - /* - * Map the single fabric received scatterlist block now populated - * in *buf into each iovec for I/O submission. - */ - for (i = 0; i < iov_num; i++) { - iov[i].iov_base = buf; - iov[i].iov_len = min_t(unsigned int, len_tmp, PAGE_SIZE); - len_tmp -= iov[i].iov_len; - } + 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; - old_fs = get_fs(); - set_fs(get_ds()); - rc = vfs_writev(f, &iov[0], iov_num, &pos); - set_fs(old_fs); + len += se_dev->dev_attrib.block_size; + } - vfree(iov); - kfree(buf); + iov_iter_bvec(&iter, ITER_BVEC, bvec, nolb, len); + ret = vfs_iter_write(fd_dev->fd_file, &iter, &pos); - if (rc < 0 || rc != len) { - pr_err("vfs_writev() returned %d for write same\n", rc); + kfree(bvec); + if (ret < 0 || ret != len) { + pr_err("vfs_iter_write() returned %zd for write same\n", ret); return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; } -- cgit v1.2.3