Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/bouyer-xen2]: src/sys/arch/xen Improve ressource shortage recovery: if x...



details:   https://anonhg.NetBSD.org/src/rev/7d7fecf9bfc2
branches:  bouyer-xen2
changeset: 571904:7d7fecf9bfc2
user:      bouyer <bouyer%NetBSD.org@localhost>
date:      Tue Mar 08 22:24:10 2005 +0000

description:
Improve ressource shortage recovery: if xen_shm_map() fails, register a
callback wich will retry the I/O when xen_shm_unmap() is called.

diffstat:

 sys/arch/xen/i386/xen_shm_machdep.c |  74 ++++++++++++++++++++++++++++++++---
 sys/arch/xen/include/xen_shm.h      |   8 ++-
 sys/arch/xen/xen/xbdback.c          |  76 ++++++++++++++++++++++++++----------
 sys/arch/xen/xen/xennetback.c       |   4 +-
 4 files changed, 130 insertions(+), 32 deletions(-)

diffs (truncated from 321 to 300 lines):

diff -r 432a91efaf3d -r 7d7fecf9bfc2 sys/arch/xen/i386/xen_shm_machdep.c
--- a/sys/arch/xen/i386/xen_shm_machdep.c       Tue Mar 08 19:33:01 2005 +0000
+++ b/sys/arch/xen/i386/xen_shm_machdep.c       Tue Mar 08 22:24:10 2005 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: xen_shm_machdep.c,v 1.1.2.1 2005/02/16 13:46:29 bouyer Exp $      */
+/*      $NetBSD: xen_shm_machdep.c,v 1.1.2.2 2005/03/08 22:24:10 bouyer Exp $      */
 
 /*
  * Copyright (c) 2005 Manuel Bouyer.
@@ -54,9 +54,12 @@
  * At boot time, we grap some kernel VM space that we'll use to map the foreing
  * pages. We also maintain a virtual to machine mapping table to give back
  * the appropriate address to bus_dma if requested.
+ * If no more VM space is available, we return an error. The caller can then
+ * register a callback which will be called when the required VM space is
+ * available.
  */
 
-
+/* pointers to our VM space */
 vaddr_t xen_shm_base_address;
 u_long xen_shm_base_address_pg;
 vaddr_t xen_shm_end_address;
@@ -74,9 +77,29 @@
 /* vm space management */
 struct extent *xen_shm_ex;
 
+/* callbacks are registered in a FIFO list. */
+
+SIMPLEQ_HEAD(xen_shm_callback_head, xen_shm_callback_entry) xen_shm_callbacks;
+struct xen_shm_callback_entry {
+       SIMPLEQ_ENTRY(xen_shm_callback_entry) xshmc_entries;
+       int (*xshmc_callback)(void *); /* our callback */
+       void *xshmc_arg; /* cookie passed to the callback */
+};
+/* a pool of struct xen_shm_callback_entry */
+struct pool xen_shm_callback_pool;
+
 void
 xen_shm_init()
 {
+       SIMPLEQ_INIT(&xen_shm_callbacks);
+       pool_init(&xen_shm_callback_pool, sizeof(struct xen_shm_callback_entry),
+           0, 0, 0, "xshmc", NULL);
+       /* ensure we'll always get items */
+       if (pool_prime(&xen_shm_callback_pool,
+           PAGE_SIZE / sizeof(struct xen_shm_callback_entry)) != 0) {
+               panic("xen_shm_init can't prime pool");
+       }
+
        xen_shm_base_address = uvm_km_valloc(kernel_map, xen_shm_size);
        xen_shm_end_address = xen_shm_base_address + xen_shm_size;
        xen_shm_base_address_pg = xen_shm_base_address >> PAGE_SHIFT;
@@ -93,8 +116,8 @@
        memset(_xen_shm_vaddr2ma, -1, sizeof(_xen_shm_vaddr2ma));
 }
 
-vaddr_t
-xen_shm_map(paddr_t *ma, int nentries, int domid)
+int
+xen_shm_map(paddr_t *ma, int nentries, int domid, vaddr_t *vap, int flags)
 {
        int i;
        vaddr_t new_va;
@@ -102,10 +125,19 @@
        multicall_entry_t mcl[XENSHM_MAX_PAGES_PER_REQUEST];
        int remap_prot = PG_V | PG_RW | PG_U | PG_M;
 
+       /*
+        * if a driver is waiting for ressources, don't try to allocate
+        * yet. This is to avoid a flood of small requests stalling large
+        * ones.
+        */
+       if (__predict_false(SIMPLEQ_FIRST(&xen_shm_callbacks) != NULL) &&
+           (flags & XSHM_CALLBACK) == 0)
+               return ENOMEM;
        /* allocate the needed virtual space */
        if (extent_alloc(xen_shm_ex, nentries, 1, 0, EX_NOWAIT, &new_va_pg)
            != 0)
-               return 0;
+               return ENOMEM;
+
        new_va = new_va_pg << PAGE_SHIFT;
        for (i = 0; i < nentries; i++, new_va_pg++) {
                mcl[i].op = __HYPERVISOR_update_va_mapping_otherdomain;
@@ -123,10 +155,11 @@
                if ((mcl[i].args[5] != 0)) {
                        printf("xen_shm_map: mcl[%d] failed\n", i);
                        xen_shm_unmap(new_va, ma, nentries, domid);
-                       return 0;
+                       return EINVAL;
                }
        }
-       return new_va;
+       *vap = new_va;
+       return 0;
 }
 
 void
