Subject: port-xen/33110: map_align() in xbd.c may sleep
To: None <port-xen@NetBSD.org>
From: Jed Davis <jdev@panix.com>
List: port-xen
Date: 03/20/2006 21:51:52
--=-=-=
[To, hopefully, summarize my PR:]
On the -3 branch, I can get a panic in xbd pretty reliably (on at
least one test host) when map_align()'s memory allocation fails and
tries to sleep; it's in interrupt context, of course, so it can't.
It looks like this was fixed in -current, but that's tangled up in a
bunch of major infrastructure changes, and so pulling it up would be
hard or impossible.
So, I've attempted to get xbdstart() as it exists in -3 to fail
gracefully and put off the I/O for later (patch attached, and will be
added to the PR), but I may well have gotten it wrong.
--
(let ((C call-with-current-continuation)) (apply (lambda (x y) (x y)) (map
((lambda (r) ((C C) (lambda (s) (r (lambda l (apply (s s) l)))))) (lambda
(f) (lambda (l) (if (null? l) C (lambda (k) (display (car l)) ((f (cdr l))
(C k))))))) '((#\J #\d #\D #\v #\s) (#\e #\space #\a #\i #\newline)))))
--=-=-=
Content-Type: text/x-patch
Content-Disposition: attachment; filename=xbd-3-nowait.diff
Index: arch/xen/xen/xbd.c
===================================================================
RCS file: /cvsroot/src/sys/arch/xen/xen/xbd.c,v
retrieving revision 1.14.2.5
diff -u -p -r1.14.2.5 xbd.c
--- arch/xen/xen/xbd.c 28 Apr 2005 10:28:42 -0000 1.14.2.5
+++ arch/xen/xen/xbd.c 20 Mar 2006 23:22:22 -0000
@@ -1140,7 +1140,7 @@ xbdsize(dev_t dev)
return dk_size(xs->sc_di, &xs->sc_dksc, dev);
}
-static void
+static int
map_align(struct xbdreq *xr)
{
int s;
@@ -1148,8 +1148,10 @@ map_align(struct xbdreq *xr)
s = splvm();
xr->xr_aligned = uvm_km_kmemalloc1(kmem_map, NULL,
xr->xr_bqueue, XEN_BSIZE, UVM_UNKNOWN_OFFSET,
- 0/* UVM_KMF_NOWAIT */);
+ UVM_KMF_NOWAIT);
splx(s);
+ if (xr->xr_aligned == 0)
+ return 0;
DPRINTF(XBDB_IO, ("map_align(%p): bp %p addr %p align 0x%08lx "
"size 0x%04lx\n", xr, xr->xr_bp, xr->xr_bp->b_data,
xr->xr_aligned, xr->xr_bqueue));
@@ -1157,6 +1159,7 @@ map_align(struct xbdreq *xr)
if ((xr->xr_bp->b_flags & B_READ) == 0)
memcpy((void *)xr->xr_aligned, xr->xr_bp->b_data,
xr->xr_bqueue);
+ return 1;
}
static void
@@ -1361,7 +1364,13 @@ xbdstart(struct dk_softc *dksc, struct b
pxr->xr_sc = xs;
if (pxr->xr_data & (XEN_BSIZE - 1))
- map_align(pxr);
+ if (!map_align(pxr)) { /* No memory; try later. */
+ DPRINTF(XBDB_IO, ("xbdstart: map_align failed\n"));
+ ret = -1;
+ disk_unbusy(&dksc->sc_dkdev, 0, bp->b_flags & B_READ);
+ PUT_XBDREQ(pxr);
+ goto out;
+ }
fill_ring(pxr);
--=-=-=--