Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 81882766 authored by FUJITA Tomonori's avatar FUJITA Tomonori Committed by Jens Axboe
Browse files

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: default avatarFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: default avatarJens Axboe <jens.axboe@oracle.com>
parent 839e96af
Loading
Loading
Loading
Loading
+12 −4
Original line number Original line Diff line number Diff line
@@ -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;
	if (!ubuf) {
		if (!map_data || rq_data_dir(rq) != READ)
			return -EINVAL;
			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)
+4 −4
Original line number Original line Diff line number Diff line
@@ -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;
+1 −0
Original line number Original line Diff line number Diff line
@@ -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)))


/*
/*