aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-05-20 16:51:49 +0000
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>2005-05-20 16:51:49 +0000
commit0474fa45ff84c8ef79cc63b239f2102dd38ea792 (patch)
tree12dbf520763d23b282337494978c46aa99360361
parentb2a0b491ee0397c0ff7b068a4091b1f7d7a66ca6 (diff)
downloadxen-0474fa45ff84c8ef79cc63b239f2102dd38ea792.tar.gz
xen-0474fa45ff84c8ef79cc63b239f2102dd38ea792.tar.bz2
xen-0474fa45ff84c8ef79cc63b239f2102dd38ea792.zip
bitkeeper revision 1.1159.258.144 (428e15a5YtSRzDLLgCSLxJk6OkQbKA)
Handle mis-aligned I/O requests in blkback driver. Signed-off-by: Keir Fraser <keir@xensource.com>
-rw-r--r--linux-2.6.11-xen-sparse/drivers/xen/blkback/blkback.c49
1 files changed, 44 insertions, 5 deletions
diff --git a/linux-2.6.11-xen-sparse/drivers/xen/blkback/blkback.c b/linux-2.6.11-xen-sparse/drivers/xen/blkback/blkback.c
index dc15b20180..80db9e1752 100644
--- a/linux-2.6.11-xen-sparse/drivers/xen/blkback/blkback.c
+++ b/linux-2.6.11-xen-sparse/drivers/xen/blkback/blkback.c
@@ -47,6 +47,8 @@ typedef struct {
atomic_t pendcnt;
unsigned short operation;
int status;
+ void *bounce_page;
+ unsigned int bounce_off, bounce_len;
} pending_req_t;
/*
@@ -232,6 +234,15 @@ static void __end_block_io_op(pending_req_t *pending_req, int uptodate)
if ( atomic_dec_and_test(&pending_req->pendcnt) )
{
int pending_idx = pending_req - pending_reqs;
+ if ( unlikely(pending_req->bounce_page != NULL) )
+ {
+ memcpy((void *)(MMAP_VADDR(pending_idx, 0) +
+ pending_req->bounce_off),
+ (void *)((unsigned long)pending_req->bounce_page +
+ pending_req->bounce_off),
+ pending_req->bounce_len);
+ free_page((unsigned long)pending_req->bounce_page);
+ }
fast_flush_area(pending_idx, pending_req->nr_pages);
make_response(pending_req->blkif, pending_req->id,
pending_req->operation, pending_req->status);
@@ -452,6 +463,7 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
pending_req->operation = operation;
pending_req->status = BLKIF_RSP_OKAY;
pending_req->nr_pages = nr_psegs;
+ pending_req->bounce_page = NULL;
atomic_set(&pending_req->pendcnt, nr_psegs);
pending_cons++;
@@ -511,11 +523,38 @@ static void dispatch_rw_block_io(blkif_t *blkif, blkif_request_t *req)
bio->bi_end_io = end_block_io_op;
bio->bi_sector = phys_seg[i].sector_number;
- bio_add_page(
- bio,
- virt_to_page(MMAP_VADDR(pending_idx, i)),
- phys_seg[i].nr_sects << 9,
- phys_seg[i].buffer & ~PAGE_MASK);
+ /* Is the request misaligned with respect to hardware sector size? */
+ if ( ((bio->bi_sector | phys_seg[i].nr_sects) &
+ ((bdev_hardsect_size(bio->bi_bdev) >> 9) - 1)) )
+ {
+ /* We can't bounce scatter-gather requests. */
+ if ( (nr_psegs != 1) ||
+ ((pending_req->bounce_page = (void *)
+ __get_free_page(GFP_KERNEL)) == NULL) )
+ {
+ printk("xen_blk: Unaligned scatter-gather request!\n");
+ bio_put(bio);
+ __end_block_io_op(pending_req, 0);
+ continue;
+ }
+
+ /* Record offset and length within a bounce page. */
+ pending_req->bounce_off = (bio->bi_sector << 9) & ~PAGE_MASK;
+ pending_req->bounce_len = phys_seg[i].nr_sects << 9;
+
+ /* Submit a page-aligned I/O. */
+ bio->bi_sector &= ~((PAGE_SIZE >> 9) - 1);
+ bio_add_page(
+ bio, virt_to_page(pending_req->bounce_page), PAGE_SIZE, 0);
+ }
+ else
+ {
+ bio_add_page(
+ bio,
+ virt_to_page(MMAP_VADDR(pending_idx, i)),
+ phys_seg[i].nr_sects << 9,
+ phys_seg[i].buffer & ~PAGE_MASK);
+ }
if ( (q = bdev_get_queue(bio->bi_bdev)) != plugged_queue )
{