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);
 

--=-=-=--