[SCSI] block: fix bio_add_page misuse with rq_map_data
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Thu, 18 Dec 2008 05:49:36 +0000 (14:49 +0900)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Fri, 2 Jan 2009 17:09:41 +0000 (11:09 -0600)
This fixes bio_add_page misuse in bio_copy_user_iov with rq_map_data,
which only sg uses now.

rq_map_data carries page frames for bio_add_pc_page. bio_copy_user_iov
uses bio_add_pc_page with a larger size than PAGE_SIZE. It's clearly
wrong.

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>
fs/bio.c

index 711cee1..356e742 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -815,28 +815,30 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
 
        ret = 0;
        i = 0;
+       if (map_data)
+               nr_pages = 1 << map_data->page_order;
        while (len) {
-               unsigned int bytes;
-
-               if (map_data)
-                       bytes = 1U << (PAGE_SHIFT + map_data->page_order);
-               else
-                       bytes = PAGE_SIZE;
+               unsigned int bytes = PAGE_SIZE;
 
                if (bytes > len)
                        bytes = len;
 
                if (map_data) {
-                       if (i == map_data->nr_entries) {
+                       if (i == map_data->nr_entries * nr_pages) {
                                ret = -ENOMEM;
                                break;
                        }
-                       page = map_data->pages[i++];
-               } else
+
+                       page = map_data->pages[i / nr_pages];
+                       page += (i % nr_pages);
+
+                       i++;
+               } else {
                        page = alloc_page(q->bounce_gfp | gfp_mask);
-               if (!page) {
-                       ret = -ENOMEM;
-                       break;
+                       if (!page) {
+                               ret = -ENOMEM;
+                               break;
+                       }
                }
 
                if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes)