summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2008-12-18 06:49:36 +0100
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2009-01-02 18:09:41 +0100
commite623ddb4e940b266adc77ba1cc28a3554aa90e79 (patch)
tree62c245b32720573d97718795b0c8165cad967b05
parent[SCSI] ibmvscsi: Make max_requests module parameter more accurate (diff)
downloadlinux-e623ddb4e940b266adc77ba1cc28a3554aa90e79.tar.xz
linux-e623ddb4e940b266adc77ba1cc28a3554aa90e79.zip
[SCSI] block: fix bio_add_page misuse with rq_map_data
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>
-rw-r--r--fs/bio.c26
1 files changed, 14 insertions, 12 deletions
diff --git a/fs/bio.c b/fs/bio.c
index 711cee103602..356e7423b923 100644
--- 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)