diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2009-11-26 01:24:13 +0100 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2009-12-10 15:54:13 +0100 |
commit | c982c368bb90adbd312faa05d0cfd842e9ab45a7 (patch) | |
tree | e5620557e3972c130e4b4b652d036a378d0f977b /drivers/scsi/st.h | |
parent | [SCSI] be2iscsi: Adding support for various Async messages from chip (diff) | |
download | linux-c982c368bb90adbd312faa05d0cfd842e9ab45a7.tar.xz linux-c982c368bb90adbd312faa05d0cfd842e9ab45a7.zip |
[SCSI] st: fix mdata->page_order handling
dio transfer always resets mdata->page_order to zero. It breaks
high-order pages previously allocated for non-dio transfer.
This patches adds reserved_page_order to st_buffer structure to save
page order for non-dio transfer.
http://bugzilla.kernel.org/show_bug.cgi?id=14563
When enlarge_buffer() allocates 524288 from 0, st uses six-order page
allocation. So mdata->page_order is 6 and frp_seg is 2.
After that, if st uses dio, sgl_map_user_pages() sets
mdata->page_order to 0 for st_do_scsi(). After that, when we call
normalize_buffer(), it frees only free frp_seg * PAGE_SIZE (2 * 4096)
though we should free frp_seg * PAGE_SIZE << 6 (2 * 4096 << 6). So we
see buffer_size is set to 516096 (524288 - 8192).
Reported-by: Joachim Breuer <linux-kernel@jmbreuer.net>
Tested-by: Joachim Breuer <linux-kernel@jmbreuer.net>
Acked-by: Kai Makisara <kai.makisara@kolumbus.fi>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Cc: stable@kernel.org
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/st.h')
-rw-r--r-- | drivers/scsi/st.h | 1 |
1 files changed, 1 insertions, 0 deletions
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 544dc6b1f548..f91a67c6d968 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -46,6 +46,7 @@ struct st_buffer { struct st_request *last_SRpnt; struct st_cmdstatus cmdstat; struct page **reserved_pages; + int reserved_page_order; struct page **mapped_pages; struct rq_map_data map_data; unsigned char *b_data; |