diff options
| author | Jens Axboe <axboe@kernel.dk> | 2017-12-18 02:40:44 -0500 |
|---|---|---|
| committer | Jens Axboe <axboe@kernel.dk> | 2017-12-18 15:55:43 -0500 |
| commit | 0abc2a10389f0c9070f76ca906c7382788036b93 (patch) | |
| tree | 9d1f1b48a3acbff7ed8b1549ebb1cffe3b407b81 | |
| parent | 14cb0dc6479dc5ebc63b3a459a5d89a2f1b39fed (diff) | |
block: fix blk_rq_append_bio
Commit caa4b02476e3(blk-map: call blk_queue_bounce from blk_rq_append_bio)
moves blk_queue_bounce() into blk_rq_append_bio(), but don't consider
the fact that the bounced bio becomes invisible to caller since the
parameter type is 'struct bio *'. Make it a pointer to a pointer to
a bio, so the caller sees the right bio also after a bounce.
Fixes: caa4b02476e3 ("blk-map: call blk_queue_bounce from blk_rq_append_bio")
Cc: Christoph Hellwig <hch@lst.de>
Reported-by: Michele Ballabio <barra_cuda@katamail.com>
(handling failure of blk_rq_append_bio(), only call bio_get() after
blk_rq_append_bio() returns OK)
Tested-by: Michele Ballabio <barra_cuda@katamail.com>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
| -rw-r--r-- | block/blk-map.c | 38 | ||||
| -rw-r--r-- | drivers/scsi/osd/osd_initiator.c | 4 | ||||
| -rw-r--r-- | drivers/target/target_core_pscsi.c | 4 | ||||
| -rw-r--r-- | include/linux/blkdev.h | 2 |
4 files changed, 28 insertions, 20 deletions
diff --git a/block/blk-map.c b/block/blk-map.c index b21f8e86f120..d3a94719f03f 100644 --- a/block/blk-map.c +++ b/block/blk-map.c | |||
| @@ -12,22 +12,29 @@ | |||
| 12 | #include "blk.h" | 12 | #include "blk.h" |
| 13 | 13 | ||
| 14 | /* | 14 | /* |
| 15 | * Append a bio to a passthrough request. Only works can be merged into | 15 | * Append a bio to a passthrough request. Only works if the bio can be merged |
| 16 | * the request based on the driver constraints. | 16 | * into the request based on the driver constraints. |
| 17 | */ | 17 | */ |
| 18 | int blk_rq_append_bio(struct request *rq, struct bio *bio) | 18 | int blk_rq_append_bio(struct request *rq, struct bio **bio) |
| 19 | { | 19 | { |
| 20 | blk_queue_bounce(rq->q, &bio); | 20 | struct bio *orig_bio = *bio; |
| 21 | |||
| 22 | blk_queue_bounce(rq->q, bio); | ||
| 21 | 23 | ||
| 22 | if (!rq->bio) { | 24 | if (!rq->bio) { |
| 23 | blk_rq_bio_prep(rq->q, rq, bio); | 25 | blk_rq_bio_prep(rq->q, rq, *bio); |
| 24 | } else { | 26 | } else { |
| 25 | if (!ll_back_merge_fn(rq->q, rq, bio)) | 27 | if (!ll_back_merge_fn(rq->q, rq, *bio)) { |
| 28 | if (orig_bio != *bio) { | ||
| 29 | bio_put(*bio); | ||
| 30 | *bio = orig_bio; | ||
| 31 | } | ||
| 26 | return -EINVAL; | 32 | return -EINVAL; |
| 33 | } | ||
| 27 | 34 | ||
| 28 | rq->biotail->bi_next = bio; | 35 | rq->biotail->bi_next = *bio; |
| 29 | rq->biotail = bio; | 36 | rq->biotail = *bio; |
| 30 | rq->__data_len += bio->bi_iter.bi_size; | 37 | rq->__data_len += (*bio)->bi_iter.bi_size; |
| 31 | } | 38 | } |
| 32 | 39 | ||
| 33 | return 0; | 40 | return 0; |
| @@ -73,14 +80,12 @@ static int __blk_rq_map_user_iov(struct request *rq, | |||
| 73 | * We link the bounce buffer in and could have to traverse it | 80 | * We link the bounce buffer in and could have to traverse it |
| 74 | * later so we have to get a ref to prevent it from being freed | 81 | * later so we have to get a ref to prevent it from being freed |
| 75 | */ | 82 | */ |
| 76 | ret = blk_rq_append_bio(rq, bio); | 83 | ret = blk_rq_append_bio(rq, &bio); |
| 77 | bio_get(bio); | ||
| 78 | if (ret) { | 84 | if (ret) { |
| 79 | bio_endio(bio); | ||
| 80 | __blk_rq_unmap_user(orig_bio); | 85 | __blk_rq_unmap_user(orig_bio); |
| 81 | bio_put(bio); | ||
| 82 | return ret; | 86 | return ret; |
| 83 | } | 87 | } |
| 88 | bio_get(bio); | ||
| 84 | 89 | ||
| 85 | return 0; | 90 | return 0; |
| 86 | } | 91 | } |
| @@ -213,7 +218,7 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, | |||
| 213 | int reading = rq_data_dir(rq) == READ; | 218 | int reading = rq_data_dir(rq) == READ; |
| 214 | unsigned long addr = (unsigned long) kbuf; | 219 | unsigned long addr = (unsigned long) kbuf; |
| 215 | int do_copy = 0; | 220 | int do_copy = 0; |
| 216 | struct bio *bio; | 221 | struct bio *bio, *orig_bio; |
| 217 | int ret; | 222 | int ret; |
| 218 | 223 | ||
| 219 | if (len > (queue_max_hw_sectors(q) << 9)) | 224 | if (len > (queue_max_hw_sectors(q) << 9)) |
| @@ -236,10 +241,11 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, | |||
| 236 | if (do_copy) | 241 | if (do_copy) |
| 237 | rq->rq_flags |= RQF_COPY_USER; | 242 | rq->rq_flags |= RQF_COPY_USER; |
| 238 | 243 | ||
| 239 | ret = blk_rq_append_bio(rq, bio); | 244 | orig_bio = bio; |
| 245 | ret = blk_rq_append_bio(rq, &bio); | ||
| 240 | if (unlikely(ret)) { | 246 | if (unlikely(ret)) { |
| 241 | /* request is too big */ | 247 | /* request is too big */ |
| 242 | bio_put(bio); | 248 | bio_put(orig_bio); |
| 243 | return ret; | 249 | return ret; |
| 244 | } | 250 | } |
| 245 | 251 | ||
diff --git a/drivers/scsi/osd/osd_initiator.c b/drivers/scsi/osd/osd_initiator.c index a4f28b7e4c65..e18877177f1b 100644 --- a/drivers/scsi/osd/osd_initiator.c +++ b/drivers/scsi/osd/osd_initiator.c | |||
| @@ -1576,7 +1576,9 @@ static struct request *_make_request(struct request_queue *q, bool has_write, | |||
| 1576 | return req; | 1576 | return req; |
| 1577 | 1577 | ||
| 1578 | for_each_bio(bio) { | 1578 | for_each_bio(bio) { |
| 1579 | ret = blk_rq_append_bio(req, bio); | 1579 | struct bio *bounce_bio = bio; |
| 1580 | |||
| 1581 | ret = blk_rq_append_bio(req, &bounce_bio); | ||
| 1580 | if (ret) | 1582 | if (ret) |
| 1581 | return ERR_PTR(ret); | 1583 | return ERR_PTR(ret); |
| 1582 | } | 1584 | } |
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 7c69b4a9694d..0d99b242e82e 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c | |||
| @@ -920,7 +920,7 @@ pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | |||
| 920 | " %d i: %d bio: %p, allocating another" | 920 | " %d i: %d bio: %p, allocating another" |
| 921 | " bio\n", bio->bi_vcnt, i, bio); | 921 | " bio\n", bio->bi_vcnt, i, bio); |
| 922 | 922 | ||
| 923 | rc = blk_rq_append_bio(req, bio); | 923 | rc = blk_rq_append_bio(req, &bio); |
| 924 | if (rc) { | 924 | if (rc) { |
| 925 | pr_err("pSCSI: failed to append bio\n"); | 925 | pr_err("pSCSI: failed to append bio\n"); |
| 926 | goto fail; | 926 | goto fail; |
| @@ -938,7 +938,7 @@ pscsi_map_sg(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | |||
| 938 | } | 938 | } |
| 939 | 939 | ||
| 940 | if (bio) { | 940 | if (bio) { |
| 941 | rc = blk_rq_append_bio(req, bio); | 941 | rc = blk_rq_append_bio(req, &bio); |
| 942 | if (rc) { | 942 | if (rc) { |
| 943 | pr_err("pSCSI: failed to append bio\n"); | 943 | pr_err("pSCSI: failed to append bio\n"); |
| 944 | goto fail; | 944 | goto fail; |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index abd06f540863..100d0df38026 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
| @@ -965,7 +965,7 @@ extern int blk_rq_prep_clone(struct request *rq, struct request *rq_src, | |||
| 965 | extern void blk_rq_unprep_clone(struct request *rq); | 965 | extern void blk_rq_unprep_clone(struct request *rq); |
| 966 | extern blk_status_t blk_insert_cloned_request(struct request_queue *q, | 966 | extern blk_status_t blk_insert_cloned_request(struct request_queue *q, |
| 967 | struct request *rq); | 967 | struct request *rq); |
| 968 | extern int blk_rq_append_bio(struct request *rq, struct bio *bio); | 968 | extern int blk_rq_append_bio(struct request *rq, struct bio **bio); |
| 969 | extern void blk_delay_queue(struct request_queue *, unsigned long); | 969 | extern void blk_delay_queue(struct request_queue *, unsigned long); |
| 970 | extern void blk_queue_split(struct request_queue *, struct bio **); | 970 | extern void blk_queue_split(struct request_queue *, struct bio **); |
| 971 | extern void blk_recount_segments(struct request_queue *, struct bio *); | 971 | extern void blk_recount_segments(struct request_queue *, struct bio *); |
