aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target
diff options
context:
space:
mode:
authorAsias He <asias@redhat.com>2013-02-25 01:03:43 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2013-04-25 04:05:23 -0400
commit506427628afeb5d70eefdac1fe4c2a1ffb27df5f (patch)
treecd487389e9013909b44032d115f279944fea7a73 /drivers/target
parent70d3ae5c80758cb2bf3cf1e0d5b2c89d040de90b (diff)
target/file: Add UNMAP emulation support
This patch adds support for emulation of UNMAP within fd_execute_unmap() backend code. If the FILEIO backend is normal file, the emulation uses fallocate to punch hole to reclaim the free space used by the file. If the FILEIO backend is block device, the emulation uses blkdev_issue_discard(). Cc: Christoph Hellwig <hch@lst.de> Cc: Martin K. Petersen <martin.petersen@oracle.com> Cc: Nicholas Bellinger <nab@linux-iscsi.org> Signed-off-by: Asias He <asias@redhat.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
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