summaryrefslogtreecommitdiffstats
path: root/kernel/block/bio.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/block/bio.c')
-rw-r--r--kernel/block/bio.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/kernel/block/bio.c b/kernel/block/bio.c
index f66a4eae1..4441522ca 100644
--- a/kernel/block/bio.c
+++ b/kernel/block/bio.c
@@ -1814,8 +1814,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)
@@ -1825,7 +1826,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;