Skip to contentSkip to conversation

Block Layer Data Integrity

PATCH In review Martin K. Petersen 2 participants 5 messages Jun 17, 2008

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Block Layer Data Integrity

These patches allow data integrity information (checksum and more) to be attached to I/Os at the block/filesystem layers and transferred through the entire I/O stack all the way to the physical storage device.

The integrity metadata can be generated in close proximity to the original data. Capable host adapters, RAID arrays and physical disks can verify the data integrity and abort I/Os in case of a mismatch.

Changes:

- Add "if in doubt" to Kconfig

- Make blk_rq_count_integrity_sg() more readable

- Queue integrity sysfs fixes

- Fix two struct bi leaks

- Rename struct bip to bio_integrity_payload

- Introduce bio_integrity_hw_sectors() that converts from block layer (512b) sectors to hardware sectors

- Fix kunmap_atomic() abuse

- Replace ?: constructs with if()

- Add __GFP_NOFAIL to bio_integrity_prep() allocation

#1 lore raw

PATCH 1/1 block: Globalize bio_set and bio_vec_slab

Move struct bio_set and biovec_slab definitions to bio.h so they can be used outside of bio.c.

---

2 files changed, 31 insertions(+), 28 deletions(-)
fs/bio.c            |   30 ++----------------------------
include/linux/bio.h |   29 +++++++++++++++++++++++++++++
fs/bio.c +2 -28
@@ -28,24 +28,9 @@
 #include <linux/blktrace_api.h>
 #include <scsi/sg.h>		/* for struct sg_iovec */
 
-#define BIO_POOL_SIZE 2
-
 static struct kmem_cache *bio_slab __read_mostly;
 
-#define BIOVEC_NR_POOLS 6
-
-/*
- * a small number of entries is fine, not going to be performance critical.
- * basically we just need to survive
- */
-#define BIO_SPLIT_ENTRIES 2
 mempool_t *bio_split_pool __read_mostly;
-
-struct biovec_slab {
-	int nr_vecs;
-	char *name; 
-	struct kmem_cache *slab;
-};
 
 /*
  * if you change this list, also change bvec_alloc or things will
@@ -60,23 +45,12 @@ static struct biovec_slab bvec_slabs[BIO
 #undef BV
 
 /*
- * bio_set is used to allow other portions of the IO system to
- * allocate their own private memory pools for bio and iovec structures.
- * These memory pools in turn all allocate from the bio_slab
- * and the bvec_slabs[].
- */
-struct bio_set {
-	mempool_t *bio_pool;
-	mempool_t *bvec_pools[BIOVEC_NR_POOLS];
-};
-
-/*
  * fs_bio_set is the bio_set containing bio and iovec memory pools used by
  * IO code that does not need private memory pools.
  */
-static struct bio_set *fs_bio_set;
+struct bio_set *fs_bio_set;
 
