block: make blk_rq_map_user take a NULL user-space buffer

This patch changes blk_rq_map_user to accept a NULL user-space buffer
with a READ command if rq_map_data is not NULL. Thus a caller can pass
page frames to lk_rq_map_user to just set up a request and bios with
page frames propely. bio_uncopy_user (called via blk_rq_unmap_user)
doesn't copy data to user space with such request.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
This commit is contained in:
FUJITA Tomonori 2008-09-02 16:20:19 +09:00 committed by Jens Axboe
parent 839e96afba
commit 818827669d
3 changed files with 17 additions and 8 deletions

View File

@ -42,7 +42,7 @@ static int __blk_rq_unmap_user(struct bio *bio)
static int __blk_rq_map_user(struct request_queue *q, struct request *rq, static int __blk_rq_map_user(struct request_queue *q, struct request *rq,
struct rq_map_data *map_data, void __user *ubuf, struct rq_map_data *map_data, void __user *ubuf,
unsigned int len, gfp_t gfp_mask) unsigned int len, int null_mapped, gfp_t gfp_mask)
{ {
unsigned long uaddr; unsigned long uaddr;
struct bio *bio, *orig_bio; struct bio *bio, *orig_bio;
@ -63,6 +63,9 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq,
if (IS_ERR(bio)) if (IS_ERR(bio))
return PTR_ERR(bio); return PTR_ERR(bio);
if (null_mapped)
bio->bi_flags |= (1 << BIO_NULL_MAPPED);
orig_bio = bio; orig_bio = bio;
blk_queue_bounce(q, &bio); blk_queue_bounce(q, &bio);
@ -111,12 +114,17 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq,
{ {
unsigned long bytes_read = 0; unsigned long bytes_read = 0;
struct bio *bio = NULL; struct bio *bio = NULL;
int ret; int ret, null_mapped = 0;
if (len > (q->max_hw_sectors << 9)) if (len > (q->max_hw_sectors << 9))
return -EINVAL; return -EINVAL;
if (!len || !ubuf) if (!len)
return -EINVAL; return -EINVAL;
if (!ubuf) {
if (!map_data || rq_data_dir(rq) != READ)
return -EINVAL;
null_mapped = 1;
}
while (bytes_read != len) { while (bytes_read != len) {
unsigned long map_len, end, start; unsigned long map_len, end, start;
@ -135,7 +143,7 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq,
map_len -= PAGE_SIZE; map_len -= PAGE_SIZE;
ret = __blk_rq_map_user(q, rq, map_data, ubuf, map_len, ret = __blk_rq_map_user(q, rq, map_data, ubuf, map_len,
gfp_mask); null_mapped, gfp_mask);
if (ret < 0) if (ret < 0)
goto unmap_rq; goto unmap_rq;
if (!bio) if (!bio)

View File

@ -547,11 +547,11 @@ static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
int bio_uncopy_user(struct bio *bio) int bio_uncopy_user(struct bio *bio)
{ {
struct bio_map_data *bmd = bio->bi_private; struct bio_map_data *bmd = bio->bi_private;
int ret; int ret = 0;
ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs, bmd->nr_sgvecs, 1,
bmd->is_our_pages);
if (!bio_flagged(bio, BIO_NULL_MAPPED))
ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs,
bmd->nr_sgvecs, 1, bmd->is_our_pages);
bio_free_map_data(bmd); bio_free_map_data(bmd);
bio_put(bio); bio_put(bio);
return ret; return ret;

View File

@ -108,6 +108,7 @@ struct bio {
#define BIO_USER_MAPPED 6 /* contains user pages */ #define BIO_USER_MAPPED 6 /* contains user pages */
#define BIO_EOPNOTSUPP 7 /* not supported */ #define BIO_EOPNOTSUPP 7 /* not supported */
#define BIO_CPU_AFFINE 8 /* complete bio on same CPU as submitted */ #define BIO_CPU_AFFINE 8 /* complete bio on same CPU as submitted */
#define BIO_NULL_MAPPED 9 /* contains invalid user pages */
#define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag))) #define bio_flagged(bio, flag) ((bio)->bi_flags & (1 << (flag)))
/* /*