[PATCH v2 4/7] sd: arbitrary dif meta-data sizes

Keith Busch keith.busch at intel.com
Thu Mar 21 13:52:04 EDT 2013


Possible block formats with protection information may have larger
meta-data per physical block than an 8byte DIF. The first 8 bytes of
the meta-data region are for DIF data, while the remaining meta-data
is application specific. The size of the integrity buffer is already
allocated large enough for the meta-data size per sector, but accessing
the integrity buffer assumed meta-data region per sector was the size
of the DIF tuple. This patch updates the DIF tuple accesses to take into
account size of the block meta-data.

Cc: Martin K. Petersen <martin.petersen at oracle.com>
Signed-off-by: Keith Busch <keith.busch at intel.com>
---
 drivers/scsi/sd_dif.c  |   86 ++++++++++++++++++++++++++++++++---------------
 fs/bio-integrity.c     |    8 +++-
 include/linux/blkdev.h |    5 ++-
 3 files changed, 67 insertions(+), 32 deletions(-)

diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c
index aae5507..1735513 100644
--- a/drivers/scsi/sd_dif.c
+++ b/drivers/scsi/sd_dif.c
@@ -56,16 +56,19 @@ static __u16 sd_dif_ip_fn(void *data, unsigned int len)
 static void sd_dif_type1_generate(struct blk_integrity_exchg *bix, csum_fn *fn)
 {
 	void *buf = bix->data_buf;
-	struct sd_dif_tuple *sdt = bix->prot_buf;
+	void *tuple = bix->prot_buf;
 	sector_t sector = bix->sector;
+	struct sd_dif_tuple *sdt;
 	unsigned int i;
 
-	for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
+	for (i = 0 ; i < bix->data_size ; i += bix->sector_size) {
+		sdt = tuple;
 		sdt->guard_tag = fn(buf, bix->sector_size);
 		sdt->ref_tag = cpu_to_be32(sector & 0xffffffff);
 		sdt->app_tag = 0;
 
 		buf += bix->sector_size;
+		tuple += bix->tuple_size;
 		sector++;
 	}
 }
