diff options
author | Martin K. Petersen <martin.petersen@oracle.com> | 2015-07-22 07:57:12 -0400 |
---|---|---|
committer | Luis Henriques <luis.henriques@canonical.com> | 2015-08-11 09:57:45 +0100 |
commit | 83d6450b0520c77b683398111a94c73654c00497 (patch) | |
tree | 691944483bfd0513d27f9af641d7f48363bf74be /block | |
parent | 2157661d38cd2bbf98e48ce12b84b8a362f1c710 (diff) | |
download | linux-stable-83d6450b0520c77b683398111a94c73654c00497.tar.gz linux-stable-83d6450b0520c77b683398111a94c73654c00497.tar.bz2 linux-stable-83d6450b0520c77b683398111a94c73654c00497.zip |
block: Do a full clone when splitting discard bios
commit f3f5da624e0a891c34d8cd513c57f1d9b0c7dadc upstream.
This fixes a data corruption bug when using discard on top of MD linear,
raid0 and raid10 personalities.
Commit 20d0189b1012 "block: Introduce new bio_split()" permits sharing
the bio_vec between the two resulting bios. That is fine for read/write
requests where the bio_vec is immutable. For discards, however, we need
to be able to attach a payload and update the bio_vec so the page can
get mapped to a scatterlist entry. Therefore the bio_vec can not be
shared when splitting discards and we must do a full clone.
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Reported-by: Seunguk Shin <seunguk.shin@samsung.com>
Tested-by: Seunguk Shin <seunguk.shin@samsung.com>
Cc: Seunguk Shin <seunguk.shin@samsung.com>
Cc: Jens Axboe <axboe@fb.com>
Cc: Kent Overstreet <kent.overstreet@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@fb.com>
Signed-off-by: Luis Henriques <luis.henriques@canonical.com>
Diffstat (limited to 'block')
-rw-r--r-- | block/bio.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/block/bio.c b/block/bio.c index 0ec61c9e536c..6467e6afdcd9 100644 --- a/block/bio.c +++ b/block/bio.c @@ -1820,8 +1820,9 @@ EXPORT_SYMBOL(bio_endio_nodec); * Allocates and returns a new bio which represents @sectors from the start of * @bio, and updates @bio to represent the remaining sectors. * - * The newly allocated bio will point to @bio's bi_io_vec; it is the caller's - * responsibility to ensure that @bio is not freed before the split. + * Unless this is a discard request the newly allocated bio will point + * to @bio's bi_io_vec; it is the caller's responsibility to ensure that + * @bio is not freed before the split. */ struct bio *bio_split(struct bio *bio, int sectors, gfp_t gfp, struct bio_set *bs) @@ -1831,7 +1832,15 @@ struct bio *bio_split(struct bio *bio, int sectors, BUG_ON(sectors <= 0); BUG_ON(sectors >= bio_sectors(bio)); - split = bio_clone_fast(bio, gfp, bs); + /* + * Discards need a mutable bio_vec to accommodate the payload + * required by the DSM TRIM and UNMAP commands. + */ + if (bio->bi_rw & REQ_DISCARD) + split = bio_clone_bioset(bio, gfp, bs); + else + split = bio_clone_fast(bio, gfp, bs); + if (!split) return NULL; |