mirror of
https://github.com/torvalds/linux.git
synced 2024-11-10 22:21:40 +00:00
block: Fix cloning of discard/write same bios
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@daterainc.com> Tested-by: Richard W.M. Jones <rjones@redhat.com> Signed-off-by: Jens Axboe <axboe@fb.com>
This commit is contained in:
parent
9d4cb8e3a5
commit
8423ae3d7a
15
fs/bio.c
15
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 *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask,
|
||||||
struct bio_set *bs)
|
struct bio_set *bs)
|
||||||
{
|
{
|
||||||
unsigned nr_iovecs = 0;
|
|
||||||
struct bvec_iter iter;
|
struct bvec_iter iter;
|
||||||
struct bio_vec bv;
|
struct bio_vec bv;
|
||||||
struct bio *bio;
|
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_clone_fast() anyways.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bio_for_each_segment(bv, bio_src, iter)
|
bio = bio_alloc_bioset(gfp_mask, bio_segments(bio_src), bs);
|
||||||
nr_iovecs++;
|
|
||||||
|
|
||||||
bio = bio_alloc_bioset(gfp_mask, nr_iovecs, bs);
|
|
||||||
if (!bio)
|
if (!bio)
|
||||||
return NULL;
|
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_sector = bio_src->bi_iter.bi_sector;
|
||||||
bio->bi_iter.bi_size = bio_src->bi_iter.bi_size;
|
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_for_each_segment(bv, bio_src, iter)
|
||||||
bio->bi_io_vec[bio->bi_vcnt++] = bv;
|
bio->bi_io_vec[bio->bi_vcnt++] = bv;
|
||||||
|
|
||||||
|
integrity_clone:
|
||||||
if (bio_integrity(bio_src)) {
|
if (bio_integrity(bio_src)) {
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -250,6 +250,17 @@ static inline unsigned bio_segments(struct bio *bio)
|
|||||||
struct bio_vec bv;
|
struct bio_vec bv;
|
||||||
struct bvec_iter iter;
|
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)
|
bio_for_each_segment(bv, bio, iter)
|
||||||
segs++;
|
segs++;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user