diff options
-rw-r--r-- | block/ll_rw_blk.c | 28 | ||||
-rw-r--r-- | block/scsi_ioctl.c | 3 | ||||
-rw-r--r-- | drivers/cdrom/cdrom.c | 3 | ||||
-rw-r--r-- | include/linux/blkdev.h | 2 |
4 files changed, 19 insertions, 17 deletions
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c index a66ec30855d8..e07c079e07e6 100644 --- a/block/ll_rw_blk.c +++ b/block/ll_rw_blk.c | |||
@@ -2405,6 +2405,7 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, | |||
2405 | unsigned long len) | 2405 | unsigned long len) |
2406 | { | 2406 | { |
2407 | unsigned long bytes_read = 0; | 2407 | unsigned long bytes_read = 0; |
2408 | struct bio *bio = NULL; | ||
2408 | int ret; | 2409 | int ret; |
2409 | 2410 | ||
2410 | if (len > (q->max_hw_sectors << 9)) | 2411 | if (len > (q->max_hw_sectors << 9)) |
@@ -2431,6 +2432,8 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, | |||
2431 | ret = __blk_rq_map_user(q, rq, ubuf, map_len); | 2432 | ret = __blk_rq_map_user(q, rq, ubuf, map_len); |
2432 | if (ret < 0) | 2433 | if (ret < 0) |
2433 | goto unmap_rq; | 2434 | goto unmap_rq; |
2435 | if (!bio) | ||
2436 | bio = rq->bio; | ||
2434 | bytes_read += ret; | 2437 | bytes_read += ret; |
2435 | ubuf += ret; | 2438 | ubuf += ret; |
2436 | } | 2439 | } |
@@ -2438,7 +2441,7 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, | |||
2438 | rq->buffer = rq->data = NULL; | 2441 | rq->buffer = rq->data = NULL; |
2439 | return 0; | 2442 | return 0; |
2440 | unmap_rq: | 2443 | unmap_rq: |
2441 | blk_rq_unmap_user(rq); | 2444 | blk_rq_unmap_user(bio); |
2442 | return ret; | 2445 | return ret; |
2443 | } | 2446 | } |
2444 | 2447 | ||
@@ -2495,29 +2498,30 @@ EXPORT_SYMBOL(blk_rq_map_user_iov); | |||
2495 | 2498 | ||
2496 | /** | 2499 | /** |
2497 | * blk_rq_unmap_user - unmap a request with user data | 2500 | * blk_rq_unmap_user - unmap a request with user data |
2498 | * @rq: rq to be unmapped | 2501 | * @bio: start of bio list |
2499 | * | 2502 | * |
2500 | * Description: | 2503 | * Description: |
2501 | * Unmap a rq previously mapped by blk_rq_map_user(). | 2504 | * Unmap a rq previously mapped by blk_rq_map_user(). The caller must |
2502 | * rq->bio must be set to the original head of the request. | 2505 | * supply the original rq->bio from the blk_rq_map_user() return, since |
2506 | * the io completion may have changed rq->bio. | ||
2503 | */ | 2507 | */ |
2504 | int blk_rq_unmap_user(struct request *rq) | 2508 | int blk_rq_unmap_user(struct bio *bio) |
2505 | { | 2509 | { |
2506 | struct bio *bio, *mapped_bio; | 2510 | struct bio *mapped_bio; |
2507 | int ret = 0, ret2; | 2511 | int ret = 0, ret2; |
2508 | 2512 | ||
2509 | while ((bio = rq->bio)) { | 2513 | while (bio) { |
2510 | if (bio_flagged(bio, BIO_BOUNCED)) | 2514 | mapped_bio = bio; |
2515 | if (unlikely(bio_flagged(bio, BIO_BOUNCED))) | ||
2511 | mapped_bio = bio->bi_private; | 2516 | mapped_bio = bio->bi_private; |
2512 | else | ||
2513 | mapped_bio = bio; | ||
2514 | 2517 | ||
2515 | ret2 = __blk_rq_unmap_user(mapped_bio); | 2518 | ret2 = __blk_rq_unmap_user(mapped_bio); |
2516 | if (ret2 && !ret) | 2519 | if (ret2 && !ret) |
2517 | ret = ret2; | 2520 | ret = ret2; |
2518 | 2521 | ||
2519 | rq->bio = bio->bi_next; | 2522 | mapped_bio = bio; |
2520 | bio_put(bio); | 2523 | bio = bio->bi_next; |
2524 | bio_put(mapped_bio); | ||
2521 | } | 2525 | } |
2522 | 2526 | ||
2523 | return ret; | 2527 | return ret; |
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index f322b6a441d8..2528a0c0dec8 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c | |||
@@ -333,8 +333,7 @@ static int sg_io(struct file *file, request_queue_t *q, | |||
333 | hdr->sb_len_wr = len; | 333 | hdr->sb_len_wr = len; |
334 | } | 334 | } |
335 | 335 | ||
336 | rq->bio = bio; | 336 | if (blk_rq_unmap_user(bio)) |
337 | if (blk_rq_unmap_user(rq)) | ||
338 | ret = -EFAULT; | 337 | ret = -EFAULT; |
339 | 338 | ||
340 | /* may not have succeeded, but output values written to control | 339 | /* may not have succeeded, but output values written to control |
diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index e4a2f8f3a1d7..66d028d30439 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c | |||
@@ -2139,8 +2139,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, | |||
2139 | cdi->last_sense = s->sense_key; | 2139 | cdi->last_sense = s->sense_key; |
2140 | } | 2140 | } |
2141 | 2141 | ||
2142 | rq->bio = bio; | 2142 | if (blk_rq_unmap_user(bio)) |
2143 | if (blk_rq_unmap_user(rq)) | ||
2144 | ret = -EFAULT; | 2143 | ret = -EFAULT; |
2145 | 2144 | ||
2146 | if (ret) | 2145 | if (ret) |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 0fa33017ec02..36a6eacefe20 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
@@ -672,7 +672,7 @@ extern void __blk_stop_queue(request_queue_t *q); | |||
672 | extern void blk_run_queue(request_queue_t *); | 672 | extern void blk_run_queue(request_queue_t *); |
673 | extern void blk_start_queueing(request_queue_t *); | 673 | extern void blk_start_queueing(request_queue_t *); |
674 | extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned long); | 674 | extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned long); |
675 | extern int blk_rq_unmap_user(struct request *); | 675 | extern int blk_rq_unmap_user(struct bio *); |
676 | extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, gfp_t); | 676 | extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, gfp_t); |
677 | extern int blk_rq_map_user_iov(request_queue_t *, struct request *, | 677 | extern int blk_rq_map_user_iov(request_queue_t *, struct request *, |
678 | struct sg_iovec *, int, unsigned int); | 678 | struct sg_iovec *, int, unsigned int); |