Blob Blame History Raw
From: Hannes Reinecke <hare@suse.de>
Date: Tue, 9 Apr 2019 09:24:45 +0200
Subject: [PATCH] block: kABI fixes for bio_rewind_iter() removal
References: bsc#1131673
Patch-Mainline: never, SLE15 kABI fix

To stay kABI compliant we simply should not remove bio_rewind_iter(),
but rather only remove it's usage in bio-integrity.c.
As the bio_integrity_payload structure is pretty densely packed we
cannot modify the structure, so I opted for having an internal
structure in bio-integrity.c which holds the modifications, and
use outcasts to get from the original payload to the internal one.

Signed-off-by: Hannes Reinecke <hare@suse.com>
---
 block/bio-integrity.c | 33 +++++++++++++++++++++++----------
 block/bio.c           |  1 +
 include/linux/bio.h   | 22 ++++++++++++++++++----
 include/linux/bvec.h  |  3 +++
 4 files changed, 45 insertions(+), 14 deletions(-)

diff --git a/block/bio-integrity.c b/block/bio-integrity.c
index b2a3374da689..9562ac6efe6c 100644
--- a/block/bio-integrity.c
+++ b/block/bio-integrity.c
@@ -33,6 +33,11 @@
 static struct kmem_cache *bip_slab;
 static struct workqueue_struct *kintegrityd_wq;
 
