aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/target')
-rw-r--r--drivers/target/target_core_file.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index e1878bfd97b7..7e02304a1024 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -33,6 +33,7 @@
33#include <linux/falloc.h> 33#include <linux/falloc.h>
34#include <scsi/scsi.h> 34#include <scsi/scsi.h>
35#include <scsi/scsi_host.h> 35#include <scsi/scsi_host.h>
36#include <asm/unaligned.h>
36 37
37#include <target/target_core_base.h> 38#include <target/target_core_base.h>
38#include <target/target_core_backend.h> 39#include <target/target_core_backend.h>
@@ -525,6 +526,115 @@ fd_execute_write_same_unmap(struct se_cmd *cmd)
525} 526}
526 527
527static sense_reason_t 528static sense_reason_t
529fd_execute_unmap(struct se_cmd *cmd)
530{
531 struct se_device *dev = cmd->se_dev;
532 struct fd_dev *fd_dev = FD_DEV(dev);
533 struct file *file = fd_dev->fd_file;
534 struct inode *inode = file->f_mapping->host;
535 unsigned char *buf, *ptr = NULL;
536 sector_t lba;
537 int size;
538 u32 range;
539 sense_reason_t ret = 0;
540 int dl, bd_dl, err;
541
542 /* We never set ANC_SUP */
543 if (cmd->t_task_cdb[1])
544 return TCM_INVALID_CDB_FIELD;
545
546 if (cmd->data_length == 0) {
547 target_complete_cmd(cmd, SAM_STAT_GOOD);
548 return 0;
549 }
550
551 if (cmd->data_length < 8) {
552 pr_warn("UNMAP parameter list length %u too small\n",
553 cmd->data_length);
554 return TCM_PARAMETER_LIST_LENGTH_ERROR;
555 }
556
557 buf = transport_kmap_data_sg(cmd);
558 if (!buf)
559 return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
560
561 dl = get_unaligned_be16(&buf[0]);
562 bd_dl = get_unaligned_be16(&buf[2]);
563
564 size = cmd->data_length - 8;
565 if (bd_dl > size)
566 pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n",
567 cmd->data_length, bd_dl);
568 else
569 size = bd_dl;
570
571 if (size / 16 > dev->dev_attrib.max_unmap_block_desc_count) {
572 ret = TCM_INVALID_PARAMETER_LIST;
573 goto err;
574 }
575
576 /* First UNMAP block descriptor starts at 8 byte offset */
577 ptr = &buf[8];
578 pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u"
579 " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
580
581 while (size >= 16) {
582 lba = get_unaligned_be64(&ptr[0]);
583 range = get_unaligned_be32(&ptr[8]);
584 pr_debug("UNMAP: Using lba: %llu and range: %u\n",
585 (unsigned long long)lba, range);
586
587 if (range > dev->dev_attrib.max_unmap_lba_count) {
588 ret = TCM_INVALID_PARAMETER_LIST;
589 goto err;
590 }
591
592 if (lba + range > dev->transport->get_blocks(dev) + 1) {
593 ret = TCM_ADDRESS_OUT_OF_RANGE;
594 goto err;
595 }
596
597 if (S_ISBLK(inode->i_mode)) {
598 /* The backend is block device, use discard */
599 struct block_device *bdev = inode->i_bdev;
600
601 err = blkdev_issue_discard(bdev, lba, range, GFP_KERNEL, 0);
602 if (err < 0) {
603 pr_err("FILEIO: blkdev_issue_discard() failed: %d\n",
604 err);
605 ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
606 goto err;
607 }
608 } else {
609 /* The backend is normal file, use fallocate */
610 loff_t pos = lba * dev->dev_attrib.block_size;
611 unsigned int len = range * dev->dev_attrib.block_size;
612 int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
613
614 if (!file->f_op->fallocate) {
615 ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
616 goto err;
617 }
618 err = file->f_op->fallocate(file, mode, pos, len);
619 if (err < 0) {
620 pr_warn("FILEIO: fallocate() failed: %d\n", err);
621 ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
622 goto err;
623 }
624 }
625
626 ptr += 16;
627 size -= 16;
628 }
629
630err:
631 transport_kunmap_data_sg(cmd);
632 if (!ret)
633 target_complete_cmd(cmd, GOOD);
634 return ret;
635}
636
637static sense_reason_t
528fd_execute_rw(struct se_cmd *cmd) 638fd_execute_rw(struct se_cmd *cmd)
529{ 639{
530 struct scatterlist *sgl = cmd->t_data_sg; 640 struct scatterlist *sgl = cmd->t_data_sg;
@@ -684,6 +794,7 @@ static struct sbc_ops fd_sbc_ops = {
684 .execute_sync_cache = fd_execute_sync_cache, 794 .execute_sync_cache = fd_execute_sync_cache,
685 .execute_write_same = fd_execute_write_same, 795 .execute_write_same = fd_execute_write_same,
686 .execute_write_same_unmap = fd_execute_write_same_unmap, 796 .execute_write_same_unmap = fd_execute_write_same_unmap,
797 .execute_unmap = fd_execute_unmap,
687}; 798};
688 799
689static sense_reason_t 800static sense_reason_t