aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2013-02-19 20:30:34 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2013-02-20 15:29:04 -0500
commit7b745c84a9f4ad62db4b67053fbceb5d706451af (patch)
tree2c8886e676130abfa4682531eb5c01d57feb6e47
parent6e5459353de4ac80924e94fafa8b3e31a086c5dd (diff)
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>
-rw-r--r--drivers/target/target_core_file.c114
1 files changed, 114 insertions, 0 deletions
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index b9c88497e8f0..94383a56bd74 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)
190 190
191 fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++; 191 fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++;
192 fd_dev->fd_queue_depth = dev->queue_depth; 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 pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s," 199 pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s,"
195 " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id, 200 " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id,
@@ -328,6 +333,114 @@ fd_execute_sync_cache(struct se_cmd *cmd)
328 return 0; 333 return 0;
329} 334}
330 335
336static unsigned char *
337fd_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
375static sense_reason_t
376fd_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
331static sense_reason_t 444static sense_reason_t
332fd_execute_rw(struct se_cmd *cmd) 445fd_execute_rw(struct se_cmd *cmd)
333{ 446{
@@ -486,6 +599,7 @@ static sector_t fd_get_blocks(struct se_device *dev)
486static struct sbc_ops fd_sbc_ops = { 599static struct sbc_ops fd_sbc_ops = {
487 .execute_rw = fd_execute_rw, 600 .execute_rw = fd_execute_rw,
488 .execute_sync_cache = fd_execute_sync_cache, 601 .execute_sync_cache = fd_execute_sync_cache,
602 .execute_write_same = fd_execute_write_same,
489}; 603};
490 604
491static sense_reason_t 605static sense_reason_t