diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2008-12-18 00:49:36 -0500 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2009-01-02 12:09:41 -0500 |
commit | e623ddb4e940b266adc77ba1cc28a3554aa90e79 (patch) | |
tree | 62c245b32720573d97718795b0c8165cad967b05 /fs/bio.c | |
parent | 4f10aae0d1a285df6b16bf6ca5abd366140fd371 (diff) |
[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>
Diffstat (limited to 'fs/bio.c')
-rw-r--r-- | fs/bio.c | 26 |
1 files changed, 14 insertions, 12 deletions
@@ -815,28 +815,30 @@ struct bio *bio_copy_user_iov(struct request_queue *q, | |||
815 | 815 | ||
816 | ret = 0; | 816 | ret = 0; |
817 | i = 0; | 817 | i = 0; |
818 | if (map_data) | ||
819 | nr_pages = 1 << map_data->page_order; | ||
818 | while (len) { | 820 | while (len) { |
819 | unsigned int bytes; | 821 | unsigned int bytes = PAGE_SIZE; |
820 | |||
821 | if (map_data) | ||
822 | bytes = 1U << (PAGE_SHIFT + map_data->page_order); | ||
823 | else | ||
824 | bytes = PAGE_SIZE; | ||
825 | 822 | ||
826 | if (bytes > len) | 823 | if (bytes > len) |
827 | bytes = len; | 824 | bytes = len; |
828 | 825 | ||
829 | if (map_data) { | 826 | if (map_data) { |
830 | if (i == map_data->nr_entries) { | 827 | if (i == map_data->nr_entries * nr_pages) { |
831 | ret = -ENOMEM; | 828 | ret = -ENOMEM; |
832 | break; | 829 | break; |
833 | } | 830 | } |
834 | page = map_data->pages[i++]; | 831 | |
835 | } else | 832 | page = map_data->pages[i / nr_pages]; |
833 | page += (i % nr_pages); | ||
834 | |||
835 | i++; | ||
836 | } else { | ||
836 | page = alloc_page(q->bounce_gfp | gfp_mask); | 837 | page = alloc_page(q->bounce_gfp | gfp_mask); |
837 | if (!page) { | 838 | if (!page) { |
838 | ret = -ENOMEM; | 839 | ret = -ENOMEM; |
839 | break; | 840 | break; |
841 | } | ||
840 | } | 842 | } |
841 | 843 | ||
842 | if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes) | 844 | if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes) |