+struct __bio_integrity_payload {
+	struct bvec_iter	bio_iter;	/* for rewinding parent bio */
+	struct bio_integrity_payload bip_orig;
+};
+
 void blk_flush_integrity(void)
 {
 	flush_workqueue(kintegrityd_wq);
@@ -52,23 +57,25 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
 						  gfp_t gfp_mask,
 						  unsigned int nr_vecs)
 {
+	struct __bio_integrity_payload *__bip;
 	struct bio_integrity_payload *bip;
 	struct bio_set *bs = bio->bi_pool;
 	unsigned inline_vecs;
 
 	if (!bs || !bs->bio_integrity_pool) {
-		bip = kmalloc(sizeof(struct bio_integrity_payload) +
+		__bip = kmalloc(sizeof(struct __bio_integrity_payload) +
 			      sizeof(struct bio_vec) * nr_vecs, gfp_mask);
 		inline_vecs = nr_vecs;
 	} else {
-		bip = mempool_alloc(bs->bio_integrity_pool, gfp_mask);
+		__bip = mempool_alloc(bs->bio_integrity_pool, gfp_mask);
 		inline_vecs = BIP_INLINE_VECS;
 	}
 
-	if (unlikely(!bip))
+	if (unlikely(!__bip))
 		return ERR_PTR(-ENOMEM);
 
-	memset(bip, 0, sizeof(*bip));
+	memset(__bip, 0, sizeof(*__bip));
+	bip = &__bip->bip_orig;
 
 	if (nr_vecs > inline_vecs) {
 		unsigned long idx = 0;
@@ -90,7 +97,7 @@ struct bio_integrity_payload *bio_integrity_alloc(struct bio *bio,
 
 	return bip;
 err:
-	mempool_free(bip, bs->bio_integrity_pool);
+	mempool_free(__bip, bs->bio_integrity_pool);
 	return ERR_PTR(-ENOMEM);
 }
 EXPORT_SYMBOL(bio_integrity_alloc);
@@ -105,6 +112,8 @@ EXPORT_SYMBOL(bio_integrity_alloc);
 static void bio_integrity_free(struct bio *bio)
 {
 	struct bio_integrity_payload *bip = bio_integrity(bio);
+	struct __bio_integrity_payload *__bip =
+		container_of(bip, struct __bio_integrity_payload, bip_orig);
 	struct bio_set *bs = bio->bi_pool;
 
 	if (bip->bip_flags & BIP_BLOCK_INTEGRITY)
@@ -114,9 +123,9 @@ static void bio_integrity_free(struct bio *bio)
 	if (bs && bs->bio_integrity_pool) {
 		bvec_free(bs->bvec_integrity_pool, bip->bip_vec, bip->bip_slab);
 
-		mempool_free(bip, bs->bio_integrity_pool);
+		mempool_free(__bip, bs->bio_integrity_pool);
 	} else {
-		kfree(bip);
+		kfree(__bip);
 	}
 
 	bio->bi_integrity = NULL;
@@ -307,7 +316,9 @@ bool bio_integrity_prep(struct bio *bio)
 		bio_integrity_process(bio, &bio->bi_iter,
 				      bi->profile->generate_fn);
 	} else {
-		bip->bio_iter = bio->bi_iter;
+		struct __bio_integrity_payload *__bip =
+			container_of(bip, struct __bio_integrity_payload, bip_orig);
+		__bip->bio_iter = bio->bi_iter;
 	}
 	return true;
 
@@ -331,6 +342,8 @@ static void bio_integrity_verify_fn(struct work_struct *work)
 {
 	struct bio_integrity_payload *bip =
 		container_of(work, struct bio_integrity_payload, bip_work);
+	struct __bio_integrity_payload *__bip =
+		container_of(bip, struct __bio_integrity_payload, bip_orig);
 	struct bio *bio = bip->bip_bio;
 	struct blk_integrity *bi = blk_get_integrity(bio->bi_disk);
 
@@ -339,7 +352,7 @@ static void bio_integrity_verify_fn(struct work_struct *work)
 	 * during split and completion, we need to rewind iterator to
 	 * it's original position.
 	 */
-	bio->bi_status = bio_integrity_process(bio, &bip->bio_iter,
+	bio->bi_status = bio_integrity_process(bio, &__bip->bio_iter,
 						bi->profile->verify_fn);
 	bio_integrity_free(bio);
 	bio_endio(bio);
@@ -478,7 +491,7 @@ void __init bio_integrity_init(void)
 		panic("Failed to create kintegrityd\n");
 
 	bip_slab = kmem_cache_create("bio_integrity_payload",
-				     sizeof(struct bio_integrity_payload) +
+				     sizeof(struct __bio_integrity_payload) +
 				     sizeof(struct bio_vec) * BIP_INLINE_VECS,
 				     0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL);
 }
diff --git a/block/bio.c b/block/bio.c
index 25cfc5528bae..336eb9eab377 100644
--- a/block/bio.c
+++ b/block/bio.c
@@ -1921,6 +1921,7 @@ struct bio *bio_split(struct bio *bio, int sectors,
 		bio_integrity_trim(split);
 
 	bio_advance(bio, split->bi_iter.bi_size);
+	bio->bi_iter.bi_done = 0;
 
 	if (bio_flagged(bio, BIO_TRACE_COMPLETION))
 		bio_set_flag(split, BIO_TRACE_COMPLETION);
diff --git a/include/linux/bio.h b/include/linux/bio.h
index c8f3140f8ec0..44b4947890cf 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -165,11 +165,27 @@ static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter,
 {
 	iter->bi_sector += bytes >> 9;
 
-	if (bio_no_advance_iter(bio))
+	if (bio_no_advance_iter(bio)) {
 		iter->bi_size -= bytes;
-	else
+		iter->bi_done += bytes;
+	} else {
 		bvec_iter_advance(bio->bi_io_vec, iter, bytes);
 		/* TODO: It is reasonable to complete bio with error here. */
+	}
+}
+
+static inline bool bio_rewind_iter(struct bio *bio, struct bvec_iter *iter,
+		unsigned int bytes)
+{
+	iter->bi_sector -= bytes >> 9;
+
+	if (bio_no_advance_iter(bio)) {
+		iter->bi_size += bytes;
+		iter->bi_done -= bytes;
+		return true;
+	}
+
+	return bvec_iter_rewind(bio->bi_io_vec, iter, bytes);
 }
 
 #define __bio_for_each_segment(bvl, bio, iter, start)			\
@@ -309,8 +325,6 @@ struct bio_integrity_payload {
 	unsigned short		bip_max_vcnt;	/* integrity bio_vec slots */
 	unsigned short		bip_flags;	/* control flags */
 
-	struct bvec_iter	bio_iter;	/* for rewinding parent bio */
-
 	struct work_struct	bip_work;	/* I/O completion */
 
 	struct bio_vec		*bip_vec;
diff --git a/include/linux/bvec.h b/include/linux/bvec.h
index b81a0c3b6acb..ec8a4d7af6bd 100644
--- a/include/linux/bvec.h
+++ b/include/linux/bvec.h
@@ -40,6 +40,8 @@ struct bvec_iter {
 
 	unsigned int		bi_idx;		/* current index into bvl_vec */
 
+	unsigned int            bi_done;	/* number of bytes completed */
+
 	unsigned int            bi_bvec_done;	/* number of bytes completed in
 						   current bvec */
 };
@@ -83,6 +85,7 @@ static inline bool bvec_iter_advance(const struct bio_vec *bv,
 		bytes -= len;
 		iter->bi_size -= len;
 		iter->bi_bvec_done += len;
+		iter->bi_done += len;
 
 		if (iter->bi_bvec_done == __bvec_iter_bvec(bv, *iter)->bv_len) {
 			iter->bi_bvec_done = 0;
-- 
2.16.4