[SCSI] block: make blk_rq_map_user take a NULL user-space buffer for WRITE
FUJITA Tomonori [Thu, 18 Dec 2008 05:49:38 +0000 (14:49 +0900)]
The commit 818827669d85b84241696ffef2de485db46b0b5e (block: make
blk_rq_map_user take a NULL user-space buffer) extended
blk_rq_map_user to accept a NULL user-space buffer with a READ
command. It was necessary to convert sg to use the block layer mapping
API.

This patch extends blk_rq_map_user again for a WRITE command. It is
necessary to convert st and osst drivers to use the block layer
apping API.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Acked-by: Jens Axboe <jens.axboe@oracle.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>

block/blk-map.c
drivers/scsi/sg.c
fs/bio.c
include/linux/blkdev.h

index c7e55b2..f103729 100644 (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,
                             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)
index 7d0b3d9..8f0bd3f 100644 (file)
@@ -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)
index 13be075..062299a 100644 (file)
--- 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;
index 811e534..044467e 100644 (file)
@@ -691,6 +691,7 @@ struct rq_map_data {
        int page_order;
        int nr_entries;
        unsigned long offset;
+       int null_mapped;
 };
 
 struct req_iterator {