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