diff options
Diffstat (limited to 'drivers/scsi/st.c')
-rw-r--r-- | drivers/scsi/st.c | 78 |
1 files changed, 43 insertions, 35 deletions
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index ce1fd3ab243..1cfd217f890 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -3753,8 +3753,9 @@ static struct st_buffer * else priority = GFP_KERNEL; - i = sizeof(struct st_buffer) + (max_sg - 1) * sizeof(struct scatterlist) + - max_sg * sizeof(struct st_buf_fragment); + i = sizeof(struct st_buffer) + + (max_sg - 1) * sizeof(struct scatterlist); + tb = kzalloc(i, priority); if (!tb) { printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n"); @@ -3762,7 +3763,6 @@ static struct st_buffer * } tb->frp_segs = tb->orig_frp_segs = 0; tb->use_sg = max_sg; - tb->frp = (struct st_buf_fragment *)(&(tb->sg[0]) + max_sg); tb->dma = need_dma; tb->buffer_size = got; @@ -3799,9 +3799,12 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm if (need_dma) priority |= GFP_DMA; + if (STbuffer->cleared) + priority |= __GFP_ZERO; + if (STbuffer->frp_segs) { - b_size = STbuffer->frp[0].length; - order = get_order(b_size); + order = STbuffer->map_data.page_order; + b_size = PAGE_SIZE << order; } else { for (b_size = PAGE_SIZE, order = 0; order <= 6 && b_size < new_size; order++, b_size *= 2) @@ -3810,22 +3813,22 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm for (segs = STbuffer->frp_segs, got = STbuffer->buffer_size; segs < max_segs && got < new_size;) { - STbuffer->frp[segs].page = alloc_pages(priority, order); - if (STbuffer->frp[segs].page == NULL) { + struct page *page; + + page = alloc_pages(priority, order); + if (!page) { DEB(STbuffer->buffer_size = got); normalize_buffer(STbuffer); return 0; } - STbuffer->frp[segs].length = b_size; + STbuffer->frp_segs += 1; got += b_size; STbuffer->buffer_size = got; - if (STbuffer->cleared) - memset(page_address(STbuffer->frp[segs].page), 0, b_size); - STbuffer->reserved_pages[segs] = STbuffer->frp[segs].page; + STbuffer->reserved_pages[segs] = page; segs++; } - STbuffer->b_data = page_address(STbuffer->frp[0].page); + STbuffer->b_data = page_address(STbuffer->reserved_pages[0]); STbuffer->map_data.page_order = order; return 1; @@ -3838,7 +3841,8 @@ static void clear_buffer(struct st_buffer * st_bp) int i; for (i=0; i < st_bp->frp_segs; i++) - memset(page_address(st_bp->frp[i].page), 0, st_bp->frp[i].length); + memset(page_address(st_bp->reserved_pages[i]), 0, + PAGE_SIZE << st_bp->map_data.page_order); st_bp->cleared = 1; } @@ -3846,12 +3850,11 @@ static void clear_buffer(struct st_buffer * st_bp) /* Release the extra buffer */ static void normalize_buffer(struct st_buffer * STbuffer) { - int i, order; + int i, order = STbuffer->map_data.page_order; for (i = STbuffer->orig_frp_segs; i < STbuffer->frp_segs; i++) { - order = get_order(STbuffer->frp[i].length); - __free_pages(STbuffer->frp[i].page, order); - STbuffer->buffer_size -= STbuffer->frp[i].length; + __free_pages(STbuffer->reserved_pages[i], order); + STbuffer->buffer_size -= (PAGE_SIZE << order); } STbuffer->frp_segs = STbuffer->orig_frp_segs; STbuffer->frp_sg_current = 0; @@ -3866,18 +3869,19 @@ static void normalize_buffer(struct st_buffer * STbuffer) static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count) { int i, cnt, res, offset; + int length = PAGE_SIZE << st_bp->map_data.page_order; for (i = 0, offset = st_bp->buffer_bytes; - i < st_bp->frp_segs && offset >= st_bp->frp[i].length; i++) - offset -= st_bp->frp[i].length; + i < st_bp->frp_segs && offset >= length; i++) + offset -= length; if (i == st_bp->frp_segs) { /* Should never happen */ printk(KERN_WARNING "st: append_to_buffer offset overflow.\n"); return (-EIO); } for (; i < st_bp->frp_segs && do_count > 0; i++) { - cnt = st_bp->frp[i].length - offset < do_count ? - st_bp->frp[i].length - offset : do_count; - res = copy_from_user(page_address(st_bp->frp[i].page) + offset, ubp, cnt); + struct page *page = st_bp->reserved_pages[i]; + cnt = length - offset < do_count ? length - offset : do_count; + res = copy_from_user(page_address(page) + offset, ubp, cnt); if (res) return (-EFAULT); do_count -= cnt; @@ -3897,18 +3901,19 @@ static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, in static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count) { int i, cnt, res, offset; + int length = PAGE_SIZE << st_bp->map_data.page_order; for (i = 0, offset = st_bp->read_pointer; - i < st_bp->frp_segs && offset >= st_bp->frp[i].length; i++) - offset -= st_bp->frp[i].length; + i < st_bp->frp_segs && offset >= length; i++) + offset -= length; if (i == st_bp->frp_segs) { /* Should never happen */ printk(KERN_WARNING "st: from_buffer offset overflow.\n"); return (-EIO); } for (; i < st_bp->frp_segs && do_count > 0; i++) { - cnt = st_bp->frp[i].length - offset < do_count ? - st_bp->frp[i].length - offset : do_count; - res = copy_to_user(ubp, page_address(st_bp->frp[i].page) + offset, cnt); + struct page *page = st_bp->reserved_pages[i]; + cnt = length - offset < do_count ? length - offset : do_count; + res = copy_to_user(ubp, page_address(page) + offset, cnt); if (res) return (-EFAULT); do_count -= cnt; @@ -3929,6 +3934,7 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset) { int src_seg, dst_seg, src_offset = 0, dst_offset; int count, total; + int length = PAGE_SIZE << st_bp->map_data.page_order; if (offset == 0) return; @@ -3936,24 +3942,26 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset) total=st_bp->buffer_bytes - offset; for (src_seg=0; src_seg < st_bp->frp_segs; src_seg++) { src_offset = offset; - if (src_offset < st_bp->frp[src_seg].length) + if (src_offset < length) break; - offset -= st_bp->frp[src_seg].length; + offset -= length; } st_bp->buffer_bytes = st_bp->read_pointer = total; for (dst_seg=dst_offset=0; total > 0; ) { - count = min(st_bp->frp[dst_seg].length - dst_offset, - st_bp->frp[src_seg].length - src_offset); - memmove(page_address(st_bp->frp[dst_seg].page) + dst_offset, - page_address(st_bp->frp[src_seg].page) + src_offset, count); + struct page *dpage = st_bp->reserved_pages[dst_seg]; + struct page *spage = st_bp->reserved_pages[src_seg]; + + count = min(length - dst_offset, length - src_offset); + memmove(page_address(dpage) + dst_offset, + page_address(spage) + src_offset, count); src_offset += count; - if (src_offset >= st_bp->frp[src_seg].length) { + if (src_offset >= length) { src_seg++; src_offset = 0; } dst_offset += count; - if (dst_offset >= st_bp->frp[dst_seg].length) { + if (dst_offset >= length) { dst_seg++; dst_offset = 0; } |