From 8e5cfc45e7527eb5c8a9a22d56a7b9227e7c0913 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 19 Dec 2006 11:12:46 +0100 Subject: [PATCH] Fixup blk_rq_unmap_user() API The blk_rq_unmap_user() API is not very nice. It expects the caller to know that rq->bio has to be reset to the original bio, and it will silently do nothing if that is not done. Instead make it explicit that we need to pass in the first bio, by expecting a bio argument. Signed-off-by: Jens Axboe --- block/ll_rw_blk.c | 28 ++++++++++++++++------------ block/scsi_ioctl.c | 3 +-- 2 files changed, 17 insertions(+), 14 deletions(-) (limited to 'block') 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, unsigned long len) { unsigned long bytes_read = 0; + struct bio *bio = NULL; int ret; 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, ret = __blk_rq_map_user(q, rq, ubuf, map_len); if (ret < 0) goto unmap_rq; + if (!bio) + bio = rq->bio; bytes_read += ret; ubuf += ret; } @@ -2438,7 +2441,7 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, rq->buffer = rq->data = NULL; return 0; unmap_rq: - blk_rq_unmap_user(rq); + blk_rq_unmap_user(bio); return ret; } @@ -2495,29 +2498,30 @@ EXPORT_SYMBOL(blk_rq_map_user_iov); /** * blk_rq_unmap_user - unmap a request with user data - * @rq: rq to be unmapped + * @bio: start of bio list * * Description: - * Unmap a rq previously mapped by blk_rq_map_user(). - * rq->bio must be set to the original head of the request. + * Unmap a rq previously mapped by blk_rq_map_user(). The caller must + * supply the original rq->bio from the blk_rq_map_user() return, since + * the io completion may have changed rq->bio. */ -int blk_rq_unmap_user(struct request *rq) +int blk_rq_unmap_user(struct bio *bio) { - struct bio *bio, *mapped_bio; + struct bio *mapped_bio; int ret = 0, ret2; - while ((bio = rq->bio)) { - if (bio_flagged(bio, BIO_BOUNCED)) + while (bio) { + mapped_bio = bio; + if (unlikely(bio_flagged(bio, BIO_BOUNCED))) mapped_bio = bio->bi_private; - else - mapped_bio = bio; ret2 = __blk_rq_unmap_user(mapped_bio); if (ret2 && !ret) ret = ret2; - rq->bio = bio->bi_next; - bio_put(bio); + mapped_bio = bio; + bio = bio->bi_next; + bio_put(mapped_bio); } 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, hdr->sb_len_wr = len; } - rq->bio = bio; - if (blk_rq_unmap_user(rq)) + if (blk_rq_unmap_user(bio)) ret = -EFAULT; /* may not have succeeded, but output values written to control -- cgit v1.2.2