diff options
author | Mike Christie <mchristi@redhat.com> | 2016-02-24 14:56:33 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2016-03-11 00:48:53 -0500 |
commit | 07b6319687026bdac90a0bb9eeb0509f1ff27179 (patch) | |
tree | 05e7f5b5e9046c813b7d118a5542d83b33240725 | |
parent | e3416ab2d156ac0f0a3d9e55bcdff69d109ba403 (diff) |
target/iblock: pass WRITE_SAME to device if possible
This patch has iblock pass the WRITE_SAME command to
the device for offloading if possible. It is similar to what is
done for UNMAP/discards, except that we export a large max write same
value to the initiator, and then rely on the block layer to
break it up into multiple requests if it cannot fit into one.
v2.
- Drop file backend changes and move helper function to
iblock backend.
Signed-off-by: Mike Christie <mchristi@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/target_core_iblock.c | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index abe4eb997a84..026a758e5778 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c | |||
@@ -413,8 +413,39 @@ iblock_execute_unmap(struct se_cmd *cmd, sector_t lba, sector_t nolb) | |||
413 | } | 413 | } |
414 | 414 | ||
415 | static sense_reason_t | 415 | static sense_reason_t |
416 | iblock_execute_write_same_direct(struct block_device *bdev, struct se_cmd *cmd) | ||
417 | { | ||
418 | struct se_device *dev = cmd->se_dev; | ||
419 | struct scatterlist *sg = &cmd->t_data_sg[0]; | ||
420 | struct page *page = NULL; | ||
421 | int ret; | ||
422 | |||
423 | if (sg->offset) { | ||
424 | page = alloc_page(GFP_KERNEL); | ||
425 | if (!page) | ||
426 | return TCM_OUT_OF_RESOURCES; | ||
427 | sg_copy_to_buffer(sg, cmd->t_data_nents, page_address(page), | ||
428 | dev->dev_attrib.block_size); | ||
429 | } | ||
430 | |||
431 | ret = blkdev_issue_write_same(bdev, | ||
432 | target_to_linux_sector(dev, cmd->t_task_lba), | ||
433 | target_to_linux_sector(dev, | ||
434 | sbc_get_write_same_sectors(cmd)), | ||
435 | GFP_KERNEL, page ? page : sg_page(sg)); | ||
436 | if (page) | ||
437 | __free_page(page); | ||
438 | if (ret) | ||
439 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
440 | |||
441 | target_complete_cmd(cmd, GOOD); | ||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | static sense_reason_t | ||
416 | iblock_execute_write_same(struct se_cmd *cmd) | 446 | iblock_execute_write_same(struct se_cmd *cmd) |
417 | { | 447 | { |
448 | struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; | ||
418 | struct iblock_req *ibr; | 449 | struct iblock_req *ibr; |
419 | struct scatterlist *sg; | 450 | struct scatterlist *sg; |
420 | struct bio *bio; | 451 | struct bio *bio; |
@@ -439,6 +470,9 @@ iblock_execute_write_same(struct se_cmd *cmd) | |||
439 | return TCM_INVALID_CDB_FIELD; | 470 | return TCM_INVALID_CDB_FIELD; |
440 | } | 471 | } |
441 | 472 | ||
473 | if (bdev_write_same(bdev)) | ||
474 | return iblock_execute_write_same_direct(bdev, cmd); | ||
475 | |||
442 | ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); | 476 | ibr = kzalloc(sizeof(struct iblock_req), GFP_KERNEL); |
443 | if (!ibr) | 477 | if (!ibr) |
444 | goto fail; | 478 | goto fail; |