Module Name:    src
Committed By:   jdolecek
Date:           Sun Apr 12 20:17:36 UTC 2020

Modified Files:
        src/sys/arch/xen/xen: xbd_xenbus.c

Log Message:
convert to bus_dma(9)

simplify and fix error handling in xbd_handler(), expect backend
to not use the grant once request is finished, and avoid leaking
bounce buffer when the request using it happens to end with error

in xbd_diskstart() only do the RING_PUSH_REQUESTS_AND_CHECK_NOTIFY()
when actually the request was pushed successfully


To generate a diff of this commit:
cvs rdiff -u -r1.104 -r1.105 src/sys/arch/xen/xen/xbd_xenbus.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/xen/xen/xbd_xenbus.c
diff -u src/sys/arch/xen/xen/xbd_xenbus.c:1.104 src/sys/arch/xen/xen/xbd_xenbus.c:1.105
--- src/sys/arch/xen/xen/xbd_xenbus.c:1.104	Sun Apr 12 18:14:09 2020
+++ src/sys/arch/xen/xen/xbd_xenbus.c	Sun Apr 12 20:17:36 2020
@@ -1,4 +1,4 @@
-/*      $NetBSD: xbd_xenbus.c,v 1.104 2020/04/12 18:14:09 jdolecek Exp $      */
+/*      $NetBSD: xbd_xenbus.c,v 1.105 2020/04/12 20:17:36 jdolecek Exp $      */
 
 /*
  * Copyright (c) 2006 Manuel Bouyer.
@@ -50,7 +50,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: xbd_xenbus.c,v 1.104 2020/04/12 18:14:09 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: xbd_xenbus.c,v 1.105 2020/04/12 20:17:36 jdolecek Exp $");
 
 #include "opt_xen.h"
 
@@ -100,10 +100,10 @@ __KERNEL_RCSID(0, "$NetBSD: xbd_xenbus.c
 struct xbd_req {
 	SLIST_ENTRY(xbd_req) req_next;
 	uint16_t req_id; /* ID passed to backend */
