--- /dev/null
+Subject: Block integrity update
+From: Martin K. Petersen <martin.petersen@oracle.com>
+Date: Mon Dec 8 09:36:35 2008 +0100:
+References: FATE#304345
+
+This patch series contains block layer integrity updates for 2.6.28.
+
+There are a few fixes to the core bits, including a switch from
+block_device to gendisk in the integrity compare function. I also had
+to add a helper to access a gendisk's integrity profile. This is used
+by MD.
+
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Hannes Reinecke <hare@suse.de>
+
+---
+ block/blk-integrity.c | 30 +++++++++++++++---------------
+ fs/bio-integrity.c | 3 ++-
+ fs/bio.c | 36 ++++++++++++++++++++++++++++++++++++
+ include/linux/bio.h | 2 ++
+ include/linux/blkdev.h | 8 +++++++-
+ 5 files changed, 62 insertions(+), 17 deletions(-)
+
+--- a/block/blk-integrity.c
++++ b/block/blk-integrity.c
+@@ -108,51 +108,51 @@ new_segment:
+ EXPORT_SYMBOL(blk_rq_map_integrity_sg);
+
+ /**
+- * blk_integrity_compare - Compare integrity profile of two block devices
+- * @bd1: Device to compare
+- * @bd2: Device to compare
++ * blk_integrity_compare - Compare integrity profile of two disks
++ * @gd1: Disk to compare
++ * @gd2: Disk to compare
+ *
+ * Description: Meta-devices like DM and MD need to verify that all
+ * sub-devices use the same integrity format before advertising to
+ * upper layers that they can send/receive integrity metadata. This
+- * function can be used to check whether two block devices have
++ * function can be used to check whether two gendisk devices have
+ * compatible integrity formats.
+ */
+-int blk_integrity_compare(struct block_device *bd1, struct block_device *bd2)
++int blk_integrity_compare(struct gendisk *gd1, struct gendisk *gd2)
+ {
+- struct blk_integrity *b1 = bd1->bd_disk->integrity;
+- struct blk_integrity *b2 = bd2->bd_disk->integrity;
++ struct blk_integrity *b1 = gd1->integrity;
++ struct blk_integrity *b2 = gd2->integrity;
+
+- BUG_ON(bd1->bd_disk == NULL);
+- BUG_ON(bd2->bd_disk == NULL);
++ if (!b1 && !b2)
++ return 0;
+
+ if (!b1 || !b2)
+- return 0;
++ return -1;
+
+ if (b1->sector_size != b2->sector_size) {
+ printk(KERN_ERR "%s: %s/%s sector sz %u != %u\n", __func__,
+- bd1->bd_disk->disk_name, bd2->bd_disk->disk_name,
++ gd1->disk_name, gd2->disk_name,
+ b1->sector_size, b2->sector_size);
+ return -1;
+ }
+
+ if (b1->tuple_size != b2->tuple_size) {
+ printk(KERN_ERR "%s: %s/%s tuple sz %u != %u\n", __func__,
+- bd1->bd_disk->disk_name, bd2->bd_disk->disk_name,
++ gd1->disk_name, gd2->disk_name,
+ b1->tuple_size, b2->tuple_size);
+ return -1;
+ }
+
+ if (b1->tag_size && b2->tag_size && (b1->tag_size != b2->tag_size)) {
+ printk(KERN_ERR "%s: %s/%s tag sz %u != %u\n", __func__,
+- bd1->bd_disk->disk_name, bd2->bd_disk->disk_name,
++ gd1->disk_name, gd2->disk_name,
+ b1->tag_size, b2->tag_size);
+ return -1;
+ }
+
+ if (strcmp(b1->name, b2->name)) {
+ printk(KERN_ERR "%s: %s/%s type %s != %s\n", __func__,
+- bd1->bd_disk->disk_name, bd2->bd_disk->disk_name,
++ gd1->disk_name, gd2->disk_name,
+ b1->name, b2->name);
+ return -1;
+ }
+@@ -375,7 +375,7 @@ void blk_integrity_unregister(struct gen
+
+ kobject_uevent(&bi->kobj, KOBJ_REMOVE);
+ kobject_del(&bi->kobj);
+- kobject_put(&disk->dev.kobj);
+ kmem_cache_free(integrity_cachep, bi);
++ disk->integrity = NULL;
+ }
+ EXPORT_SYMBOL(blk_integrity_unregister);
+--- a/fs/bio.c
++++ b/fs/bio.c
+@@ -1274,6 +1274,42 @@ struct bio_pair *bio_split(struct bio *b
+ return bp;
+ }
+
++/**
++ * bio_sector_offset - Find hardware sector offset in bio
++ * @bio: bio to inspect
++ * @index: bio_vec index
++ * @offset: offset in bv_page
++ *
++ * Return the number of hardware sectors between beginning of bio
++ * and an end point indicated by a bio_vec index and an offset
++ * within that vector's page.
++ */
++sector_t bio_sector_offset(struct bio *bio, unsigned short index,
++ unsigned int offset)
++{
++ unsigned int sector_sz = queue_hardsect_size(bio->bi_bdev->bd_disk->queue);
++ struct bio_vec *bv;
++ sector_t sectors;
++ int i;
++
++ sectors = 0;
++
++ if (index >= bio->bi_idx)
++ index = bio->bi_vcnt - 1;
++
++ __bio_for_each_segment(bv, bio, i, 0) {
++ if (i == index) {
++ if (offset > bv->bv_offset)
++ sectors += (offset - bv->bv_offset) / sector_sz;
++ break;
++ }
++
++ sectors += bv->bv_len / sector_sz;
++ }
++
++ return sectors;
++}
++EXPORT_SYMBOL(bio_sector_offset);
+
+ /*
+ * create memory pools for biovec's in a bio_set.
+--- a/fs/bio-integrity.c
++++ b/fs/bio-integrity.c
+@@ -107,7 +107,8 @@ void bio_integrity_free(struct bio *bio,
+ BUG_ON(bip == NULL);
+
+ /* A cloned bio doesn't own the integrity metadata */
+- if (!bio_flagged(bio, BIO_CLONED) && bip->bip_buf != NULL)
++ if (!bio_flagged(bio, BIO_CLONED) && !bio_flagged(bio, BIO_FS_INTEGRITY)
++ && bip->bip_buf != NULL)
+ kfree(bip->bip_buf);
+
+ mempool_free(bip->bip_vec, bs->bvec_pools[bip->bip_pool]);
+--- a/include/linux/bio.h
++++ b/include/linux/bio.h
+@@ -115,6 +115,7 @@ struct bio {
+ #define BIO_USER_MAPPED 6 /* contains user pages */
+ #define BIO_EOPNOTSUPP 7 /* not supported */
+ #define BIO_CPU_AFFINE 8 /* complete bio on same CPU as submitted */
++#define BIO_FS_INTEGRITY 10 /* fs owns integrity data, not block layer */
+ #define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag)))
+
+ /*
+@@ -331,6 +332,7 @@ extern int bio_add_page(struct bio *, st
+ extern int bio_add_pc_page(struct request_queue *, struct bio *, struct page *,
+ unsigned int, unsigned int);
+ extern int bio_get_nr_vecs(struct block_device *);
++extern sector_t bio_sector_offset(struct bio *, unsigned short, unsigned int);
+ extern struct bio *bio_map_user(struct request_queue *, struct block_device *,
+ unsigned long, unsigned int, int);
+ struct sg_iovec;
+--- a/include/linux/blkdev.h
++++ b/include/linux/blkdev.h
+@@ -980,7 +980,7 @@ struct blk_integrity {
+
+ extern int blk_integrity_register(struct gendisk *, struct blk_integrity *);
+ extern void blk_integrity_unregister(struct gendisk *);
+-extern int blk_integrity_compare(struct block_device *, struct block_device *);
++extern int blk_integrity_compare(struct gendisk *, struct gendisk *);
+ extern int blk_rq_map_integrity_sg(struct request *, struct scatterlist *);
+ extern int blk_rq_count_integrity_sg(struct request *);
+
+@@ -997,6 +997,11 @@ static inline struct blk_integrity *bdev
+ return bdev->bd_disk->integrity;
+ }
+
++static inline struct blk_integrity *blk_get_integrity(struct gendisk *disk)
++{
++ return disk->integrity;
++}
++
+ static inline unsigned int bdev_get_tag_size(struct block_device *bdev)
+ {
+ struct blk_integrity *bi = bdev_get_integrity(bdev);
+@@ -1039,6 +1044,7 @@ static inline int blk_integrity_rq(struc
+ #define blk_rq_count_integrity_sg(a) (0)
+ #define blk_rq_map_integrity_sg(a, b) (0)
+ #define bdev_get_integrity(a) (0)
++#define blk_get_integrity(a) (0)
+ #define bdev_get_tag_size(a) (0)
+ #define blk_integrity_compare(a, b) (0)
+ #define blk_integrity_register(a, b) (0)