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 <k...@daterainc.com>

Tested-by: Richard W.M. Jones <rjo...@redhat.com>

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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to