[PATCHes] Updated patches for thin-provisioning support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Tomo,

Please find attached updated patches for UNMAP and thin provisioning support.



regards
ronnie sahlberg

Attachment: 0001-TGTIMG-Add-support-for-thin-provisioning.patch.gz
Description: GNU Zip compressed data

From ce53f79c2692147164fe4e6ede856c2f26b3028f Mon Sep 17 00:00:00 2001
From: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx>
Date: Sun, 1 Apr 2012 07:09:10 +1000
Subject: [PATCH 1/2] TGTIMG: Add support for thin-provisioning

A new flag --ting-provisioning is added to the tgtimg command.
When used this flag will create a sparse file without any
allocation guarantee.
It will also verify that FALLOC_FL_PUNCH_HOLE works.

If such files are created, a future patch to tgtd will add
support for the UNMAP command that is used by initiators to
release blocks that are no longer in use.

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx>
---
 doc/tgtimg.8.xml |   22 ++++++++++++++++++++++
 usr/tgtimg.c     |   37 ++++++++++++++++++++++++++++---------
 usr/util.h       |   16 ++++++++++++++++
 3 files changed, 66 insertions(+), 9 deletions(-)

diff --git a/doc/tgtimg.8.xml b/doc/tgtimg.8.xml
index 5a787af..e067db0 100644
--- a/doc/tgtimg.8.xml
+++ b/doc/tgtimg.8.xml
@@ -21,6 +21,7 @@
 		<arg choice="opt">-s --size &lt;size&gt;</arg>
 		<arg choice="opt">-t --type &lt;media-type&gt;</arg>
 		<arg choice="opt">-f --file &lt;path&gt;</arg>
+		<arg choice="opt">-T --thin-provisioning</arg>
 	</cmdsynopsis>
 	<cmdsynopsis>
 		<command>tgtimg --help</command>
@@ -126,6 +127,27 @@ Supported media types for tape devices are :
         </listitem>
       </varlistentry>
 
+      <varlistentry><term><option>-T, --thin-provisioning</option></term>
+        <listitem>
+          <para>
+	    This argument makes the allocation of the image format use
+	    thin-provisioning. This means that the file created will be a
+	    sparse file that will allocate blocks from the filesystem on demand.
+          </para>
+          <para>
+	    Be careful when using thin-provisioning. If the filesystem
+	    fills up a iSCSI write to a thin-provisioned LUN
+	    can fail. Initiators generally do not handle "out of space" errors
+	    gracefully.
+          </para>
+          <para>
+	    Thin-provisioning uses FALLOC_FL_PUNCH_HOLE which is only available
+	    on some linux filesystems. Thin-provisioning can only be used for
+	    DISK images.
+          </para>
+        </listitem>
+      </varlistentry>
+
     </variablelist>
   </refsect1>
 
