# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1261031870 0
# Node ID df70d482d0f43fbd6f5e55a006350e93e26ed9a5
# Parent 981db8d78913016a0dbfa041e106b3404b5f5791
Fixes to block backend to handle -EAGAIN grant table errors properly.
Signed-off-by: Grzegorz Milos <Grzegorz.Milos@xxxxxxxxxx>
---
drivers/xen/blkback/blkback.c | 53 ++++++++++++++++++++++++++++++++--------
drivers/xen/blkback/common.h | 2 +
drivers/xen/blkback/interface.c | 8 ++++--
3 files changed, 51 insertions(+), 12 deletions(-)
diff -r 981db8d78913 -r df70d482d0f4 drivers/xen/blkback/blkback.c
--- a/drivers/xen/blkback/blkback.c Thu Dec 17 06:37:49 2009 +0000
+++ b/drivers/xen/blkback/blkback.c Thu Dec 17 06:37:50 2009 +0000
@@ -107,7 +107,7 @@ static inline unsigned long vaddr(pendin
static int do_block_io_op(blkif_t *blkif);
-static void dispatch_rw_block_io(blkif_t *blkif,
+static int dispatch_rw_block_io(blkif_t *blkif,
blkif_request_t *req,
pending_req_t *pending_req);
static void make_response(blkif_t *blkif, u64 id,
@@ -309,13 +309,13 @@ static int do_block_io_op(blkif_t *blkif
blkif_request_t req;
pending_req_t *pending_req;
RING_IDX rc, rp;
- int more_to_do = 0;
+ int more_to_do = 0, ret;
rc = blk_rings->common.req_cons;
rp = blk_rings->common.sring->req_prod;
rmb(); /* Ensure we see queued requests up to 'rp'. */
- while (rc != rp) {
+ while ((rc != rp) || (blkif->is_suspended_req)) {
if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc))
break;
@@ -332,6 +332,14 @@ static int do_block_io_op(blkif_t *blkif
break;
}
+ /* Handle the suspended request first, if one exists */
+ if(blkif->is_suspended_req)
+ {
+ memcpy(&req, &blkif->suspended_req, sizeof(req));
+ blkif->is_suspended_req = 0;
+ goto handle_request;
+ }
+
switch (blkif->blk_protocol) {
case BLKIF_PROTOCOL_NATIVE:
memcpy(&req, RING_GET_REQUEST(&blk_rings->native, rc),
sizeof(req));
@@ -350,17 +358,19 @@ static int do_block_io_op(blkif_t *blkif
/* Apply all sanity checks to /private copy/ of request. */
barrier();
+handle_request:
+ ret = 0;
switch (req.operation) {
case BLKIF_OP_READ:
blkif->st_rd_req++;
- dispatch_rw_block_io(blkif, &req, pending_req);
+ ret = dispatch_rw_block_io(blkif, &req, pending_req);
break;
case BLKIF_OP_WRITE_BARRIER:
blkif->st_br_req++;
/* fall through */
case BLKIF_OP_WRITE:
blkif->st_wr_req++;
- dispatch_rw_block_io(blkif, &req, pending_req);
+ ret = dispatch_rw_block_io(blkif, &req, pending_req);
break;
default:
/* A good sign something is wrong: sleep for a while to
@@ -373,6 +383,17 @@ static int do_block_io_op(blkif_t *blkif
free_req(pending_req);
break;
}
+ BUG_ON(ret != 0 && ret != -EAGAIN);
+ /* If we can't handle the request at the moment, save it, and break the
+ * loop */
+ if(ret == -EAGAIN)
+ {
+ memcpy(&blkif->suspended_req, &req, sizeof(req));
+ blkif->is_suspended_req = 1;
+ /* Return "no more work pending", restart will be handled 'out of
+ * band' */
+ return 0;
+ }
/* Yield point for this unbounded loop. */
cond_resched();
@@ -381,7 +402,7 @@ static int do_block_io_op(blkif_t *blkif
return more_to_do;
}
-static void dispatch_rw_block_io(blkif_t *blkif,
+static int dispatch_rw_block_io(blkif_t *blkif,
blkif_request_t *req,
pending_req_t *pending_req)
{
@@ -450,11 +471,15 @@ static void dispatch_rw_block_io(blkif_t
ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nseg);
BUG_ON(ret);
+#define GENERAL_ERR (1<<0)
+#define EAGAIN_ERR (1<<1)
for (i = 0; i < nseg; i++) {
if (unlikely(map[i].status != 0)) {
DPRINTK("invalid buffer -- could not remap it\n");
map[i].handle = BLKBACK_INVALID_HANDLE;
- ret |= 1;
+ ret |= GENERAL_ERR;
+ if(map[i].status == GNTST_eagain)
+ ret |= EAGAIN_ERR;
} else {
blkback_pagemap_set(vaddr_pagenr(pending_req, i),
pending_page(pending_req, i),
@@ -473,6 +498,14 @@ static void dispatch_rw_block_io(blkif_t
seg[i].buf = map[i].dev_bus_addr |
(req->seg[i].first_sect << 9);
}
+
+ /* If any of grant maps failed with GNTST_eagain, suspend and retry later
*/
+ if(ret & EAGAIN_ERR)
+ {
+ fast_flush_area(pending_req);
+ free_req(pending_req);
+ return -EAGAIN;
+ }
if (ret)
goto fail_flush;
@@ -539,7 +572,7 @@ static void dispatch_rw_block_io(blkif_t
else if (operation == WRITE || operation == WRITE_BARRIER)
blkif->st_wr_sect += preq.nr_sects;
- return;
+ return 0;
fail_flush:
fast_flush_area(pending_req);
@@ -547,7 +580,7 @@ static void dispatch_rw_block_io(blkif_t
make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
free_req(pending_req);
msleep(1); /* back off a bit */
- return;
+ return 0;
fail_put_bio:
__end_block_io_op(pending_req, -EINVAL);
@@ -555,7 +588,7 @@ static void dispatch_rw_block_io(blkif_t
bio_put(bio);
unplug_queue(blkif);
msleep(1); /* back off a bit */
- return;
+ return 0;
}
diff -r 981db8d78913 -r df70d482d0f4 drivers/xen/blkback/common.h
--- a/drivers/xen/blkback/common.h Thu Dec 17 06:37:49 2009 +0000
+++ b/drivers/xen/blkback/common.h Thu Dec 17 06:37:50 2009 +0000
@@ -82,6 +82,8 @@ typedef struct blkif_st {
struct task_struct *xenblkd;
unsigned int waiting_reqs;
request_queue_t *plug;
+ int is_suspended_req;
+ blkif_request_t suspended_req;
/* statistics */
unsigned long st_print;
diff -r 981db8d78913 -r df70d482d0f4 drivers/xen/blkback/interface.c
--- a/drivers/xen/blkback/interface.c Thu Dec 17 06:37:49 2009 +0000
+++ b/drivers/xen/blkback/interface.c Thu Dec 17 06:37:50 2009 +0000
@@ -33,6 +33,7 @@
#include "common.h"
#include <xen/evtchn.h>
#include <linux/kthread.h>
+#include <linux/delay.h>
static kmem_cache_t *blkif_cachep;
@@ -62,8 +63,11 @@ static int map_frontend_page(blkif_t *bl
gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr,
GNTMAP_host_map, shared_page, blkif->domid);
- if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
- BUG();
+ do {
+ if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
+ BUG();
+ msleep(100);
+ } while(op.status == GNTST_eagain);
if (op.status) {
DPRINTK(" Grant table operation failure !\n");
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|