@@ -134,6 +167,7 @@
 {
        multicall_entry_t mcl[XENSHM_MAX_PAGES_PER_REQUEST];
        int i;
+       struct xen_shm_callback_entry *xshmc;
 
        va = va >> PAGE_SHIFT;
        for (i = 0; i < nentries; i++) {
@@ -148,8 +182,34 @@
                panic("xen_shm_unmap");
        if (extent_free(xen_shm_ex, va, nentries, EX_NOWAIT) != 0)
                panic("xen_shm_unmap: extent_free");
+       while (__predict_false((xshmc = SIMPLEQ_FIRST(&xen_shm_callbacks))
+           != NULL)) {
+               if (xshmc->xshmc_callback(xshmc->xshmc_arg) == 0) {
+                       /* callback succeeded */
+                       SIMPLEQ_REMOVE_HEAD(&xen_shm_callbacks, xshmc_entries);
+                       pool_put(&xen_shm_callback_pool, xshmc);
+               } else {
+                       /* callback failed, probably out of ressources */
+                       return;
+               }
+       }
 }
 
+int
+xen_shm_callback(int (*callback)(void *), void *arg)
+{
+       struct xen_shm_callback_entry *xshmc;
+
+       xshmc = pool_get(&xen_shm_callback_pool, PR_NOWAIT);
+       if (xshmc == NULL)
+               return ENOMEM;
+       xshmc->xshmc_arg = arg;
+       xshmc->xshmc_callback = callback;
+       SIMPLEQ_INSERT_TAIL(&xen_shm_callbacks, xshmc, xshmc_entries);
+       return 0;
+}
+
+
 /*
  * Shared memory pages are managed by drivers, and are not known from
  * the pmap. This tests if va is a shared memory page, and if so
diff -r 432a91efaf3d -r 7d7fecf9bfc2 sys/arch/xen/include/xen_shm.h
--- a/sys/arch/xen/include/xen_shm.h    Tue Mar 08 19:33:01 2005 +0000
+++ b/sys/arch/xen/include/xen_shm.h    Tue Mar 08 22:24:10 2005 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: xen_shm.h,v 1.1.2.1 2005/02/16 13:46:29 bouyer Exp $      */
+/*      $NetBSD: xen_shm.h,v 1.1.2.2 2005/03/08 22:24:10 bouyer Exp $      */
 
 /*
  * Copyright (c) 2005 Manuel Bouyer.
@@ -36,6 +36,10 @@
  * space, do I/O to it, and unmap it.
  */
 
-vaddr_t xen_shm_map(paddr_t *, int, int);
+int  xen_shm_map(paddr_t *, int, int, vaddr_t *, int);
 void xen_shm_unmap(vaddr_t, paddr_t *, int, int);
+int xen_shm_callback(int (*)(void *), void *);
 int  xen_shm_vaddr2ma(vaddr_t, paddr_t *);
+
+/* flags for xen_shm_map() */
+#define XSHM_CALLBACK 0x01     /* called from a callback */
diff -r 432a91efaf3d -r 7d7fecf9bfc2 sys/arch/xen/xen/xbdback.c
--- a/sys/arch/xen/xen/xbdback.c        Tue Mar 08 19:33:01 2005 +0000
+++ b/sys/arch/xen/xen/xbdback.c        Tue Mar 08 22:24:10 2005 +0000
@@ -1,4 +1,4 @@
-/*      $NetBSD: xbdback.c,v 1.1.2.2 2005/03/08 19:33:01 bouyer Exp $      */
+/*      $NetBSD: xbdback.c,v 1.1.2.3 2005/03/08 22:24:10 bouyer Exp $      */
 
 /*
  * Copyright (c) 2005 Manuel Bouyer.
@@ -119,6 +119,7 @@
        SLIST_ENTRY(xbdback_request) next;
        blkif_request_t *rq_req; /* the request itself */
        vaddr_t rq_vaddr; /* the virtual address to map the request at */
+       paddr_t rq_ma[BLKIF_MAX_PAGES_PER_REQUEST]; /* machine address to map */
        struct xbdback_instance *rq_xbdi; /* our xbd instance */
 };
 SLIST_HEAD(, xbdback_request) free_xbdback_requests;
@@ -130,6 +131,8 @@
 static struct xbd_vbd * vbd_lookup(struct xbdback_instance *, blkif_vdev_t);
 
 static int  xbdback_io(struct xbdback_instance *, blkif_request_t *);
+static int  xbdback_shm_callback(void *);
+static void xbdback_do_io(struct xbdback_request *);
 static void xbdback_iodone(struct buf *);
 static int  xbdback_probe(struct xbdback_instance *, blkif_request_t *);
 static void xbdback_send_reply(struct xbdback_instance *, int , int , int);
