diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-01-18 04:33:48 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2014-01-18 21:21:55 -0500 |
commit | 42201b557471f2fef2e9e028b50a773d99ffc401 (patch) | |
tree | b24fbaf77eed5cf01d384137a9d143981c6d31fd /drivers/target | |
parent | 0f5e2ec46dd64579c0770f3822764f94db4fa465 (diff) |
target/file: Add DIF protection support to fd_execute_rw
This patch adds support for DIF protection into fd_execute_rw() code
for WRITE/READ I/O using sbc_dif_verify_[write,read]() logic.
It adds fd_do_prot_rw() for handling interface with FILEIO PI, and
uses a locally allocated fd_prot->prot_buf + fd_prot->prot_sg for
interacting with SBC DIF verify emulation code.
Cc: Martin K. Petersen <martin.petersen@oracle.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Sagi Grimberg <sagig@mellanox.com>
Cc: Or Gerlitz <ogerlitz@mellanox.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/target_core_file.c | 119 | ||||
-rw-r--r-- | drivers/target/target_core_file.h | 5 |
2 files changed, 123 insertions, 1 deletions
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 119d51909762..aaba7c588c4d 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c | |||
@@ -257,6 +257,72 @@ static void fd_free_device(struct se_device *dev) | |||
257 | kfree(fd_dev); | 257 | kfree(fd_dev); |
258 | } | 258 | } |
259 | 259 | ||
260 | static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot, | ||
261 | int is_write) | ||
262 | { | ||
263 | struct se_device *se_dev = cmd->se_dev; | ||
264 | struct fd_dev *dev = FD_DEV(se_dev); | ||
265 | struct file *prot_fd = dev->fd_prot_file; | ||
266 | struct scatterlist *sg; | ||
267 | loff_t pos = (cmd->t_task_lba * se_dev->prot_length); | ||
268 | unsigned char *buf; | ||
269 | u32 prot_size, len, size; | ||
270 | int rc, ret = 1, i; | ||
271 | |||
272 | prot_size = (cmd->data_length / se_dev->dev_attrib.block_size) * | ||
273 | se_dev->prot_length; | ||
274 | |||
275 | if (!is_write) { | ||
276 | fd_prot->prot_buf = vzalloc(prot_size); | ||
277 | if (!fd_prot->prot_buf) { | ||
278 | pr_err("Unable to allocate fd_prot->prot_buf\n"); | ||
279 | return -ENOMEM; | ||
280 | } | ||
281 | buf = fd_prot->prot_buf; | ||
282 | |||
283 | fd_prot->prot_sg_nents = cmd->t_prot_nents; | ||
284 | fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist) * | ||
285 | fd_prot->prot_sg_nents, GFP_KERNEL); | ||
286 | if (!fd_prot->prot_sg) { | ||
287 | pr_err("Unable to allocate fd_prot->prot_sg\n"); | ||
288 | vfree(fd_prot->prot_buf); | ||
289 | return -ENOMEM; | ||
290 | } | ||
291 | size = prot_size; | ||
292 | |||
293 | for_each_sg(fd_prot->prot_sg, sg, fd_prot->prot_sg_nents, i) { | ||
294 | |||
295 | len = min_t(u32, PAGE_SIZE, size); | ||
296 | sg_set_buf(sg, buf, len); | ||
297 | size -= len; | ||
298 | buf += len; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | if (is_write) { | ||
303 | rc = kernel_write(prot_fd, fd_prot->prot_buf, prot_size, pos); | ||
304 | if (rc < 0 || prot_size != rc) { | ||
305 | pr_err("kernel_write() for fd_do_prot_rw failed:" | ||
306 | " %d\n", rc); | ||
307 | ret = -EINVAL; | ||
308 | } | ||
309 | } else { | ||
310 | rc = kernel_read(prot_fd, pos, fd_prot->prot_buf, prot_size); | ||
311 | if (rc < 0) { | ||
312 | pr_err("kernel_read() for fd_do_prot_rw failed:" | ||
313 | " %d\n", rc); | ||
314 | ret = -EINVAL; | ||
315 | } | ||
316 | } | ||
317 | |||
318 | if (is_write || ret < 0) { | ||
319 | kfree(fd_prot->prot_sg); | ||
320 | vfree(fd_prot->prot_buf); | ||
321 | } | ||
322 | |||
323 | return ret; | ||
324 | } | ||
325 | |||
260 | static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl, | 326 | static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl, |
261 | u32 sgl_nents, int is_write) | 327 | u32 sgl_nents, int is_write) |
262 | { | 328 | { |
@@ -551,6 +617,8 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | |||
551 | enum dma_data_direction data_direction) | 617 | enum dma_data_direction data_direction) |
552 | { | 618 | { |
553 | struct se_device *dev = cmd->se_dev; | 619 | struct se_device *dev = cmd->se_dev; |
620 | struct fd_prot fd_prot; | ||
621 | sense_reason_t rc; | ||
554 | int ret = 0; | 622 | int ret = 0; |
555 | 623 | ||
556 | /* | 624 | /* |
@@ -558,8 +626,48 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | |||
558 | * physical memory addresses to struct iovec virtual memory. | 626 | * physical memory addresses to struct iovec virtual memory. |
559 | */ | 627 | */ |
560 | if (data_direction == DMA_FROM_DEVICE) { | 628 | if (data_direction == DMA_FROM_DEVICE) { |
629 | memset(&fd_prot, 0, sizeof(struct fd_prot)); | ||
630 | |||
631 | if (cmd->prot_type) { | ||
632 | ret = fd_do_prot_rw(cmd, &fd_prot, false); | ||
633 | if (ret < 0) | ||
634 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
635 | } | ||
636 | |||
561 | ret = fd_do_rw(cmd, sgl, sgl_nents, 0); | 637 | ret = fd_do_rw(cmd, sgl, sgl_nents, 0); |
638 | |||
639 | if (ret > 0 && cmd->prot_type) { | ||
640 | u32 sectors = cmd->data_length / dev->dev_attrib.block_size; | ||
641 | |||
642 | rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, | ||
643 | 0, fd_prot.prot_sg, 0); | ||
644 | if (rc) { | ||
645 | kfree(fd_prot.prot_sg); | ||
646 | vfree(fd_prot.prot_buf); | ||
647 | return rc; | ||
648 | } | ||
649 | kfree(fd_prot.prot_sg); | ||
650 | vfree(fd_prot.prot_buf); | ||
651 | } | ||
562 | } else { | 652 | } else { |
653 | memset(&fd_prot, 0, sizeof(struct fd_prot)); | ||
654 | |||
655 | if (cmd->prot_type) { | ||
656 | u32 sectors = cmd->data_length / dev->dev_attrib.block_size; | ||
657 | |||
658 | ret = fd_do_prot_rw(cmd, &fd_prot, false); | ||
659 | if (ret < 0) | ||
660 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
661 | |||
662 | rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors, | ||
663 | 0, fd_prot.prot_sg, 0); | ||
664 | if (rc) { | ||
665 | kfree(fd_prot.prot_sg); | ||
666 | vfree(fd_prot.prot_buf); | ||
667 | return rc; | ||
668 | } | ||
669 | } | ||
670 | |||
563 | ret = fd_do_rw(cmd, sgl, sgl_nents, 1); | 671 | ret = fd_do_rw(cmd, sgl, sgl_nents, 1); |
564 | /* | 672 | /* |
565 | * Perform implicit vfs_fsync_range() for fd_do_writev() ops | 673 | * Perform implicit vfs_fsync_range() for fd_do_writev() ops |
@@ -576,10 +684,19 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | |||
576 | 684 | ||
577 | vfs_fsync_range(fd_dev->fd_file, start, end, 1); | 685 | vfs_fsync_range(fd_dev->fd_file, start, end, 1); |
578 | } | 686 | } |
687 | |||
688 | if (ret > 0 && cmd->prot_type) { | ||
689 | ret = fd_do_prot_rw(cmd, &fd_prot, true); | ||
690 | if (ret < 0) | ||
691 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
692 | } | ||
579 | } | 693 | } |
580 | 694 | ||
581 | if (ret < 0) | 695 | if (ret < 0) { |
696 | kfree(fd_prot.prot_sg); | ||
697 | vfree(fd_prot.prot_buf); | ||
582 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 698 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
699 | } | ||
583 | 700 | ||
584 | if (ret) | 701 | if (ret) |
585 | target_complete_cmd(cmd, SAM_STAT_GOOD); | 702 | target_complete_cmd(cmd, SAM_STAT_GOOD); |
diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h index 583691ebcbe0..97e5e7dd4259 100644 --- a/drivers/target/target_core_file.h +++ b/drivers/target/target_core_file.h | |||
@@ -18,6 +18,11 @@ | |||
18 | #define FDBD_HAS_BUFFERED_IO_WCE 0x04 | 18 | #define FDBD_HAS_BUFFERED_IO_WCE 0x04 |
19 | #define FDBD_FORMAT_UNIT_SIZE 2048 | 19 | #define FDBD_FORMAT_UNIT_SIZE 2048 |
20 | 20 | ||
21 | struct fd_prot { | ||
22 | unsigned char *prot_buf; | ||
23 | struct scatterlist *prot_sg; | ||
24 | u32 prot_sg_nents; | ||
25 | }; | ||
21 | 26 | ||
22 | struct fd_dev { | 27 | struct fd_dev { |
23 | struct se_device dev; | 28 | struct se_device dev; |