+	bus_dmamap_t req_dmamap;
 	union {
 	    struct {
 		grant_ref_t req_gntref[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-		int req_nr_segments; /* number of segments in this request */
 		struct buf *req_bp; /* buffer associated with this request */
 		void *req_data; /* pointer to the data buffer */
 	    } req_rw;
@@ -114,7 +114,6 @@ struct xbd_req {
 	} u;
 };
 #define req_gntref	u.req_rw.req_gntref
-#define req_nr_segments	u.req_rw.req_nr_segments
 #define req_bp		u.req_rw.req_bp
 #define req_data	u.req_rw.req_data
 #define req_sync	u.req_sync
@@ -288,6 +287,16 @@ xbd_xenbus_attach(device_t parent, devic
 	evcnt_attach_dynamic(&sc->sc_cnt_map_unalign, EVCNT_TYPE_MISC,
 	    NULL, device_xname(self), "map unaligned");
 
+	for (i = 0; i < XBD_RING_SIZE; i++) {
+		if (bus_dmamap_create(sc->sc_xbusd->xbusd_dmat,
+		    XBD_MAX_XFER, BLKIF_MAX_SEGMENTS_PER_REQUEST,
+		    PAGE_SIZE, PAGE_SIZE, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
+		    &sc->sc_reqs[i].req_dmamap) != 0) {
+			aprint_error_dev(self, "can't alloc dma maps\n");
+			return;
+		}
+	}
+
 	/* resume shared structures and tell backend that we are ready */
 	if (xbd_xenbus_resume(self, PMF_Q_NONE) == false) {
 		uvm_km_free(kernel_map, (vaddr_t)ring, PAGE_SIZE,
@@ -371,6 +380,14 @@ xbd_xenbus_detach(device_t dev, int flag
 	uvm_km_free(kernel_map, (vaddr_t)sc->sc_ring.sring,
 	    PAGE_SIZE, UVM_KMF_WIRED);
 
+	for (i = 0; i < XBD_RING_SIZE; i++) {
+		if (sc->sc_reqs[i].req_dmamap != NULL) {
+			bus_dmamap_destroy(sc->sc_xbusd->xbusd_dmat,
+			    sc->sc_reqs[i].req_dmamap);
+			sc->sc_reqs[i].req_dmamap = NULL;
+		}
+	}
+
 	evcnt_detach(&sc->sc_cnt_map_unalign);
 
 	pmf_device_deregister(dev);
@@ -686,41 +703,38 @@ again:
 			continue;
 		}
 
-		for (seg = xbdreq->req_nr_segments - 1; seg >= 0; seg--) {
-			if (__predict_false(
-			    xengnt_status(xbdreq->req_gntref[seg]))) {
-				aprint_verbose_dev(sc->sc_dksc.sc_dev,
-					"grant still used by backend\n");
-				sc->sc_ring.rsp_cons = i;
-				xbdreq->req_nr_segments = seg + 1;
-				goto done;
-			}
+		for (seg = 0; seg < xbdreq->req_dmamap->dm_nsegs; seg++) {
+			/*
+			 * We are not allowing persistent mappings, so
+			 * expect the backend to release the grant
+			 * immediately.
+			 */
+			KASSERT(xengnt_status(xbdreq->req_gntref[seg]) == 0);
 			xengnt_revoke_access(xbdreq->req_gntref[seg]);
-			xbdreq->req_nr_segments--;
 		}
-		KASSERT(xbdreq->req_nr_segments == 0);
+
+		bus_dmamap_unload(sc->sc_xbusd->xbusd_dmat, xbdreq->req_dmamap);
 
 		bp = xbdreq->req_bp;
-		KASSERT(bp != NULL);
+		KASSERT(bp != NULL && bp->b_data != NULL);
 		DPRINTF(("%s(%p): b_bcount = %ld\n", __func__,
 		    bp, (long)bp->b_bcount));
 
+		if (__predict_false(bp->b_data != xbdreq->req_data))
+			xbd_unmap_align(xbdreq);
+		xbdreq->req_bp = xbdreq->req_data = NULL;
+
+		/* b_resid was set in dk_start, only override on error */
 		if (rep->status != BLKIF_RSP_OKAY) {
 			bp->b_error = EIO;
 			bp->b_resid = bp->b_bcount;
-			goto next;
 		}
-		/* b_resid was set in dk_start */
-		if (__predict_false(
-		    xbdreq->req_data != NULL && bp->b_data != xbdreq->req_data))
-			xbd_unmap_align(xbdreq);
-next:
-		xbdreq->req_bp = NULL;
+
 		dk_done(&sc->sc_dksc, bp);
 
 		SLIST_INSERT_HEAD(&sc->sc_xbdreq_head, xbdreq, req_next);
 	}
-done:
+
 	xen_rmb();
 	sc->sc_ring.rsp_cons = i;
 
@@ -937,9 +951,8 @@ xbd_diskstart(device_t self, struct buf 
 	struct xbd_xenbus_softc *sc = device_private(self);
 	struct xbd_req *xbdreq;
 	blkif_request_t *req;
-	size_t bcount, off;
+	size_t off;
 	paddr_t ma;
-	vaddr_t va;
 	int nsects, nbytes, seg;
 	int notify, error = 0;
 	int s;
@@ -947,19 +960,19 @@ xbd_diskstart(device_t self, struct buf 
 	DPRINTF(("xbd_diskstart(%p): b_bcount = %ld\n",
 	    bp, (long)bp->b_bcount));
 
+	s = splbio();	/* XXX SMP */
+
 	if (sc->sc_shutdown != BLKIF_SHUTDOWN_RUN) {
 		error = EIO;
-		goto err;
+		goto out;
 	}
 
 	if (bp->b_rawblkno < 0 || bp->b_rawblkno > sc->sc_xbdsize) {
 		/* invalid block number */
 		error = EINVAL;
-		goto err;
+		goto out;
 	}
 
-	s = splbio();	/* XXX SMP */
-
 	if (__predict_false(
 	    sc->sc_backend_status == BLKIF_STATE_SUSPENDED)) {
 		/* device is suspended, do not consume buffer */
@@ -997,6 +1010,16 @@ xbd_diskstart(device_t self, struct buf 
 		}
 	}
 
+	if (__predict_false(bus_dmamap_load(sc->sc_xbusd->xbusd_dmat,
+	    xbdreq->req_dmamap, xbdreq->req_data, bp->b_bcount, NULL,
+	    BUS_DMA_NOWAIT) != 0)) {
+		printf("%s: %s: xengnt_grant_access failed",
+		    device_xname(sc->sc_dksc.sc_dev), __func__);
+		error = EINVAL;
+		goto out;
+	}
+
+	/* We are now committed to the transfer */
 	SLIST_REMOVE_HEAD(&sc->sc_xbdreq_head, req_next);
 	req = RING_GET_REQUEST(&sc->sc_ring, sc->sc_ring.req_prod_pvt);
 	req->id = xbdreq->req_id;
@@ -1005,45 +1028,41 @@ xbd_diskstart(device_t self, struct buf 
 	req->sector_number = bp->b_rawblkno;
 	req->handle = sc->sc_handle;
 
-	va = (vaddr_t)xbdreq->req_data & ~PAGE_MASK;
-	off = (vaddr_t)xbdreq->req_data & PAGE_MASK;
-	bcount = bp->b_bcount;
 	bp->b_resid = 0;
-	for (seg = 0; bcount > 0;) {
-		pmap_extract_ma(pmap_kernel(), va, &ma);
-		KASSERT((ma & (XEN_BSIZE - 1)) == 0);
-		if (bcount > PAGE_SIZE - off)
-			nbytes = PAGE_SIZE - off;
-		else
-			nbytes = bcount;
+	for (seg = 0; seg < xbdreq->req_dmamap->dm_nsegs; seg++) {
+		bus_dma_segment_t *dmaseg = &xbdreq->req_dmamap->dm_segs[seg];
+
+		ma = dmaseg->ds_addr;
+		off = ma & PAGE_MASK;
+		nbytes = dmaseg->ds_len;
 		nsects = nbytes >> XEN_BSHIFT;
+
 		req->seg[seg].first_sect = off >> XEN_BSHIFT;
-		req->seg[seg].last_sect =
-		    (off >> XEN_BSHIFT) + nsects - 1;
-		KASSERT(req->seg[seg].first_sect <=
-		    req->seg[seg].last_sect);
-		KASSERT(req->seg[seg].last_sect < 8);
+		req->seg[seg].last_sect = (off >> XEN_BSHIFT) + nsects - 1;
+		KASSERT(req->seg[seg].first_sect <= req->seg[seg].last_sect);
+		KASSERT(req->seg[seg].last_sect < (PAGE_SIZE / XEN_BSIZE));
+
 		if (__predict_false(xengnt_grant_access(
-		    sc->sc_xbusd->xbusd_otherend_id, ma,
-		    (bp->b_flags & B_READ) == 0,
-		    &xbdreq->req_gntref[seg])))
-			panic("xbd_diskstart: xengnt_grant_access"); /* XXX XXX !!! */
+		    sc->sc_xbusd->xbusd_otherend_id,
+		    (ma & ~PAGE_MASK), (bp->b_flags & B_READ) == 0,
+		    &xbdreq->req_gntref[seg]))) {
+			printf("%s: %s: xengnt_grant_access failed",
+			    device_xname(sc->sc_dksc.sc_dev), __func__);
+			error = EFAULT;
+			goto out;
+		}
+
 		req->seg[seg].gref = xbdreq->req_gntref[seg];
-		seg++;
-		KASSERT(seg <= BLKIF_MAX_SEGMENTS_PER_REQUEST);
-		va += PAGE_SIZE;
-		off = 0;
-		bcount -= nbytes;
 	}
-	xbdreq->req_nr_segments = req->nr_segments = seg;
+	req->nr_segments = seg;
 	sc->sc_ring.req_prod_pvt++;
 
-out:
 	RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&sc->sc_ring, notify);
 	if (notify)
 		hypervisor_notify_via_evtchn(sc->sc_evtchn);
+
+out:
 	splx(s);	/* XXXSMP */
-err:
 	return error;
 }
 

Reply via email to