@@ -523,7 +526,7 @@
                }
                switch (error) {
                case 0:
-                       /* reply has already been sent */
+                       /* reply has already been sent, or will be */
                        break;
                default:
                        xbdback_send_reply(xbdi, req->id, req->operation,
@@ -563,11 +566,6 @@
        SLIST_REMOVE_HEAD(&free_xbdback_requests, next);
 
        xbd_req->rq_xbdi = xbdi;
-       if (xbdback_map_shm(req, xbd_req) < 0) {
-               xbd_req->rq_req = NULL;
-               SLIST_INSERT_HEAD(&free_xbdback_requests, xbd_req, next);
-               return EINVAL;
-       }
 
        start_offset =
            blkif_first_sect(req->frame_and_sects[0]) * VBD_BSIZE;
@@ -606,20 +604,60 @@
        xbd_req->rq_buf.b_vp = vbd->vp;
        xbd_req->rq_buf.b_blkno = req->sector_number;
        xbd_req->rq_buf.b_bcount = (daddr_t)req_size;
-       xbd_req->rq_buf.b_data = (void *)(xbd_req->rq_vaddr + start_offset);
+       xbd_req->rq_buf.b_data = (void *)start_offset;
        xbd_req->rq_buf.b_private = xbd_req;
-       if ((xbd_req->rq_buf.b_flags & B_READ) == 0)
-               xbd_req->rq_buf.b_vp->v_numoutput++;
-       XENPRINTF(("xbdback_io domain %d: start reqyest\n", xbdi->domid));
-       VOP_STRATEGY(vbd->vp, &xbd_req->rq_buf);
-       return 0;
+       switch(xbdback_map_shm(req, xbd_req)) {
+       case 0:
+               xbdback_do_io(xbd_req);
+               return 0;
+       case ENOMEM:
+               if (xen_shm_callback(xbdback_shm_callback, xbd_req) == 0)
+                       return 0;
+               error = ENOMEM;
+               break;
+       default:
+               error = EINVAL;
+               break;
+       }
 end:
-       xbdback_unmap_shm(xbd_req);
        xbd_req->rq_req = NULL;
        SLIST_INSERT_HEAD(&free_xbdback_requests, xbd_req, next);
        return error;
 }
 
+static int
+xbdback_shm_callback(void *arg)
+{
+       struct xbdback_request *xbd_req = arg;
+
+       switch(xen_shm_map(xbd_req->rq_ma, xbd_req->rq_req->nr_segments,
+           xbd_req->rq_xbdi->domid, &xbd_req->rq_vaddr, XSHM_CALLBACK)) {
+       case ENOMEM:
+               return -1; /* will try again later */
+       case 0:
+               xbdback_do_io(xbd_req);
+               return 0;
+       default:
+               xbdback_send_reply(xbd_req->rq_xbdi, xbd_req->rq_req->id,
+                   xbd_req->rq_req->operation, BLKIF_RSP_ERROR);
+               xbd_req->rq_req = NULL;
+               SLIST_INSERT_HEAD(&free_xbdback_requests, xbd_req, next);
+               return 0;
+       }
+}
+
+static void
+xbdback_do_io(struct xbdback_request *xbd_req)
+{
+       xbd_req->rq_buf.b_data =
+           (void *)((vaddr_t)xbd_req->rq_buf.b_data + xbd_req->rq_vaddr);
+       if ((xbd_req->rq_buf.b_flags & B_READ) == 0)
+               xbd_req->rq_buf.b_vp->v_numoutput++;
+       XENPRINTF(("xbdback_io domain %d: start reqyest\n",
+           xbd_req->rq_xbdi->domid));
+       VOP_STRATEGY(xbd_req->rq_buf.b_vp, &xbd_req->rq_buf);
+}
+
 static void
 xbdback_iodone(struct buf *bp)
 {
@@ -717,7 +755,6 @@
 static int
 xbdback_map_shm(blkif_request_t *req, struct xbdback_request *xbd_req)
 {
-       paddr_t ma[BLKIF_MAX_PAGES_PER_REQUEST];
        int i;
 
        xbd_req->rq_req = req;
@@ -731,13 +768,10 @@
 #endif
 
        for (i = 0; i < req->nr_segments; i++) {
-               ma[i] = (req->frame_and_sects[i] & ~PAGE_MASK);
+               xbd_req->rq_ma[i] = (req->frame_and_sects[i] & ~PAGE_MASK);
        }
-       xbd_req->rq_vaddr =
-           xen_shm_map(ma, req->nr_segments, xbd_req->rq_xbdi->domid);
-       if (xbd_req->rq_vaddr == -1)
-               panic("xbdback_map_shm");
-       return 0;
+       return xen_shm_map(xbd_req->rq_ma, req->nr_segments,
+               xbd_req->rq_xbdi->domid, &xbd_req->rq_vaddr, 0);



Home | Main Index | Thread Index | Old Index