@@ -84,11 +87,15 @@ static int sd_dif_type1_verify(struct blk_integrity_exchg *bix, csum_fn *fn)
 {
 	void *buf = bix->data_buf;
 	void *end = buf + bix->data_size;
-	struct sd_dif_tuple *sdt = bix->prot_buf;
+	void *tuple = bix->prot_buf;
+	struct sd_dif_tuple *sdt;
 	sector_t sector = bix->sector;
 	__u16 csum;
 
-	for (; buf < end; buf += bix->sector_size, sdt++, sector++) {
+	for (; buf < end; buf += bix->sector_size, tuple += bix->tuple_size,
+								sector++) {
+		sdt = tuple;
+
 		/* Unwritten sectors */
 		if (sdt->app_tag == 0xffff)
 			continue;
@@ -128,25 +135,31 @@ static int sd_dif_type1_verify_ip(struct blk_integrity_exchg *bix)
 /*
  * Functions for interleaving and deinterleaving application tags
  */
-static void sd_dif_type1_set_tag(void *prot, void *tag_buf, unsigned int sectors)
+static void sd_dif_type1_set_tag(void *prot, void *tag_buf, unsigned int sectors,
+							unsigned short tuple_size)
 {
-	struct sd_dif_tuple *sdt = prot;
+	void *tuple = prot;
 	u8 *tag = tag_buf;
+	struct sd_dif_tuple *sdt;
 	unsigned int i, j;
 
-	for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) {
+	for (i = 0, j = 0 ; i < sectors ; i++, j += 2, tuple += tuple_size) {
+		sdt = tuple;
 		sdt->app_tag = tag[j] << 8 | tag[j+1];
 		BUG_ON(sdt->app_tag == 0xffff);
 	}
 }
 
-static void sd_dif_type1_get_tag(void *prot, void *tag_buf, unsigned int sectors)
+static void sd_dif_type1_get_tag(void *prot, void *tag_buf, unsigned int sectors,
+							unsigned short tuple_size)
 {
-	struct sd_dif_tuple *sdt = prot;
+	void *tuple = prot;
 	u8 *tag = tag_buf;
+	struct sd_dif_tuple *sdt;
 	unsigned int i, j;
 
-	for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) {
+	for (i = 0, j = 0 ; i < sectors ; i++, j += 2, tuple += tuple_size) {
+		sdt = tuple;
 		tag[j] = (sdt->app_tag & 0xff00) >> 8;
 		tag[j+1] = sdt->app_tag & 0xff;
 	}
@@ -180,15 +193,18 @@ static struct blk_integrity dif_type1_integrity_ip = {
 static void sd_dif_type3_generate(struct blk_integrity_exchg *bix, csum_fn *fn)
 {
 	void *buf = bix->data_buf;
-	struct sd_dif_tuple *sdt = bix->prot_buf;
+	void *tuple = bix->prot_buf;
+	struct sd_dif_tuple *sdt;
 	unsigned int i;
 
-	for (i = 0 ; i < bix->data_size ; i += bix->sector_size, sdt++) {
+	for (i = 0 ; i < bix->data_size ; i += bix->sector_size) {
+		sdt = tuple;
 		sdt->guard_tag = fn(buf, bix->sector_size);
 		sdt->ref_tag = 0;
 		sdt->app_tag = 0;
 
 		buf += bix->sector_size;
+		tuple += bix->tuple_size;
 	}
 }
 
@@ -206,11 +222,15 @@ static int sd_dif_type3_verify(struct blk_integrity_exchg *bix, csum_fn *fn)
 {
 	void *buf = bix->data_buf;
 	void *end = buf + bix->data_size;
-	struct sd_dif_tuple *sdt = bix->prot_buf;
+	void *tuple = bix->prot_buf;
 	sector_t sector = bix->sector;
+	struct sd_dif_tuple *sdt;
 	__u16 csum;
 
-	for (; buf < end; buf += bix->sector_size, sdt++, sector++) {
+	for (; buf < end; buf += bix->sector_size, tuple += bix->tuple_size,
+								sector++) {
+		sdt = tuple;
+
 		/* Unwritten sectors */
 		if (sdt->app_tag == 0xffff && sdt->ref_tag == 0xffffffff)
 			continue;
@@ -239,26 +259,32 @@ static int sd_dif_type3_verify_ip(struct blk_integrity_exchg *bix)
 	return sd_dif_type3_verify(bix, sd_dif_ip_fn);
 }
 
-static void sd_dif_type3_set_tag(void *prot, void *tag_buf, unsigned int sectors)
+static void sd_dif_type3_set_tag(void *prot, void *tag_buf, unsigned int sectors,
+							unsigned short tuple_size)
 {
-	struct sd_dif_tuple *sdt = prot;
+	void *tuple = prot;
 	u8 *tag = tag_buf;
+	struct sd_dif_tuple *sdt;
 	unsigned int i, j;
 
-	for (i = 0, j = 0 ; i < sectors ; i++, j += 6, sdt++) {
+	for (i = 0, j = 0 ; i < sectors ; i++, j += 6, tuple += tuple_size) {
+		sdt = tuple;
 		sdt->app_tag = tag[j] << 8 | tag[j+1];
 		sdt->ref_tag = tag[j+2] << 24 | tag[j+3] << 16 |
 			tag[j+4] << 8 | tag[j+5];
 	}
 }
 
-static void sd_dif_type3_get_tag(void *prot, void *tag_buf, unsigned int sectors)
+static void sd_dif_type3_get_tag(void *prot, void *tag_buf, unsigned int sectors,
+							unsigned short tuple_size)
 {
-	struct sd_dif_tuple *sdt = prot;
+	void *tuple = prot;
 	u8 *tag = tag_buf;
+	struct sd_dif_tuple *sdt;
 	unsigned int i, j;
 
-	for (i = 0, j = 0 ; i < sectors ; i++, j += 2, sdt++) {
+	for (i = 0, j = 0 ; i < sectors ; i++, j += 2, tuple += tuple_size) {
+		sdt = tuple;
 		tag[j] = (sdt->app_tag & 0xff00) >> 8;
 		tag[j+1] = sdt->app_tag & 0xff;
 		tag[j+2] = (sdt->ref_tag & 0xff000000) >> 24;
@@ -355,14 +381,15 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
 void sd_dif_prepare(struct request *rq, sector_t hw_sector,
 		    unsigned int sector_sz)
 {
-	const int tuple_sz = sizeof(struct sd_dif_tuple);
 	struct bio *bio;
 	struct scsi_disk *sdkp;
 	struct sd_dif_tuple *sdt;
+	struct blk_integrity *bi;
 	unsigned int i, j;
 	u32 phys, virt;
 
 	sdkp = rq->bio->bi_bdev->bd_disk->private_data;
+	bi = bdev_get_integrity(rq->bio->bi_bdev);
 
 	if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION)
 		return;
@@ -380,14 +407,15 @@ void sd_dif_prepare(struct request *rq, sector_t hw_sector,
 				(__ffs(sector_sz) - 9)) & 0xffffffff;
 
 		bip_for_each_vec(iv, bio->bi_integrity, i) {
-			sdt = kmap_atomic(iv->bv_page)
+			void *tuple = kmap_atomic(iv->bv_page)
 				+ iv->bv_offset;
 
-			for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) {
-
+			for (j = 0 ; j < iv->bv_len ; j += bi->tuple_size) {
+				sdt = tuple;
 				if (be32_to_cpu(sdt->ref_tag) == virt)
 					sdt->ref_tag = cpu_to_be32(phys);
 
+				tuple += bi->tuple_size;
 				virt++;
 				phys++;
 			}
@@ -405,14 +433,15 @@ void sd_dif_prepare(struct request *rq, sector_t hw_sector,
  */
 void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
 {
-	const int tuple_sz = sizeof(struct sd_dif_tuple);
 	struct scsi_disk *sdkp;
 	struct bio *bio;
 	struct sd_dif_tuple *sdt;
+	struct blk_integrity *bi;
 	unsigned int i, j, sectors, sector_sz;
 	u32 phys, virt;
 
 	sdkp = scsi_disk(scmd->request->rq_disk);
+	bi = bdev_get_integrity(scmd->request->bio->bi_bdev);
 
 	if (sdkp->protection_type == SD_DIF_TYPE3_PROTECTION || good_bytes == 0)
 		return;
@@ -429,11 +458,11 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
 					(__ffs(sector_sz) - 9)) & 0xffffffff;
 
 		bip_for_each_vec(iv, bio->bi_integrity, i) {
-			sdt = kmap_atomic(iv->bv_page)
+			void *tuple = kmap_atomic(iv->bv_page)
 				+ iv->bv_offset;
 
-			for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) {
-
+			for (j = 0 ; j < iv->bv_len ; j += bi->tuple_size) {
+				sdt = tuple;
 				if (sectors == 0) {
 					kunmap_atomic(sdt);
 					return;
@@ -442,6 +471,7 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
 				if (be32_to_cpu(sdt->ref_tag) == phys)
 					sdt->ref_tag = cpu_to_be32(virt);
 
+				tuple += bi->tuple_size;
 				virt++;
 				phys++;
 				sectors--;
diff --git a/fs/bio-integrity.c b/fs/bio-integrity.c
index b4ab7da..81b0ddf 100644
--- a/fs/bio-integrity.c
+++ b/fs/bio-integrity.c
@@ -273,9 +273,11 @@ int bio_integrity_tag(struct bio *bio, void *tag_buf, unsigned int len, int set)
 	}
 
 	if (set)
-		bi->set_tag_fn(bip->bip_buf, tag_buf, nr_sectors);
+		bi->set_tag_fn(bip->bip_buf, tag_buf, nr_sectors,
+							bi->tuple_size);
 	else
-		bi->get_tag_fn(bip->bip_buf, tag_buf, nr_sectors);
+		bi->get_tag_fn(bip->bip_buf, tag_buf, nr_sectors,
+							bi->tuple_size);
 
 	return 0;
 }
@@ -338,6 +340,7 @@ static void bio_integrity_generate(struct bio *bio)
 	total = 0;
 	bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
 	bix.sector_size = bi->sector_size;
+	bix.tuple_size = bi->tuple_size;
 
 	bio_for_each_segment(bv, bio, i) {
 		void *kaddr = kmap_atomic(bv->bv_page);
@@ -480,6 +483,7 @@ static int bio_integrity_verify(struct bio *bio)
 	ret = total = 0;
 	bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
 	bix.sector_size = bi->sector_size;
+	bix.tuple_size = bi->tuple_size;
 
 	bio_for_each_segment(bv, bio, i) {
 		void *kaddr = kmap_atomic(bv->bv_page);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 1756001..70eccab 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -1325,13 +1325,14 @@ struct blk_integrity_exchg {
 	sector_t		sector;
 	unsigned int		data_size;
 	unsigned short		sector_size;
+	unsigned short		tuple_size;
 	const char		*disk_name;
 };
 
 typedef void (integrity_gen_fn) (struct blk_integrity_exchg *);
 typedef int (integrity_vrfy_fn) (struct blk_integrity_exchg *);
-typedef void (integrity_set_tag_fn) (void *, void *, unsigned int);
-typedef void (integrity_get_tag_fn) (void *, void *, unsigned int);
+typedef void (integrity_set_tag_fn) (void *, void *, unsigned int, unsigned short);
+typedef void (integrity_get_tag_fn) (void *, void *, unsigned int, unsigned short);
 
 struct blk_integrity {
 	integrity_gen_fn	*generate_fn;
-- 
1.7.0.4




More information about the Linux-nvme mailing list