-static inline struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs)
+struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs)
 {
 	struct bio_vec *bvl;
 
include/linux/bio.h +29 -0
@@ -333,6 +333,35 @@ extern struct bio *bio_copy_user_iov(str
 				     int, int);
 extern int bio_uncopy_user(struct bio *);
 void zero_fill_bio(struct bio *bio);
+extern struct bio_vec *bvec_alloc_bs(gfp_t, int, unsigned long *, struct bio_set *);
+
+/*
+ * bio_set is used to allow other portions of the IO system to
+ * allocate their own private memory pools for bio and iovec structures.
+ * These memory pools in turn all allocate from the bio_slab
+ * and the bvec_slabs[].
+ */
+#define BIO_POOL_SIZE 2
+#define BIOVEC_NR_POOLS 6
+
+struct bio_set {
+	mempool_t *bio_pool;
+	mempool_t *bvec_pools[BIOVEC_NR_POOLS];
+};
+
+struct biovec_slab {
+	int nr_vecs;
+	char *name;
+	struct kmem_cache *slab;
+};
+
+extern struct bio_set *fs_bio_set;
+
+/*
+ * a small number of entries is fine, not going to be performance critical.
+ * basically we just need to survive
+ */
+#define BIO_SPLIT_ENTRIES 2
 
 #ifdef CONFIG_HIGHMEM
 /*
#2 lore raw

PATCH 1/1 block: Block layer data integrity support

In reply to Martin K. Petersen

Some block devices support verifying the integrity of requests by way of checksums or other protection information that is submitted along with the I/O.

This patch implements support for generating and verifying integrity metadata, as well as correctly merging, splitting and cloning bios and requests that have this extra information attached.

See Documentation/block/data-integrity.txt for more information.

---

13 files changed, 1355 insertions(+), 7 deletions(-)
block/Kconfig          |   12 
block/Makefile         |    1 
block/blk-core.c       |    7 
block/blk-integrity.c  |  382 +++++++++++++++++++++++++
block/blk-merge.c      |    3 
block/blk.h            |    8 
block/elevator.c       |    6 
fs/Makefile            |    1 
fs/bio-integrity.c     |  708 ++++++++++++++++++++++++++++++++++++++++++++++++
fs/bio.c               |   32 +-
include/linux/bio.h    |   94 ++++++
include/linux/blkdev.h |  105 +++++++
include/linux/genhd.h  |    3 
block/Kconfig +12 -0
@@ -81,6 +81,18 @@ config BLK_DEV_BSG
 
 	  If unsure, say N.
 
+config BLK_DEV_INTEGRITY
+	bool "Block layer data integrity support"
+	---help---
+	Some storage devices allow extra information to be
+	stored/retrieved to help protect the data.  The block layer
+	data integrity option provides hooks which can be used by
+	filesystems to ensure better data integrity.
+
+	Say yes here if you have a storage device that provides the
+	T10/SCSI Data Integrity Field or the T13/ATA External Path
+	Protection.  If in doubt, say N.
+
 endif # BLOCK
 
 config BLOCK_COMPAT
block/Makefile +1 -0
@@ -14,3 +14,4 @@ obj-$(CONFIG_IOSCHED_CFQ)	+= cfq-iosched
 
 obj-$(CONFIG_BLK_DEV_IO_TRACE)	+= blktrace.o
 obj-$(CONFIG_BLOCK_COMPAT)	+= compat_ioctl.o
+obj-$(CONFIG_BLK_DEV_INTEGRITY)	+= blk-integrity.o
block/blk-core.c +7 -0
@@ -143,6 +143,10 @@ static void req_bio_endio(struct request
 
 		bio->bi_size -= nbytes;
 		bio->bi_sector += (nbytes >> 9);
+
+		if (bio_integrity(bio))
+			bio_integrity_advance(bio, nbytes);
+
 		if (bio->bi_size == 0)
 			bio_endio(bio, error);
 	} else {
@@ -1381,6 +1385,9 @@ end_io:
 		 */
 		blk_partition_remap(bio);
 
+		if (bio_integrity_enabled(bio) && bio_integrity_prep(bio))
+			goto end_io;
+
 		if (old_sector != -1)
 			blk_add_trace_remap(q, bio, old_dev, bio->bi_sector,
 					    old_sector);
block/blk-integrity.c new file +382 -0

382 lines not on this page · raw message

block/blk-merge.c +3 -0
@@ -441,6 +441,9 @@ static int attempt_merge(struct request_
 	    || next->special)
 		return 0;
 
+	if (blk_integrity_rq(req) != blk_integrity_rq(next))
+		return 0;
+
 	/*
 	 * If we are allowed to merge, then append bio list
 	 * from next to rq and release next. merge_requests_fn
block/blk.h +8 -0
@@ -51,4 +51,12 @@ static inline int queue_congestion_off_t
 	return q->nr_congestion_off;
 }
 
+#if defined(CONFIG_BLK_DEV_INTEGRITY)
+
+#define rq_for_each_integrity_segment(bvl, _rq, _iter)		\
+	__rq_for_each_bio(_iter.bio, _rq)			\
+		bip_for_each_vec(bvl, _iter.bio->bi_integrity, _iter.i)
+
+#endif /* BLK_DEV_INTEGRITY */
+
 #endif
block/elevator.c +6 -0
@@ -84,6 +84,12 @@ int elv_rq_merge_ok(struct request *rq, 
 	 * must be same device and not a special request
 	 */
 	if (rq->rq_disk != bio->bi_bdev->bd_disk || rq->special)
+		return 0;
+
+	/*
+	 * only merge integrity protected bio into ditto rq
+	 */
+	if (bio_integrity(bio) != blk_integrity_rq(rq))
 		return 0;
 
 	if (!elv_iosched_allow_merge(rq, bio))
fs/Makefile +1 -0
@@ -19,6 +19,7 @@ obj-y +=	no-block.o
 obj-y +=	no-block.o
 endif
 
+obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o
 obj-$(CONFIG_INOTIFY)		+= inotify.o
 obj-$(CONFIG_INOTIFY_USER)	+= inotify_user.o
 obj-$(CONFIG_EPOLL)		+= eventpoll.o
fs/bio-integrity.c new file +708 -0

708 lines not on this page · raw message

fs/bio.c +29 -3
@@ -50,6 +50,11 @@ static struct biovec_slab bvec_slabs[BIO
  */
 struct bio_set *fs_bio_set;
 
+inline unsigned int bvec_nr_vecs(unsigned short idx)
+{
+	return bvec_slabs[idx].nr_vecs;
+}
+
 struct bio_vec *bvec_alloc_bs(gfp_t gfp_mask, int nr, unsigned long *idx, struct bio_set *bs)
 {
 	struct bio_vec *bvl;
@@ -90,6 +95,9 @@ void bio_free(struct bio *bio, struct bi
 
 		mempool_free(bio->bi_io_vec, bio_set->bvec_pools[pool_idx]);
 	}
+
+	if (bio_integrity(bio))
+		bio_integrity_free(bio, bio_set);
 
 	mempool_free(bio, bio_set->bio_pool);
 }
@@ -249,9 +257,19 @@ struct bio *bio_clone(struct bio *bio, g
 {
 	struct bio *b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs, fs_bio_set);
 
-	if (b) {
-		b->bi_destructor = bio_fs_destructor;
-		__bio_clone(b, bio);
+	if (!b)
+		return NULL;
+
+	b->bi_destructor = bio_fs_destructor;
+	__bio_clone(b, bio);
+
+	if (bio_integrity(bio)) {
+		int ret;
+
+		ret = bio_integrity_clone(b, bio, fs_bio_set);
+
+		if (ret < 0)
+			return NULL;
 	}
 
 	return b;
@@ -1223,6 +1241,9 @@ struct bio_pair *bio_split(struct bio *b
 	bp->bio1.bi_private = bi;
 	bp->bio2.bi_private = pool;
 
+	if (bio_integrity(bi))
+		bio_integrity_split(bi, bp, first_sectors);
+
 	return bp;
 }
 
@@ -1264,6 +1285,7 @@ void bioset_free(struct bio_set *bs)
 	if (bs->bio_pool)
 		mempool_destroy(bs->bio_pool);
 
+	bioset_integrity_free(bs);
 	biovec_free_pools(bs);
 
 	kfree(bs);
@@ -1278,6 +1300,9 @@ struct bio_set *bioset_create(int bio_po
 
 	bs->bio_pool = mempool_create_slab_pool(bio_pool_size, bio_slab);
 	if (!bs->bio_pool)
+		goto bad;
+
+	if (bioset_integrity_create(bs, bio_pool_size))
 		goto bad;
 
 	if (!biovec_create_pools(bs, bvec_pool_size))
@@ -1306,6 +1331,7 @@ static int __init init_bio(void)
 {
 	bio_slab = KMEM_CACHE(bio, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
 
+	bio_integrity_init_slab();
 	biovec_init_slabs();
 
 	fs_bio_set = bioset_create(BIO_POOL_SIZE, 2);
include/linux/bio.h +90 -4

135 lines not on this page · raw message

include/linux/blkdev.h +105 -0

123 lines not on this page · raw message

include/linux/genhd.h +3 -0
@@ -141,6 +141,9 @@ struct gendisk {
 	struct disk_stats dkstats;
 #endif
 	struct work_struct async_notify;
+#ifdef  CONFIG_BLK_DEV_INTEGRITY
+	struct blk_integrity *integrity;
+#endif
 };
 
 /* 
#3 lore raw

PATCH 1/1 block: Data integrity infrastructure documentation

In reply to Martin K. Petersen

---

2 files changed, 361 insertions(+)

Documentation/ABI/testing/sysfs-block | 34 +++
Documentation/block/data-integrity.txt | 327 ++++++++++++++++++++++++++++++++

Documentation/ABI/testing/sysfs-block +34 -0
@@ -26,3 +26,37 @@ Description:
 		I/O statistics of partition <part>. The format is the
 		same as the above-written /sys/block/<disk>/stat
 		format.
+
+
+What:		/sys/block/<disk>/integrity/format
+Date:		June 2008
+Contact:	Martin K. Petersen <[email protected]>
+Description:
+		Metadata format for integrity capable block device.
+		E.g. T10-DIF-TYPE1-CRC.
+
+
+What:		/sys/block/<disk>/integrity/read_verify
+Date:		June 2008
+Contact:	Martin K. Petersen <[email protected]>
+Description:
+		Indicates whether the block layer should verify the
+		integrity of read requests serviced by devices that
+		support sending integrity metadata.
+
+
+What:		/sys/block/<disk>/integrity/tag_size
+Date:		June 2008
+Contact:	Martin K. Petersen <[email protected]>
+Description:
+		Number of bytes of integrity tag space available per
+		512 bytes of data.
+
+
+What:		/sys/block/<disk>/integrity/write_generate
+Date:		June 2008
+Contact:	Martin K. Petersen <[email protected]>
+Description:
+		Indicates whether the block layer should automatically
+		generate checksums for write requests bound for
+		devices that support receiving integrity metadata.
Documentation/block/data-integrity.txt new file +327 -0

327 lines not on this page · raw message

#4 lore raw
In reply to Martin K. Petersen
Quoted 22 lines · Martin K. Petersen

These patches allow data integrity information (checksum and more) to be attached to I/Os at the block/filesystem layers and transferred through the entire I/O stack all the way to the physical storage device.

The integrity metadata can be generated in close proximity to the original data. Capable host adapters, RAID arrays and physical disks can verify the data integrity and abort I/Os in case of a mismatch.

Changes:

- Add "if in doubt" to Kconfig

- Make blk_rq_count_integrity_sg() more readable

- Queue integrity sysfs fixes

- Fix two struct bi leaks

- Rename struct bip to bio_integrity_payload

Quoted 8 lines

- Introduce bio_integrity_hw_sectors() that converts from block layer (512b) sectors to hardware sectors

- Fix kunmap_atomic() abuse

- Replace ?: constructs with if()

- Add __GFP_NOFAIL to bio_integrity_prep() allocation

Thanks Martin, looks good to me now. Applied to pending 2.6.27 queue.

Signature · 1 line
Jens Axboe