diff --git a/usr/tgtimg.c b/usr/tgtimg.c
index f4388d9..286e333 100644
--- a/usr/tgtimg.c
+++ b/usr/tgtimg.c
@@ -1,5 +1,5 @@
 /*
- *	Create blank media files for bs_tape backing store
+ *	Create media files for TGTD devices
  *
  * Copyright (C) 2008 Mark Harvey markh794@xxxxxxxxx
  *
@@ -38,6 +38,7 @@
 #include "ssc.h"
 #include "libssc.h"
 #include "scsi.h"
+#include "util.h"
 
 #define NO_LOGGING
 #include "log.h"
@@ -59,6 +60,7 @@ struct option const long_options[] = {
 	{"size", required_argument, NULL, 's'},
 	{"type", required_argument, NULL, 't'},
 	{"file", required_argument, NULL, 'f'},
+	{"thin-provisioning", no_argument, NULL, 'T'},
 	{NULL, 0, NULL, 0},
 };
 
@@ -71,7 +73,7 @@ static void usage(int status)
 		printf("\
 Linux SCSI Target Framework Image File Utility, version %s\n\
 \n\
-  --op new --device-type tape --barcode=[code] --size=[size] --type=[type] --file=[path]\n\
+  --op new --device-type tape --barcode=[code] --size=[size] --type=[type] --file=[path] [--thin-provisioning]\n\
 			create a new tape image file.\n\
 			[code] is a string of chars.\n\
 			[size] is media size(in megabytes).\n\
@@ -83,6 +85,7 @@ Linux SCSI Target Framework Image File Utility, version %s\n\
   --op show --device-type tape --file=[path]\n\
 			dump the tape image file contents.\n\
 			[path] is the tape image file\n\
+  --thin-provisioning   create a sparse file for the media\n\
   --help                display this help and exit\n\
 \n\
 Report bugs to <stgt@xxxxxxxxxxxxxxx>.\n", TGT_VERSION);
@@ -414,7 +417,7 @@ static int mmc_ops(int op, char *path, char *media_type)
 	return 0;
 }
 
-static int sbc_new(int op, char *path, char *capacity, char *media_type)
+static int sbc_new(int op, char *path, char *capacity, char *media_type, int thin)
 {
 	int fd;
 
@@ -438,9 +441,21 @@ static int sbc_new(int op, char *path, char *capacity, char *media_type)
 			perror("Failed creating file");
 			exit(2);
 		}
-		if (posix_fallocate(fd, 0, size*1024*1024LL) == -1) {
-			perror("posix_fallocate failed.");
-			exit(3);
+		if (thin) {
+			if (ftruncate(fd, size*1024*1024LL) != 0) {
+				perror("Failed to set file size");
+				exit(6);
+			}
+			if (unmap_file_region(fd, 0, size*1024*1024LL) != 0) {
+				perror("Thin provisioning not available on"
+					" this file");
+				exit(5);
+			}
+		} else {
+			if (posix_fallocate(fd, 0, size*1024*1024LL) == -1) {
+				perror("posix_fallocate failed.");
+				exit(3);
+			}
 		}
 
 		free(buf);
@@ -456,7 +471,7 @@ static int sbc_new(int op, char *path, char *capacity, char *media_type)
 	return 0;
 }
 
-static int sbc_ops(int op, char *path, char *capacity, char *media_type)
+static int sbc_ops(int op, char *path, char *capacity, char *media_type, int thin)
 {
 	if (op == OP_NEW) {
 		if (!media_type) {
@@ -471,7 +486,7 @@ static int sbc_ops(int op, char *path, char *capacity, char *media_type)
 			eprintf("Missing the capacity param\n");
 			usage(1);
 		}
-		return sbc_new(op, path, capacity, media_type);
+		return sbc_new(op, path, capacity, media_type, thin);
 	} else {
 		eprintf("unknown the operation type\n");
 		usage(1);
@@ -489,6 +504,7 @@ int main(int argc, char **argv)
 	int dev_type = TYPE_TAPE;
 	int op = -1;
 	char *path = NULL;
+	int thin = 0;
 
 	while ((ch = getopt_long(argc, argv, short_options,
 				 long_options, &longindex)) >= 0) {
@@ -514,6 +530,9 @@ int main(int argc, char **argv)
 		case 'h':
 			usage(0);
 			break;
+		case 'T':
+			thin = 1;
+			break;
 		default:
 			eprintf("unrecognized option '%s'\n", optarg);
 			usage(1);
@@ -543,7 +562,7 @@ int main(int argc, char **argv)
 		mmc_ops(op, path, media_type);
 		break;
 	case TYPE_DISK:
-		sbc_ops(op, path, media_capacity, media_type);
+		sbc_ops(op, path, media_capacity, media_type, thin);
 		break;
 	default:
 		eprintf("unsupported the device type operation\n");
diff --git a/usr/util.h b/usr/util.h
index e75b23a..4bf157d 100644
--- a/usr/util.h
+++ b/usr/util.h
@@ -5,6 +5,7 @@
 #include <endian.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <linux/falloc.h>
 #include <signal.h>
 #include <syscall.h>
 #include <unistd.h>
@@ -159,4 +160,19 @@ int concat_buf_finish(struct concat_buf *b);
 int concat_write(struct concat_buf *b, int fd, int offset);
 void concat_buf_release(struct concat_buf *b);
 
+
+/* If we have recent enough glibc to support PUNCH HOLE we try to unmap
+ * the region.
+ */
+static inline int unmap_file_region(int fd, off_t offset, off_t length)
+{
+#ifdef FALLOC_FL_PUNCH_HOLE
+	if (fallocate(fd, FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
+			offset, length) == 0)
+		return 0; 
+#endif
+	return -1;
+}
+
+
 #endif
