* [PATCH] target/file: Add WRITE_SAME w/ UNMAP=0 emulation support
@ 2013-02-20 1:43 Nicholas A. Bellinger
2013-02-20 3:17 ` Asias He
0 siblings, 1 reply; 3+ messages in thread
From: Nicholas A. Bellinger @ 2013-02-20 1:43 UTC (permalink / raw)
To: target-devel
Cc: linux-scsi, Nicholas Bellinger, Martin K. Petersen,
Christoph Hellwig, Asias He
From: Nicholas Bellinger <nab@linux-iscsi.org>
Hi mkp, hch, & Co,
Please review this patch to add support for WRITE_SAME w/ UNMAP=0
emulation into FILEIO, as I'd really like to include this in the
upcoming for-3.9 target merge.
Thank you,
--nab
---------------------------------------------------------------------
This patch adds support for emulation of WRITE_SAME w/ UNMAP=0 within
fd_execute_write_same() backend code.
The emulation uses vfs_writev() to submit a locally populated buffer
from the received WRITE_SAME scatterlist block for duplication, and by
default enforces a limit of max_write_same_len=0x1000 (8192) sectors up
to the limit of 1024 iovec entries for the single call to vfs_writev().
It also sets max_write_same_len to the operational default at setup ->
fd_configure_device() time.
Tested with 512, 1k, 2k, and 4k block_sizes.
Cc: Martin K. Petersen <martin.petersen@oracle.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Asias He <asias@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
---
drivers/target/target_core_file.c | 115 +++++++++++++++++++++++++++++++++++++
1 files changed, 115 insertions(+), 0 deletions(-)
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index b9c8849..0b71509 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -190,6 +190,11 @@ static int fd_configure_device(struct se_device *dev)
fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
fd_dev->fd_queue_depth = dev->queue_depth;
+ /*
+ * Limit WRITE_SAME w/ UNMAP=0 emulation to 8k Number of LBAs (NoLB)
+ * based upon struct iovec limit for vfs_writev()
+ */
+ dev->dev_attrib.max_write_same_len = 0x1000;
pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s,"
" %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id,
@@ -328,6 +333,115 @@ 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 = spc_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;
+
+ if (!nolb) {
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
+ return 0;
+ }
+ sg = &cmd->t_data_sg[0];
+
+ if (cmd->t_data_nents > 1 ||
+ 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, sg->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)
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+ iov = vmalloc(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;
+ }
+ memset(iov, 0, sizeof(struct iovec) * iov_num);
+ /*
+ * Map the single fabric received scatterlist block into each
+ * iovec for 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;
+ }
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+ rc = vfs_writev(f, &iov[0], iov_num, &pos);
+ set_fs(old_fs);
+
+ vfree(iov);
+ kfree(buf);
+
+ if (rc < 0 || rc != len) {
+ pr_err("vfs_writev() returned %d for write same\n", rc);
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ }
+
+ target_complete_cmd(cmd, SAM_STAT_GOOD);
+ return 0;
+}
+
static sense_reason_t
fd_execute_rw(struct se_cmd *cmd)
{
@@ -486,6 +600,7 @@ static sector_t fd_get_blocks(struct se_device *dev)
static struct sbc_ops fd_sbc_ops = {
.execute_rw = fd_execute_rw,
.execute_sync_cache = fd_execute_sync_cache,
+ .execute_write_same = fd_execute_write_same,
};
static sense_reason_t
--
1.7.2.5
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] target/file: Add WRITE_SAME w/ UNMAP=0 emulation support
2013-02-20 1:43 [PATCH] target/file: Add WRITE_SAME w/ UNMAP=0 emulation support Nicholas A. Bellinger
@ 2013-02-20 3:17 ` Asias He
2013-02-20 20:32 ` Nicholas A. Bellinger
0 siblings, 1 reply; 3+ messages in thread
From: Asias He @ 2013-02-20 3:17 UTC (permalink / raw)
To: Nicholas A. Bellinger
Cc: target-devel, linux-scsi, Martin K. Petersen, Christoph Hellwig
On 02/20/2013 09:43 AM, Nicholas A. Bellinger wrote:
> From: Nicholas Bellinger <nab@linux-iscsi.org>
>
> Hi mkp, hch, & Co,
>
> Please review this patch to add support for WRITE_SAME w/ UNMAP=0
> emulation into FILEIO, as I'd really like to include this in the
> upcoming for-3.9 target merge.
>
> Thank you,
>
> --nab
>
> ---------------------------------------------------------------------
>
> This patch adds support for emulation of WRITE_SAME w/ UNMAP=0 within
> fd_execute_write_same() backend code.
>
> The emulation uses vfs_writev() to submit a locally populated buffer
> from the received WRITE_SAME scatterlist block for duplication, and by
> default enforces a limit of max_write_same_len=0x1000 (8192) sectors up
> to the limit of 1024 iovec entries for the single call to vfs_writev().
>
> It also sets max_write_same_len to the operational default at setup ->
> fd_configure_device() time.
>
> Tested with 512, 1k, 2k, and 4k block_sizes.
>
> Cc: Martin K. Petersen <martin.petersen@oracle.com>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: Asias He <asias@redhat.com>
> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> ---
> drivers/target/target_core_file.c | 115 +++++++++++++++++++++++++++++++++++++
> 1 files changed, 115 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
> index b9c8849..0b71509 100644
> --- a/drivers/target/target_core_file.c
> +++ b/drivers/target/target_core_file.c
> @@ -190,6 +190,11 @@ static int fd_configure_device(struct se_device *dev)
>
> fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
> fd_dev->fd_queue_depth = dev->queue_depth;
> + /*
> + * Limit WRITE_SAME w/ UNMAP=0 emulation to 8k Number of LBAs (NoLB)
> + * based upon struct iovec limit for vfs_writev()
> + */
> + dev->dev_attrib.max_write_same_len = 0x1000;
>
> pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s,"
> " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id,
> @@ -328,6 +333,115 @@ 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 = spc_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;
> +
> + if (!nolb) {
> + target_complete_cmd(cmd, SAM_STAT_GOOD);
> + return 0;
> + }
> + sg = &cmd->t_data_sg[0];
> +
> + if (cmd->t_data_nents > 1 ||
> + 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, sg->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)
> + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
> +
> + iov = vmalloc(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;
> + }
> + memset(iov, 0, sizeof(struct iovec) * iov_num);
Use vzalloc()?
> + /*
> + * Map the single fabric received scatterlist block into each
> + * iovec for 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;
> + }
> +
> + old_fs = get_fs();
> + set_fs(get_ds());
> + rc = vfs_writev(f, &iov[0], iov_num, &pos);
> + set_fs(old_fs);
> +
> + vfree(iov);
> + kfree(buf);
> +
> + if (rc < 0 || rc != len) {
> + pr_err("vfs_writev() returned %d for write same\n", rc);
> + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
> + }
> +
> + target_complete_cmd(cmd, SAM_STAT_GOOD);
> + return 0;
> +}
> +
> static sense_reason_t
> fd_execute_rw(struct se_cmd *cmd)
> {
> @@ -486,6 +600,7 @@ static sector_t fd_get_blocks(struct se_device *dev)
> static struct sbc_ops fd_sbc_ops = {
> .execute_rw = fd_execute_rw,
> .execute_sync_cache = fd_execute_sync_cache,
> + .execute_write_same = fd_execute_write_same,
> };
>
> static sense_reason_t
>
--
Asias
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] target/file: Add WRITE_SAME w/ UNMAP=0 emulation support
2013-02-20 3:17 ` Asias He
@ 2013-02-20 20:32 ` Nicholas A. Bellinger
0 siblings, 0 replies; 3+ messages in thread
From: Nicholas A. Bellinger @ 2013-02-20 20:32 UTC (permalink / raw)
To: Asias He; +Cc: target-devel, linux-scsi, Martin K. Petersen, Christoph Hellwig
On Wed, 2013-02-20 at 11:17 +0800, Asias He wrote:
> On 02/20/2013 09:43 AM, Nicholas A. Bellinger wrote:
> > From: Nicholas Bellinger <nab@linux-iscsi.org>
> >
> > Hi mkp, hch, & Co,
> >
> > Please review this patch to add support for WRITE_SAME w/ UNMAP=0
> > emulation into FILEIO, as I'd really like to include this in the
> > upcoming for-3.9 target merge.
> >
> > Thank you,
> >
> > --nab
> >
> > ---------------------------------------------------------------------
> >
> > This patch adds support for emulation of WRITE_SAME w/ UNMAP=0 within
> > fd_execute_write_same() backend code.
> >
> > The emulation uses vfs_writev() to submit a locally populated buffer
> > from the received WRITE_SAME scatterlist block for duplication, and by
> > default enforces a limit of max_write_same_len=0x1000 (8192) sectors up
> > to the limit of 1024 iovec entries for the single call to vfs_writev().
> >
> > It also sets max_write_same_len to the operational default at setup ->
> > fd_configure_device() time.
> >
> > Tested with 512, 1k, 2k, and 4k block_sizes.
> >
> > Cc: Martin K. Petersen <martin.petersen@oracle.com>
> > Cc: Christoph Hellwig <hch@lst.de>
> > Cc: Asias He <asias@redhat.com>
> > Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
> > ---
> > drivers/target/target_core_file.c | 115 +++++++++++++++++++++++++++++++++++++
> > 1 files changed, 115 insertions(+), 0 deletions(-)
> >
<SNIP>
> > +
> > +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 = spc_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;
> > +
> > + if (!nolb) {
> > + target_complete_cmd(cmd, SAM_STAT_GOOD);
> > + return 0;
> > + }
> > + sg = &cmd->t_data_sg[0];
> > +
> > + if (cmd->t_data_nents > 1 ||
> > + 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, sg->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)
> > + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
> > +
> > + iov = vmalloc(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;
> > + }
> > + memset(iov, 0, sizeof(struct iovec) * iov_num);
>
> Use vzalloc()?
Of course.. Changed to vzalloc + dropped memset.
Thanks for reviewing!
--nab
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2013-02-20 20:32 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-02-20 1:43 [PATCH] target/file: Add WRITE_SAME w/ UNMAP=0 emulation support Nicholas A. Bellinger
2013-02-20 3:17 ` Asias He
2013-02-20 20:32 ` Nicholas A. Bellinger
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.