Commit 8e5cfc45 authored by Jens Axboe's avatar Jens Axboe

[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: default avatarJens Axboe <jens.axboe@oracle.com>
parent 48785bb9
...@@ -2405,6 +2405,7 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, ...@@ -2405,6 +2405,7 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf,
unsigned long len) unsigned long len)
{ {
unsigned long bytes_read = 0; unsigned long bytes_read = 0;
struct bio *bio = NULL;
int ret; int ret;
if (len > (q->max_hw_sectors << 9)) 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,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); ret = __blk_rq_map_user(q, rq, ubuf, map_len);
if (ret < 0) if (ret < 0)
goto unmap_rq; goto unmap_rq;
if (!bio)
bio = rq->bio;
bytes_read += ret; bytes_read += ret;
ubuf += ret; ubuf += ret;
} }
...@@ -2438,7 +2441,7 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, ...@@ -2438,7 +2441,7 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf,
rq->buffer = rq->data = NULL; rq->buffer = rq->data = NULL;
return 0; return 0;
unmap_rq: unmap_rq:
blk_rq_unmap_user(rq); blk_rq_unmap_user(bio);
return ret; return ret;
} }
...@@ -2495,29 +2498,30 @@ EXPORT_SYMBOL(blk_rq_map_user_iov); ...@@ -2495,29 +2498,30 @@ EXPORT_SYMBOL(blk_rq_map_user_iov);
/** /**
* blk_rq_unmap_user - unmap a request with user data * blk_rq_unmap_user - unmap a request with user data
* @rq: rq to be unmapped * @bio: start of bio list
* *
* Description: * Description:
* Unmap a rq previously mapped by blk_rq_map_user(). * Unmap a rq previously mapped by blk_rq_map_user(). The caller must
* rq->bio must be set to the original head of the request. * 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; int ret = 0, ret2;
while ((bio = rq->bio)) { while (bio) {
if (bio_flagged(bio, BIO_BOUNCED)) mapped_bio = bio;
if (unlikely(bio_flagged(bio, BIO_BOUNCED)))
mapped_bio = bio->bi_private; mapped_bio = bio->bi_private;
else
mapped_bio = bio;
ret2 = __blk_rq_unmap_user(mapped_bio); ret2 = __blk_rq_unmap_user(mapped_bio);
if (ret2 && !ret) if (ret2 && !ret)
ret = ret2; ret = ret2;
rq->bio = bio->bi_next; mapped_bio = bio;
bio_put(bio); bio = bio->bi_next;
bio_put(mapped_bio);
} }
return ret; return ret;
......
...@@ -333,8 +333,7 @@ static int sg_io(struct file *file, request_queue_t *q, ...@@ -333,8 +333,7 @@ static int sg_io(struct file *file, request_queue_t *q,
hdr->sb_len_wr = len; hdr->sb_len_wr = len;
} }
rq->bio = bio; if (blk_rq_unmap_user(bio))
if (blk_rq_unmap_user(rq))
ret = -EFAULT; ret = -EFAULT;
/* may not have succeeded, but output values written to control /* may not have succeeded, but output values written to control
......
...@@ -2139,8 +2139,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, ...@@ -2139,8 +2139,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf,
cdi->last_sense = s->sense_key; cdi->last_sense = s->sense_key;
} }
rq->bio = bio; if (blk_rq_unmap_user(bio))
if (blk_rq_unmap_user(rq))
ret = -EFAULT; ret = -EFAULT;
if (ret) if (ret)
......
...@@ -672,7 +672,7 @@ extern void __blk_stop_queue(request_queue_t *q); ...@@ -672,7 +672,7 @@ extern void __blk_stop_queue(request_queue_t *q);
extern void blk_run_queue(request_queue_t *); extern void blk_run_queue(request_queue_t *);
extern void blk_start_queueing(request_queue_t *); extern void blk_start_queueing(request_queue_t *);
extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned long); extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned long);
extern int blk_rq_unmap_user(struct request *); extern int blk_rq_unmap_user(struct bio *);
extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, gfp_t); extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, gfp_t);
extern int blk_rq_map_user_iov(request_queue_t *, struct request *, extern int blk_rq_map_user_iov(request_queue_t *, struct request *,
struct sg_iovec *, int, unsigned int); struct sg_iovec *, int, unsigned int);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment