This is a really hacky patch to add discard support. I don't plan to merge this. Let me know if someone is interested in it. I'll think about how to support discard cleanly. I'll give you an example how useful this is. On the target box, I have one 2GB file on xfs. It's exported to an initiator: clover:/home/fujita# df -h Filesystem Size Used Avail Use% Mounted on /dev/cciss/c0d0p1 130G 7.2G 116G 6% / tmpfs 4.0G 0 4.0G 0% /lib/init/rw udev 10M 96K 10M 1% /dev tmpfs 4.0G 0 4.0G 0% /dev/shm /dev/cciss/c0d1p1 137G 2.1G 135G 2% /mnt/xfs clover:/home/fujita# ls -lh /mnt/xfs/sbc1 -rw-r--r-- 1 root root 2.0G 2010-07-09 16:17 /mnt/xfs/sbc1 clover:/home/fujita# ./tgt/usr/tgtadm --op show --mode target Target 1: iqn.2001-04.com.example:storage.sr.rose.sys1.xyz System information: Driver: iscsi State: ready I_T nexus information: I_T nexus: 1 Initiator: iqn.2005-03.org.open-iscsi:7e4eaf7a28q Connection: 0 IP Address: 10.76.0.32 LUN information: LUN: 0 Type: controller SCSI ID: IET 00010000 SCSI SN: beaf10 Size: 0 MB Online: Yes Removable media: No Backing store type: null Backing store path: None Backing store flags: LUN: 1 Type: disk SCSI ID: IET 00010001 SCSI SN: beaf11 Size: 2147 MB Online: Yes Removable media: No Backing store type: rdwr Backing store path: /mnt/xfs/sbc1 Backing store flags: Account information: ACL information: ALL On the initiator box, I run mkfs.xfs Then, on the target box: clover:/home/fujita# df -h Filesystem Size Used Avail Use% Mounted on /dev/cciss/c0d0p1 130G 7.2G 116G 6% / tmpfs 4.0G 0 4.0G 0% /lib/init/rw udev 10M 96K 10M 1% /dev tmpfs 4.0G 0 4.0G 0% /dev/shm /dev/cciss/c0d1p1 137G 43M 137G 1% /mnt/xfs Surprisingly, now I only use 43MB. clover:/home/fujita# ls -lh /mnt/xfs/sbc1 -rw-r--r-- 1 root root 2.0G 2010-07-09 16:17 /mnt/xfs/sbc1 But I still have the 2GB file. The trick is that the majority data of file was discarded. = diff --git a/usr/sbc.c b/usr/sbc.c index a048d53..a94f803 100644 --- a/usr/sbc.c +++ b/usr/sbc.c @@ -161,23 +161,27 @@ static int sbc_service_action(int host_no, struct scsi_cmd *cmd) { uint32_t *data; uint64_t size; + uint8_t *p; if (cmd->scb[1] != SAI_READ_CAPACITY_16) goto sense; - if (scsi_get_in_length(cmd) < 12) + if (scsi_get_in_length(cmd) < 32) goto overflow; data = scsi_get_in_buffer(cmd); - memset(data, 0, 12); + memset(data, 0, 32); size = cmd->dev->size >> BLK_SHIFT; *((uint64_t *)(data)) = __cpu_to_be64(size - 1); data[2] = __cpu_to_be32(1UL << BLK_SHIFT); + p = (void *)data; + p[14] |= 0x80; + overflow: - scsi_set_in_resid_by_actual(cmd, 12); + scsi_set_in_resid_by_actual(cmd, 32); return SAM_STAT_GOOD; sense: sense_data_build(cmd, ILLEGAL_REQUEST, ASC_INVALID_OP_CODE); @@ -219,10 +223,49 @@ sense: return SAM_STAT_CHECK_CONDITION; } +#include <xfs/xfs.h> + +static int sbc_write_same_16(int host_no, struct scsi_cmd *cmd) +{ + struct xfs_flock64 fl; + int ret; + + memset(&fl, 0, sizeof(fl)); + fl.l_whence = SEEK_SET; + fl.l_start = scsi_rw_offset(cmd->scb) << BLK_SHIFT; + fl.l_len = scsi_rw_count(cmd->scb) << BLK_SHIFT; + + ret = xfsctl(NULL, cmd->dev->fd, XFS_IOC_UNRESVSP64, &fl); + + eprintf("%llu %lld %d\n", fl.l_start, fl.l_len, ret); + + scsi_set_in_resid_by_actual(cmd, 0); + return SAM_STAT_GOOD; +} + +static unsigned char vpdb0_data[] = { + /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +}; + +static void update_vpd_b0(struct scsi_lu *lu, void *sn) +{ + struct vpd *vpd_pg = lu->attrs.lu_vpd[PCODE_OFFSET(0xb0)]; + char *data = (char *)vpd_pg->data; + uint32_t g = 1; + + memcpy(data, vpdb0_data, sizeof(vpdb0_data)); + put_unaligned_be32(g, data + 24); +} + static int sbc_lu_init(struct scsi_lu *lu) { + struct vpd **lu_vpd = lu->attrs.lu_vpd; uint64_t size; uint8_t *data; + int pg; if (spc_lu_init(lu)) return TGTADM_NOMEM; @@ -259,6 +302,12 @@ static int sbc_lu_init(struct scsi_lu *lu) /* Informational Exceptions Control page */ add_mode_page(lu, "0x1c:0:10:8:0:0:0:0:0:0:0:0:0"); + /* VPD page 0xb0 */ + pg = PCODE_OFFSET(0xb0); + lu_vpd[pg] = alloc_vpd(0x3c); + lu_vpd[pg]->vpd_update = update_vpd_b0; + lu_vpd[pg]->vpd_update(lu, NULL); + return 0; } @@ -391,7 +440,7 @@ static struct device_type_template sbc_template = { {spc_illegal_op,}, {sbc_sync_cache, NULL, PR_WE_FA|PR_EA_FA|PR_WE_FN|PR_EA_FN}, {spc_illegal_op,}, - {spc_illegal_op,}, + {sbc_write_same_16,}, {spc_illegal_op,}, {spc_illegal_op,}, {spc_illegal_op,}, diff --git a/usr/scsi.c b/usr/scsi.c index cef231b..62819e2 100644 --- a/usr/scsi.c +++ b/usr/scsi.c @@ -123,6 +123,7 @@ uint64_t scsi_rw_offset(uint8_t *scb) case WRITE_12: case VERIFY_12: case WRITE_VERIFY_12: + case WRITE_SAME_16: off = (uint32_t)scb[2] << 24 | (uint32_t)scb[3] << 16 | (uint32_t)scb[4] << 8 | (uint32_t)scb[5]; break; @@ -172,6 +173,7 @@ uint32_t scsi_rw_count(uint8_t *scb) case VERIFY_16: case WRITE_VERIFY_16: case SYNCHRONIZE_CACHE_16: + case WRITE_SAME_16: cnt = (uint32_t)scb[10] << 24 | (uint32_t)scb[11] << 16 | (uint32_t)scb[12] << 8 | (uint32_t)scb[13]; break; diff --git a/usr/scsi.h b/usr/scsi.h index f4d8c11..117888d 100644 --- a/usr/scsi.h +++ b/usr/scsi.h @@ -75,6 +75,7 @@ #define WRITE_VERIFY_16 0x8e #define VERIFY_16 0x8f #define SYNCHRONIZE_CACHE_16 0x91 +#define WRITE_SAME_16 0x93 #define SERVICE_ACTION_IN 0x9e #define SAI_READ_CAPACITY_16 0x10 #define REPORT_LUNS 0xa0 -- To unsubscribe from this list: send the line "unsubscribe stgt" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html