This is similar to the credit scheduler used in netif, except that it
allows occasional burstability (for use with e2fsck as an example).
Signed-off-by: William Pitcock <nenolod@xxxxxxxxxxxxxxxx>
---
drivers/xen/blkback/blkback.c | 25 +++++++++++++++++++++++++
drivers/xen/blkback/common.h | 5 +++++
drivers/xen/blkback/xenbus.c | 41 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 71 insertions(+), 0 deletions(-)
diff --git a/drivers/xen/blkback/blkback.c b/drivers/xen/blkback/blkback.c
index 8d988f4..0ed4998 100644
--- a/drivers/xen/blkback/blkback.c
+++ b/drivers/xen/blkback/blkback.c
@@ -203,6 +203,16 @@ static void print_stats(blkif_t *blkif)
blkif->st_oo_req = 0;
}
+static void refill_credit(blkif_t *blkif)
+{
+ blkif->credit_time = jiffies + msecs_to_jiffies(blkif->credit_msec);
+ blkif->available_credit += blkif->credit_req;
+
+ /* this allows for bursting. */
+ if (blkif->available_credit > (blkif->credit_req * blkif->credit_msec))
+ blkif->available_credit = blkif->credit_req;
+}
+
int blkif_schedule(void *arg)
{
blkif_t *blkif = arg;
@@ -230,6 +240,9 @@ int blkif_schedule(void *arg)
blkif->waiting_reqs = 1;
unplug_queue(blkif);
+ if (time_after(jiffies, blkif->credit_time))
+ refill_credit(blkif);
+
if (log_stats && time_after(jiffies, blkif->st_print))
print_stats(blkif);
}
@@ -313,11 +326,23 @@ static int do_block_io_op(blkif_t *blkif)
rp = blk_rings->common.sring->req_prod;
rmb(); /* Ensure we see queued requests up to 'rp'. */
+ /* if there's no available request credit right now, and limiting
+ * is requested, then don't bother with going any further.
+ */
+ if (blkif->remaining_credit <= 0 && blkif->credit_req != 0)
+ return (rc != rp) ? 1 : 0;
+
while (rc != rp) {
if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc))
break;
+ /* FIXME: Should we report QoS overages as VBD_OO, or not? */
+ if (blkif->credit_req != 0 && --blkif->remaining_credit <= 0) {
+ more_to_do = 1;
+ break;
+ }
+
if (kthread_should_stop()) {
more_to_do = 1;
break;
diff --git a/drivers/xen/blkback/common.h b/drivers/xen/blkback/common.h
index 57b7825..971d3fa 100644
--- a/drivers/xen/blkback/common.h
+++ b/drivers/xen/blkback/common.h
@@ -92,6 +92,11 @@ typedef struct blkif_st {
grant_handle_t shmem_handle;
grant_ref_t shmem_ref;
+
+ int credit_req;
+ int remaining_credit;
+ int credit_msec;
+ unsigned long credit_time;
} blkif_t;
blkif_t *blkif_alloc(domid_t domid);
diff --git a/drivers/xen/blkback/xenbus.c b/drivers/xen/blkback/xenbus.c
index 650f4b3..9a45299 100644
--- a/drivers/xen/blkback/xenbus.c
+++ b/drivers/xen/blkback/xenbus.c
@@ -255,6 +255,42 @@ fail:
return err;
}
+static void blkback_read_credit(struct xenbus_transaction xbt,
+ struct xenbus_device *dev,
+ unsigned long *credit, unsigned long *msec)
+{
+ char *s, *e;
+ unsigned long b, u;
+ char *ratestr;
+
+ /* Default to unlimited I/O operations. */
+ *credit = ~0UL;
+ *usec = 0;
+
+ ratestr = xenbus_read(xbt, dev->nodename, "credit", NULL);
+ if (IS_ERR(ratestr))
+ return;
+
+ s = ratestr;
+ b = simple_strtoul(s, &e, 10);
+ if ((s == e) || (*e != ','))
+ goto fail;
+
+ s = e + 1;
+ u = simple_strtoul(s, &e, 10);
+ if ((s == e) || (*e != '\0'))
+ goto fail;
+
+ *credit = b;
+ *msec = (u / 1000);
+
+ kfree(ratestr);
+ return;
+
+ fail:
+ WPRINTK("Failed to parse I/O credit limit. I/O operations are
unlimited.\n");
+ kfree(ratestr);
+}
/**
* Callback received when the hotplug scripts have placed the physical-device
@@ -401,6 +437,7 @@ static void frontend_changed(struct xenbus_device *dev,
/* ** Connection ** */
+
/**
* Write the physical details regarding the block device to the store, and
* switch to Connected state.
@@ -425,6 +462,10 @@ again:
if (err)
goto abort;
+ blkback_read_credit(xbt, dev, &be->blkif->credit_req,
+ &be->blkif->credit_msec);
+ be->blkif->remaining_credit = be->blkif->credit_req;
+
err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu",
vbd_size(&be->blkif->vbd));
if (err) {
--
1.6.3.3
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|