-- 
1.7.3.1

Attachment: 0002-SBC-UNMAP-Add-support-for-thin-provisioning-and-the-.patch.gz
Description: GNU Zip compressed data

From 2830abc3935294eba621b781f72aecda604c65a7 Mon Sep 17 00:00:00 2001
From: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx>
Date: Sun, 1 Apr 2012 08:04:06 +1000
Subject: [PATCH 2/2] SBC UNMAP: Add support for thin-provisioning and the UNMAP command.

The UNMAP command is implemented using FALLOC_FL_PUNCH_HOLE and will
release UNMAPPED blocks back to the underlying filesystem.

FALLOC_FL_PUNCH_HOLE is fairly new addition to Linux but works on
ext4 and XFS filesystems currently.

Signed-off-by: Ronnie Sahlberg <ronniesahlberg@xxxxxxxxx>
---
 doc/tgtadm.8.xml |   25 ++++++++++++++
 usr/bs_rdwr.c    |   97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 usr/sbc.c        |   76 +++++++++++++++++++++++++++++++++++++++++-
 usr/scsi.h       |    1 +
 usr/spc.c        |   43 +++++++++++++++++++++--
 usr/target.c     |    2 +
 usr/tgtd.h       |    2 +
 7 files changed, 241 insertions(+), 5 deletions(-)

diff --git a/doc/tgtadm.8.xml b/doc/tgtadm.8.xml
index 668e184..a40f659 100644
--- a/doc/tgtadm.8.xml
+++ b/doc/tgtadm.8.xml
@@ -352,6 +352,31 @@ tgtadm --lld iscsi --mode logicalunit --op update --tid 1 --lun 1 \
          --params readonly=1
       </screen>
 
+      <varlistentry><term><option>thin_provisioning=&lt;0|1&gt;</option></term>
+        <listitem>
+          <para>
+	    This controls the provisioning for the LUN. A thin-provisioned
+	    LUN is represented as a sparse file.
+	    TGTD supports provisioning type 2 for sparse files.
+	    When initiators use the SCSI UNMAP command TGTD will release
+	    the affected areas back to the filesystem using 
+	    FALLOC_FL_PUNCH_HOLE.
+          </para>
+          <para>
+	    This parameter only applies to DISK devices.
+          </para>
+          <para>
+	    Thin-provisioning only works for LUNs stored on filesystems
+	    that support FALLOC_FL_PUNCH_HOLE.
+          </para>
+        </listitem>
+      </varlistentry>
+
+      <screen format="linespecific">
+tgtadm --lld iscsi --mode logicalunit --op update --tid 1 --lun 1 \
+         --params thin_provisioning=1
+      </screen>
+
     </variablelist>
   </refsect1>
 
diff --git a/usr/bs_rdwr.c b/usr/bs_rdwr.c
index 84ed278..7d614f8 100644
--- a/usr/bs_rdwr.c
+++ b/usr/bs_rdwr.c
@@ -27,6 +27,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include <linux/fs.h>
@@ -63,6 +65,7 @@ static void bs_rdwr_request(struct scsi_cmd *cmd)
 	uint8_t key;
 	uint16_t asc;
 	char *tmpbuf;
+	struct stat st;
 
 	ret = length = 0;
 	key = asc = 0;
@@ -160,6 +163,100 @@ static void bs_rdwr_request(struct scsi_cmd *cmd)
 
 		free(tmpbuf);
 		break;
