Re: [PATCH] block: Fix cloning of discard/write same bios

From: Richard W.M. Jones
Date: Tue Feb 11 2014 - 07:22:37 EST


On Mon, Feb 10, 2014 at 05:45:50PM -0800, Kent Overstreet wrote:
> Immutable biovecs changed the way bio segments are treated in such a way that
> bio_for_each_segment() cannot now do what we want for discard/write same bios,
> since bi_size means something completely different for them.
>
> Fortunately discard and write same bios never have more than a single biovec, so
> bio_for_each_segment() is unnecessary and not terribly meaningful for them, but
> we still have to special case them in a few places.
>
> Signed-off-by: Kent Overstreet <kmo@xxxxxxxxxxxxx>

Tested-by: Richard W.M. Jones <rjones@xxxxxxxxxx>

I have confirmed this fixes the bug described here:

https://bugzilla.redhat.com/show_bug.cgi?id=1061339

Rich.

> ---
> fs/bio.c | 15 ++++++++++-----
> include/linux/bio.h | 11 +++++++++++
> 2 files changed, 21 insertions(+), 5 deletions(-)
>
> diff --git a/fs/bio.c b/fs/bio.c
> index 75c49a3822..8754e7b6eb 100644
> --- a/fs/bio.c
> +++ b/fs/bio.c
> @@ -611,7 +611,6 @@ EXPORT_SYMBOL(bio_clone_fast);
> struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask,
> struct bio_set *bs)
> {
> - unsigned nr_iovecs = 0;
> struct bvec_iter iter;
> struct bio_vec bv;
> struct bio *bio;
> @@ -638,10 +637,7 @@ struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask,
> * __bio_clone_fast() anyways.
> */
>
> - bio_for_each_segment(bv, bio_src, iter)
> - nr_iovecs++;
> -
> - bio = bio_alloc_bioset(gfp_mask, nr_iovecs, bs);
> + bio = bio_alloc_bioset(gfp_mask, bio_segments(bio_src), bs);
> if (!bio)
> return NULL;
>
> @@ -650,9 +646,18 @@ struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask,
> bio->bi_iter.bi_sector = bio_src->bi_iter.bi_sector;
> bio->bi_iter.bi_size = bio_src->bi_iter.bi_size;
>
> + if (bio->bi_rw & REQ_DISCARD)
> + goto integrity_clone;
> +
> + if (bio->bi_rw & REQ_WRITE_SAME) {
> + bio->bi_io_vec[bio->bi_vcnt++] = bio_src->bi_io_vec[0];
> + goto integrity_clone;
> + }
> +
> bio_for_each_segment(bv, bio_src, iter)
> bio->bi_io_vec[bio->bi_vcnt++] = bv;
>
> +integrity_clone:
> if (bio_integrity(bio_src)) {
> int ret;
>
> diff --git a/include/linux/bio.h b/include/linux/bio.h
> index 70654521da..05d2a0392f 100644
> --- a/include/linux/bio.h
> +++ b/include/linux/bio.h
> @@ -250,6 +250,17 @@ static inline unsigned bio_segments(struct bio *bio)
> struct bio_vec bv;
> struct bvec_iter iter;
>
> + /*
> + * We special case discard/write same, because they interpret bi_size
> + * differently:
> + */
> +
> + if (bio->bi_rw & REQ_DISCARD)
> + return 1;
> +
> + if (bio->bi_rw & REQ_WRITE_SAME)
> + return 1;
> +
> bio_for_each_segment(bv, bio, iter)
> segs++;
>
> --
> 1.8.5.3

--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming blog: http://rwmj.wordpress.com
Fedora now supports 80 OCaml packages (the OPEN alternative to F#)
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/