diff --git a/block/blk-map.c b/block/blk-map.c index c7e55b23a2bc..f103729b462f 100644 --- a/block/blk-map.c +++ b/block/blk-map.c @@ -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, struct rq_map_data *map_data, void __user *ubuf, - unsigned int len, int null_mapped, gfp_t gfp_mask) + unsigned int len, gfp_t gfp_mask) { unsigned long uaddr; struct bio *bio, *orig_bio; @@ -63,7 +63,7 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq, if (IS_ERR(bio)) return PTR_ERR(bio); - if (null_mapped) + if (map_data && map_data->null_mapped) bio->bi_flags |= (1 << BIO_NULL_MAPPED); orig_bio = bio; @@ -114,17 +114,15 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq, { unsigned long bytes_read = 0; struct bio *bio = NULL; - int ret, null_mapped = 0; + int ret; if (len > (q->max_hw_sectors << 9)) return -EINVAL; if (!len) return -EINVAL; - if (!ubuf) { - if (!map_data || rq_data_dir(rq) != READ) - return -EINVAL; - null_mapped = 1; - } + + if (!ubuf && (!map_data || !map_data->null_mapped)) + return -EINVAL; while (bytes_read != len) { unsigned long map_len, end, start; @@ -143,7 +141,7 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq, map_len -= PAGE_SIZE; ret = __blk_rq_map_user(q, rq, map_data, ubuf, map_len, - null_mapped, gfp_mask); + gfp_mask); if (ret < 0) goto unmap_rq; if (!bio) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 7d0b3d9ee43b..8f0bd3f7a59f 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1670,6 +1670,7 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd) md->page_order = req_schp->page_order; md->nr_entries = req_schp->k_use_sg; md->offset = 0; + md->null_mapped = hp->dxferp ? 0 : 1; } if (iov_count) diff --git a/fs/bio.c b/fs/bio.c index 13be075806b6..062299acbccd 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -859,7 +859,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q, /* * success */ - if (!write_to_vm) { + if (!write_to_vm && (!map_data || !map_data->null_mapped)) { ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 0); if (ret) goto cleanup; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 811e5342c452..044467ef7b11 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -691,6 +691,7 @@ struct rq_map_data { int page_order; int nr_entries; unsigned long offset; + int null_mapped; }; struct req_iterator {