+	case UNMAP:
+		if (!cmd->dev->attrs.thinprovisioning) {
+			result = SAM_STAT_CHECK_CONDITION;
+			key = ILLEGAL_REQUEST;
+			asc = ASC_INVALID_FIELD_IN_CDB;
+			break;
+		}
+
+		if (fstat(fd, &st) != 0) {
+			eprintf("Failed to fstat() file for UNMAP\n");
+			result = SAM_STAT_CHECK_CONDITION;
+			key = HARDWARE_ERROR;
+			asc = ASC_INTERNAL_TGT_FAILURE;
+			break;
+		}
+		
+		length = scsi_get_out_length(cmd);
+		tmpbuf = scsi_get_out_buffer(cmd);
+
+		if (length < 8)
+			break;
+
+		length -= 8;
+		tmpbuf += 8;
+
+		while (length >= 16) {
+			uint64_t offset;
+			uint64_t len;
+
+			offset = get_unaligned_be64(&tmpbuf[0]);
+			offset = offset << cmd->dev->blk_shift;
+
+			len = get_unaligned_be32(&tmpbuf[8]);
+			len = len << cmd->dev->blk_shift;
+
+			if (offset + len > st.st_size) {
+				eprintf("UNMAP beyond EOF\n");
+				result = SAM_STAT_CHECK_CONDITION;
+				key = ILLEGAL_REQUEST;
+				asc = ASC_LBA_OUT_OF_RANGE;
+				break;
+			}
+
+			/* we can only punch holes aligned for full blocks.
+			 * if not aligned to a block boundary we overwrite
+			 * the first partial block with zero
+			 */
+			if (len > 0 && offset % st.st_blksize) {
+				char *buf;
+				uint64_t l;
+
+				l = st.st_blksize - offset % st.st_blksize;
+				if (l > len)
+					l = len;
+
+				buf = zalloc(l);
+				pwrite64(fd, buf, l, offset);
+				free(buf);
+				
+				offset += l;
+				len -= l;
+			}
+
+			if (len >= st.st_blksize) {
+				if (unmap_file_region(fd, offset,
+					len - len % st.st_blksize) != 0) {
+					eprintf("Failed to punch hole for"
+						" UNMAP at offset:" PRIu64
+						" length: " PRIu64 "\n",
+						offset,
+						len - len % st.st_blksize);
+					result = SAM_STAT_CHECK_CONDITION;
+					key = HARDWARE_ERROR;
+					asc = ASC_INTERNAL_TGT_FAILURE;
+					break;
+				}
+				offset += len - len % st.st_blksize;
+				len     = len % st.st_blksize;
+
+			}
+
+			/* zero the tail if there is one */
+			if (len > 0) {
+				char *buf;
+
+				buf = zalloc(len);
+				pwrite64(fd, buf, len, offset);
+				free(buf);
+			}
+
+			length -= 16;
+			tmpbuf += 16;
+		}
+		break;
 	default:
 		break;
 	}
diff --git a/usr/sbc.c b/usr/sbc.c
index 0c3681e..c93d5de 100644
--- a/usr/sbc.c
+++ b/usr/sbc.c
@@ -141,6 +141,60 @@ sense:
 	return SAM_STAT_CHECK_CONDITION;
 }
 
