[SCSI] block: fix the partial mappings with struct rq_map_data
FUJITA Tomonori [Thu, 18 Dec 2008 05:49:37 +0000 (14:49 +0900)]
This fixes bio_copy_user_iov to properly handle the partial mappings
with struct rq_map_data (which only sg uses for now but st and osst
will shortly). It adds the offset member to struct rq_map_data and
changes blk_rq_map_user to update it so that bio_copy_user_iov can add
an appropriate page frame via bio_add_pc_page().

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 2990447..c7e55b2 100644 (file)
@@ -150,6 +150,9 @@ int blk_rq_map_user(struct request_queue *q, struct request *rq,
                        bio = rq->bio;
                bytes_read += ret;
                ubuf += ret;
+
+               if (map_data)
+                       map_data->offset += ret;
        }
 
        if (!bio_flagged(bio, BIO_USER_MAPPED))
index 5103855..7d0b3d9 100644 (file)
@@ -1669,6 +1669,7 @@ static int sg_start_req(Sg_request *srp, unsigned char *cmd)
                md->pages = req_schp->pages;
                md->page_order = req_schp->page_order;
                md->nr_entries = req_schp->k_use_sg;
+               md->offset = 0;
        }
 
        if (iov_count)
index 356e742..13be075 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -788,6 +788,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
        int i, ret;
        int nr_pages = 0;
        unsigned int len = 0;
+       unsigned int offset = map_data ? map_data->offset & ~PAGE_MASK : 0;
 
        for (i = 0; i < iov_count; i++) {
                unsigned long uaddr;
@@ -814,12 +815,16 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
        bio->bi_rw |= (!write_to_vm << BIO_RW);
 
        ret = 0;
-       i = 0;
-       if (map_data)
+
+       if (map_data) {
                nr_pages = 1 << map_data->page_order;
+               i = map_data->offset / PAGE_SIZE;
+       }
        while (len) {
                unsigned int bytes = PAGE_SIZE;
 
+               bytes -= offset;
+
                if (bytes > len)
                        bytes = len;
 
@@ -841,10 +846,11 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
                        }
                }
 
-               if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes)
+               if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes)
                        break;
 
                len -= bytes;
+               offset = 0;
        }
 
        if (ret)
index 7035cec..811e534 100644 (file)
@@ -690,6 +690,7 @@ struct rq_map_data {
        struct page **pages;
        int page_order;
        int nr_entries;
+       unsigned long offset;
 };
 
 struct req_iterator {