Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+123 -1
+118 -1
drivers/target/target_core_file.c
··· 257 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 326 static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl, 261 327 u32 sgl_nents, int is_write) 262 328 { ··· 617 551 enum dma_data_direction data_direction) 618 552 { 619 553 struct se_device *dev = cmd->se_dev; 554 + struct fd_prot fd_prot; 555 + sense_reason_t rc; 620 556 int ret = 0; 621 557 622 558 /* ··· 626 558 * physical memory addresses to struct iovec virtual memory. 627 559 */ 628 560 if (data_direction == DMA_FROM_DEVICE) { 561 + memset(&fd_prot, 0, sizeof(struct fd_prot)); 562 + 563 + if (cmd->prot_type) { 564 + ret = fd_do_prot_rw(cmd, &fd_prot, false); 565 + if (ret < 0) 566 + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 567 + } 568 + 629 569 ret = fd_do_rw(cmd, sgl, sgl_nents, 0); 570 + 571 + if (ret > 0 && cmd->prot_type) { 572 + u32 sectors = cmd->data_length / dev->dev_attrib.block_size; 573 + 574 + rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, 575 + 0, fd_prot.prot_sg, 0); 576 + if (rc) { 577 + kfree(fd_prot.prot_sg); 578 + vfree(fd_prot.prot_buf); 579 + return rc; 580 + } 581 + kfree(fd_prot.prot_sg); 582 + vfree(fd_prot.prot_buf); 583 + } 630 584 } else { 585 + memset(&fd_prot, 0, sizeof(struct fd_prot)); 586 + 587 + if (cmd->prot_type) { 588 + u32 sectors = cmd->data_length / dev->dev_attrib.block_size; 589 + 590 + ret = fd_do_prot_rw(cmd, &fd_prot, false); 591 + if (ret < 0) 592 + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 593 + 594 + rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors, 595 + 0, fd_prot.prot_sg, 0); 596 + if (rc) { 597 + kfree(fd_prot.prot_sg); 598 + vfree(fd_prot.prot_buf); 599 + return rc; 600 + } 601 + } 602 + 631 603 ret = fd_do_rw(cmd, sgl, sgl_nents, 1); 632 604 /* 633 605 * Perform implicit vfs_fsync_range() for fd_do_writev() ops ··· 684 576 685 577 vfs_fsync_range(fd_dev->fd_file, start, end, 1); 686 578 } 579 + 580 + if (ret > 0 && cmd->prot_type) { 581 + ret = fd_do_prot_rw(cmd, &fd_prot, true); 582 + if (ret < 0) 583 + return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 584 + } 687 585 } 688 586 689 - if (ret < 0) 587 + if (ret < 0) { 588 + kfree(fd_prot.prot_sg); 589 + vfree(fd_prot.prot_buf); 690 590 return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; 591 + } 691 592 692 593 if (ret) 693 594 target_complete_cmd(cmd, SAM_STAT_GOOD);
+5
drivers/target/target_core_file.h
··· 18 18 #define FDBD_HAS_BUFFERED_IO_WCE 0x04 19 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 27 struct fd_dev { 23 28 struct se_device dev;