|
@@ -12,22 +12,29 @@
|
|
#include "blk.h"
|
|
#include "blk.h"
|
|
|
|
|
|
/*
|
|
/*
|
|
- * Append a bio to a passthrough request. Only works can be merged into
|
|
|
|
- * the request based on the driver constraints.
|
|
|
|
|
|
+ * Append a bio to a passthrough request. Only works if the bio can be merged
|
|
|
|
+ * into the request based on the driver constraints.
|
|
*/
|
|
*/
|
|
-int blk_rq_append_bio(struct request *rq, struct bio *bio)
|
|
|
|
|
|
+int blk_rq_append_bio(struct request *rq, struct bio **bio)
|
|
{
|
|
{
|
|
- blk_queue_bounce(rq->q, &bio);
|
|
|
|
|
|
+ struct bio *orig_bio = *bio;
|
|
|
|
+
|
|
|
|
+ blk_queue_bounce(rq->q, bio);
|
|
|
|
|
|
if (!rq->bio) {
|
|
if (!rq->bio) {
|
|
- blk_rq_bio_prep(rq->q, rq, bio);
|
|
|
|
|
|
+ blk_rq_bio_prep(rq->q, rq, *bio);
|
|
} else {
|
|
} else {
|
|
- if (!ll_back_merge_fn(rq->q, rq, bio))
|
|
|
|
|
|
+ if (!ll_back_merge_fn(rq->q, rq, *bio)) {
|
|
|
|
+ if (orig_bio != *bio) {
|
|
|
|
+ bio_put(*bio);
|
|
|
|
+ *bio = orig_bio;
|
|
|
|
+ }
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
+ }
|
|
|
|
|
|
- rq->biotail->bi_next = bio;
|
|
|
|
- rq->biotail = bio;
|
|
|
|
- rq->__data_len += bio->bi_iter.bi_size;
|
|
|
|
|
|
+ rq->biotail->bi_next = *bio;
|
|
|
|
+ rq->biotail = *bio;
|
|
|
|
+ rq->__data_len += (*bio)->bi_iter.bi_size;
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -73,14 +80,12 @@ static int __blk_rq_map_user_iov(struct request *rq,
|
|
* We link the bounce buffer in and could have to traverse it
|
|
* We link the bounce buffer in and could have to traverse it
|
|
* later so we have to get a ref to prevent it from being freed
|
|
* later so we have to get a ref to prevent it from being freed
|
|
*/
|
|
*/
|
|
- ret = blk_rq_append_bio(rq, bio);
|
|
|
|
- bio_get(bio);
|
|
|
|
|
|
+ ret = blk_rq_append_bio(rq, &bio);
|
|
if (ret) {
|
|
if (ret) {
|
|
- bio_endio(bio);
|
|
|
|
__blk_rq_unmap_user(orig_bio);
|
|
__blk_rq_unmap_user(orig_bio);
|
|
- bio_put(bio);
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
+ bio_get(bio);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -213,7 +218,7 @@ int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf,
|
|
int reading = rq_data_dir(rq) == READ;
|
|
int reading = rq_data_dir(rq) == READ;
|
|
unsigned long addr = (unsigned long) kbuf;
|
|
unsigned long addr = (unsigned long) kbuf;
|
|
int do_copy = 0;
|
|
int do_copy = 0;
|
|
- struct bio *bio;
|
|
|
|
|
|
+ struct bio *bio, *orig_bio;
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
if (len > (queue_max_hw_sectors(q) << 9))
|
|
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,
|
|
if (do_copy)
|
|
if (do_copy)
|
|
rq->rq_flags |= RQF_COPY_USER;
|
|
rq->rq_flags |= RQF_COPY_USER;
|
|
|
|
|
|
- ret = blk_rq_append_bio(rq, bio);
|
|
|
|
|
|
+ orig_bio = bio;
|
|
|
|
+ ret = blk_rq_append_bio(rq, &bio);
|
|
if (unlikely(ret)) {
|
|
if (unlikely(ret)) {
|
|
/* request is too big */
|
|
/* request is too big */
|
|
- bio_put(bio);
|
|
|
|
|
|
+ bio_put(orig_bio);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|