+static int sbc_unmap(int host_no, struct scsi_cmd *cmd)
+{
+	int ret;
+	unsigned char key = ILLEGAL_REQUEST;
+	uint16_t asc = ASC_LUN_NOT_SUPPORTED;
+	struct scsi_lu *lu = cmd->dev;
+	int anchor;
+
+	ret = device_reserved(cmd);
+	if (ret)
+		return SAM_STAT_RESERVATION_CONFLICT;
+
+	/* We dont support anchored blocks */
+	anchor = cmd->scb[1] & 0x01;
+	if (anchor) {
+		key = ILLEGAL_REQUEST;
+		asc = ASC_INVALID_FIELD_IN_CDB;
+		goto sense;
+	}
+
+	if (!lu->attrs.thinprovisioning) {
+		key = ILLEGAL_REQUEST;
+		asc = ASC_INVALID_OP_CODE;
+		goto sense;
+	}
+
+	if (lu->attrs.removable && !lu->attrs.online) {
+		key = NOT_READY;
+		asc = ASC_MEDIUM_NOT_PRESENT;
+		goto sense;
+	}
+
+	if (lu->attrs.readonly) {
+		key = DATA_PROTECT;
+		asc = ASC_WRITE_PROTECT;
+		goto sense;
+	}
+
+	ret = cmd->dev->bst->bs_cmd_submit(cmd);
+	if (ret) {
+		key = HARDWARE_ERROR;
+		asc = ASC_INTERNAL_TGT_FAILURE;
+		goto sense;
+	}
+
+sense:
+	cmd->offset = 0;
+	scsi_set_in_resid_by_actual(cmd, 0);
+	scsi_set_out_resid_by_actual(cmd, 0);
+
+	sense_data_build(cmd, key, asc);
+	return SAM_STAT_CHECK_CONDITION;
+}
+
 static int sbc_rw(int host_no, struct scsi_cmd *cmd)
 {
 	int ret;
@@ -370,8 +424,11 @@ static int sbc_service_action(int host_no, struct scsi_cmd *cmd)
 	data[2] = __cpu_to_be32(1UL << bshift);
 
 	val = (cmd->dev->attrs.lbppbe << 16) | cmd->dev->attrs.la_lba;
+	if (cmd->dev->attrs.thinprovisioning)
+		val |= (3 << 14); /* set LBPME and LBPRZ */
 	data[3] = __cpu_to_be32(val);
 
+
 overflow:
 	scsi_set_in_resid_by_actual(cmd, len);
 	return SAM_STAT_GOOD;
@@ -549,7 +606,24 @@ static struct device_type_template sbc_template = {
 		{spc_illegal_op,},
 		{spc_illegal_op,},
 
-		[0x40 ... 0x4f] = {spc_illegal_op,},
+		/* 0x40 */
+		{spc_illegal_op,},
+		{spc_illegal_op,},
+		{sbc_unmap,},
+		{spc_illegal_op,},
+		{spc_illegal_op,},
+		{spc_illegal_op,},
+		{spc_illegal_op,},
+		{spc_illegal_op,},
+
+		{spc_illegal_op,},
+		{spc_illegal_op,},
+		{spc_illegal_op,},
+		{spc_illegal_op,},
+		{spc_illegal_op,},
+		{spc_illegal_op,},
+		{spc_illegal_op,},
+		{spc_illegal_op,},
 
 		/* 0x50 */
 		{spc_illegal_op,},
diff --git a/usr/scsi.h b/usr/scsi.h
index ca1109a..1508cc6 100644
--- a/usr/scsi.h
+++ b/usr/scsi.h
@@ -60,6 +60,7 @@
 #define WRITE_LONG            0x3f
 #define CHANGE_DEFINITION     0x40
 #define WRITE_SAME            0x41
+#define UNMAP		      0x42
 #define READ_TOC              0x43
 #define LOG_SELECT            0x4c
 #define LOG_SENSE             0x4d
diff --git a/usr/spc.c b/usr/spc.c
index 44cd193..1834038 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -139,6 +139,24 @@ static void update_vpd_83(struct scsi_lu *lu, void *id)
 	strncpy((char *)data + 4, id, SCSI_ID_LEN);
 }
 
+static void update_vpd_b2(struct scsi_lu *lu, void *id)
+{
+	struct vpd *vpd_pg = lu->attrs.lu_vpd[PCODE_OFFSET(0xb2)];
+	uint8_t	*data = vpd_pg->data;
+
+	if (lu->attrs.thinprovisioning) {
+		data[0] = 0;		/* threshold exponent */
+		data[1] = 0x84;		/* LBPU LBPRZ */
+		data[2] = 0x02;		/* provisioning type */
+		data[3] = 0;
+	} else {
+		data[0] = 0;
+		data[1] = 0;
+		data[2] = 0;
+		data[3] = 0;
+	}
+}
+
 static void update_b0_opt_xfer_gran(struct scsi_lu *lu, int opt_xfer_gran)
 {
 	struct vpd *vpd_pg = lu->attrs.lu_vpd[PCODE_OFFSET(0xb0)];
@@ -1661,7 +1679,7 @@ enum {
 	Opt_removable, Opt_readonly, Opt_online,
 	Opt_mode_page,
 	Opt_path,
-	Opt_bsoflags,
+	Opt_bsoflags, Opt_thinprovisioning,
 	Opt_err,
 };
 
@@ -1682,6 +1700,7 @@ static match_table_t tokens = {
 	{Opt_mode_page, "mode_page=%s"},
 	{Opt_path, "path=%s"},
 	{Opt_bsoflags, "bsoflags=%s"},
+	{Opt_thinprovisioning, "thin_provisioning=%s"},
 	{Opt_err, NULL},
 };
 
@@ -1772,6 +1791,12 @@ tgtadm_err lu_config(struct scsi_lu *lu, char *params, match_fn_t *fn)
 			match_strncpy(buf, &args[0], sizeof(buf));
 			attrs->readonly = atoi(buf);
 			break;
+		case Opt_thinprovisioning:
+			match_strncpy(buf, &args[0], sizeof(buf));
+			attrs->thinprovisioning = atoi(buf);
+			/* update the provisioning vpd page */
+			lu_vpd[PCODE_OFFSET(0xb2)]->vpd_update(lu, NULL);
+			break;
 		case Opt_online:
 			match_strncpy(buf, &args[0], sizeof(buf));
 			if (atoi(buf))
@@ -1807,6 +1832,10 @@ int spc_lu_init(struct scsi_lu *lu)
 
 	lu->attrs.device_type = lu->dev_type_template.type;
 	lu->attrs.qualifier = 0x0;
+	lu->attrs.thinprovisioning = 0;
+	lu->attrs.removable = 0;
+	lu->attrs.readonly = 0;
+	lu->attrs.sense_format = 0;
 
 	snprintf(lu->attrs.vendor_id, sizeof(lu->attrs.vendor_id),
 		 "%-16s", VENDOR_ID);
@@ -1839,9 +1868,15 @@ int spc_lu_init(struct scsi_lu *lu)
 	if (!lu_vpd[pg])
 		return -ENOMEM;
 
-	lu->attrs.removable = 0;
-	lu->attrs.readonly = 0;
-	lu->attrs.sense_format = 0;
+	/* VPD page 0xb2 LOGICAL BLOCK PROVISIONING*/
+	pg = PCODE_OFFSET(0xb2);
+	lu_vpd[pg] = alloc_vpd(LBP_VPD_LEN);
+	if (!lu_vpd[pg])
+		return -ENOMEM;
+	lu_vpd[pg]->vpd_update = update_vpd_b2;
+	lu_vpd[pg]->vpd_update(lu, NULL);
+
+
 	lu->dev_type_template.lu_offline(lu);
 
 	return 0;
diff --git a/usr/target.c b/usr/target.c
index 0b6be13..dd3ca91 100644
--- a/usr/target.c
+++ b/usr/target.c
@@ -1857,6 +1857,7 @@ tgtadm_err tgt_target_show_all(struct concat_buf *b)
 				 _TAB3 "Removable media: %s\n"
 				 _TAB3 "Prevent removal: %s\n"
 				 _TAB3 "Readonly: %s\n"
+				 _TAB3 "Thin-provisioning: %s\n"
 				 _TAB3 "Backing store type: %s\n"
 				 _TAB3 "Backing store path: %s\n"
 				 _TAB3 "Backing store flags: %s\n",
@@ -1871,6 +1872,7 @@ tgtadm_err tgt_target_show_all(struct concat_buf *b)
 				 lu_prevent_removal(lu) ?
 					"Yes" : "No",
 				 lu->attrs.readonly ? "Yes" : "No",
+				 lu->attrs.thinprovisioning ? "Yes" : "No",
 				 lu->bst ?
 					(lu->bst->bs_name ? : "Unknown") :
 					"None",
diff --git a/usr/tgtd.h b/usr/tgtd.h
index 726a3f5..03036ba 100644
--- a/usr/tgtd.h
+++ b/usr/tgtd.h
@@ -14,6 +14,7 @@ struct concat_buf;
 #define PRODUCT_ID_LEN		16
 #define PRODUCT_REV_LEN		4
 #define BLOCK_LIMITS_VPD_LEN	0x3C
+#define LBP_VPD_LEN		4
 
 #define PCODE_SHIFT		7
 #define PCODE_OFFSET(x) (x & ((1 << PCODE_SHIFT) - 1))
@@ -72,6 +73,7 @@ struct lu_phy_attr {
 	char qualifier;		/* Peripheral Qualifier */
 	char removable;		/* Removable media */
 	char readonly;          /* Read-Only media */
+	char thinprovisioning;  /* Use thin-provisioning for this LUN */
 	char online;		/* Logical Unit online */
 	char sense_format;	/* Descrptor format sense data supported */
 				/* For the following see READ CAPACITY (16) */
-- 
1.7.3.1


[Index of Archives]     [Linux SCSI]     [Linux RAID]     [Linux Clusters]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]

  Powered by Linux