Commit 7b745c84a9f4ad62db4b67053fbceb5d706451af

Authored by Nicholas Bellinger
1 parent 6e5459353d

target/file: Add WRITE_SAME w/ UNMAP=0 emulation support

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.

(asias: convert to vzalloc)

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>

Showing 1 changed file with 114 additions and 0 deletions Side-by-side Diff

drivers/target/target_core_file.c
... ... @@ -190,6 +190,11 @@
190 190  
191 191 fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
192 192 fd_dev->fd_queue_depth = dev->queue_depth;
  193 + /*
  194 + * Limit WRITE_SAME w/ UNMAP=0 emulation to 8k Number of LBAs (NoLB)
  195 + * based upon struct iovec limit for vfs_writev()
  196 + */
  197 + dev->dev_attrib.max_write_same_len = 0x1000;
193 198  
194 199 pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s,"
195 200 " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id,
196 201  
... ... @@ -328,7 +333,115 @@
328 333 return 0;
329 334 }
330 335  
  336 +static unsigned char *
  337 +fd_setup_write_same_buf(struct se_cmd *cmd, struct scatterlist *sg,
  338 + unsigned int len)
  339 +{
  340 + struct se_device *se_dev = cmd->se_dev;
  341 + unsigned int block_size = se_dev->dev_attrib.block_size;
  342 + unsigned int i = 0, end;
  343 + unsigned char *buf, *p, *kmap_buf;
  344 +
  345 + buf = kzalloc(min_t(unsigned int, len, PAGE_SIZE), GFP_KERNEL);
  346 + if (!buf) {
  347 + pr_err("Unable to allocate fd_execute_write_same buf\n");
  348 + return NULL;
  349 + }
  350 +
  351 + kmap_buf = kmap(sg_page(sg)) + sg->offset;
  352 + if (!kmap_buf) {
  353 + pr_err("kmap() failed in fd_setup_write_same\n");
  354 + kfree(buf);
  355 + return NULL;
  356 + }
  357 + /*
  358 + * Fill local *buf to contain multiple WRITE_SAME blocks up to
  359 + * min(len, PAGE_SIZE)
  360 + */
  361 + p = buf;
  362 + end = min_t(unsigned int, len, PAGE_SIZE);
  363 +
  364 + while (i < end) {
  365 + memcpy(p, kmap_buf, block_size);
  366 +
  367 + i += block_size;
  368 + p += block_size;
  369 + }
  370 + kunmap(sg_page(sg));
  371 +
  372 + return buf;
  373 +}
  374 +
331 375 static sense_reason_t
  376 +fd_execute_write_same(struct se_cmd *cmd)
  377 +{
  378 + struct se_device *se_dev = cmd->se_dev;
  379 + struct fd_dev *fd_dev = FD_DEV(se_dev);
  380 + struct file *f = fd_dev->fd_file;
  381 + struct scatterlist *sg;
  382 + struct iovec *iov;
  383 + mm_segment_t old_fs;
  384 + sector_t nolb = spc_get_write_same_sectors(cmd);
  385 + loff_t pos = cmd->t_task_lba * se_dev->dev_attrib.block_size;
  386 + unsigned int len, len_tmp, iov_num;
  387 + int i, rc;
  388 + unsigned char *buf;
  389 +
  390 + if (!nolb) {
  391 + target_complete_cmd(cmd, SAM_STAT_GOOD);
  392 + return 0;
  393 + }
  394 + sg = &cmd->t_data_sg[0];
  395 +
  396 + if (cmd->t_data_nents > 1 ||
  397 + sg->length != cmd->se_dev->dev_attrib.block_size) {
  398 + pr_err("WRITE_SAME: Illegal SGL t_data_nents: %u length: %u"
  399 + " block_size: %u\n", cmd->t_data_nents, sg->length,
  400 + cmd->se_dev->dev_attrib.block_size);
  401 + return TCM_INVALID_CDB_FIELD;
  402 + }
  403 +
  404 + len = len_tmp = nolb * se_dev->dev_attrib.block_size;
  405 + iov_num = DIV_ROUND_UP(len, PAGE_SIZE);
  406 +
  407 + buf = fd_setup_write_same_buf(cmd, sg, len);
  408 + if (!buf)
  409 + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
  410 +
  411 + iov = vzalloc(sizeof(struct iovec) * iov_num);
  412 + if (!iov) {
  413 + pr_err("Unable to allocate fd_execute_write_same iovecs\n");
  414 + kfree(buf);
  415 + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
  416 + }
  417 + /*
  418 + * Map the single fabric received scatterlist block now populated
  419 + * in *buf into each iovec for I/O submission.
  420 + */
  421 + for (i = 0; i < iov_num; i++) {
  422 + iov[i].iov_base = buf;
  423 + iov[i].iov_len = min_t(unsigned int, len_tmp, PAGE_SIZE);
  424 + len_tmp -= iov[i].iov_len;
  425 + }
  426 +
  427 + old_fs = get_fs();
  428 + set_fs(get_ds());
  429 + rc = vfs_writev(f, &iov[0], iov_num, &pos);
  430 + set_fs(old_fs);
  431 +
  432 + vfree(iov);
  433 + kfree(buf);
  434 +
  435 + if (rc < 0 || rc != len) {
  436 + pr_err("vfs_writev() returned %d for write same\n", rc);
  437 + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
  438 + }
  439 +
  440 + target_complete_cmd(cmd, SAM_STAT_GOOD);
  441 + return 0;
  442 +}
  443 +
  444 +static sense_reason_t
332 445 fd_execute_rw(struct se_cmd *cmd)
333 446 {
334 447 struct scatterlist *sgl = cmd->t_data_sg;
... ... @@ -486,6 +599,7 @@
486 599 static struct sbc_ops fd_sbc_ops = {
487 600 .execute_rw = fd_execute_rw,
488 601 .execute_sync_cache = fd_execute_sync_cache,
  602 + .execute_write_same = fd_execute_write_same,
489 603 };
490 604  
491 605 static sense_reason_t