Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/dkwedge Make dk(4) device mpsafe.



details:   https://anonhg.NetBSD.org/src/rev/6030bcb5cb70
branches:  trunk
changeset: 819763:6030bcb5cb70
user:      mlelstv <mlelstv%NetBSD.org@localhost>
date:      Fri Dec 16 15:06:39 2016 +0000

description:
Make dk(4) device mpsafe.

diffstat:

 sys/dev/dkwedge/dk.c |  84 ++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 56 insertions(+), 28 deletions(-)

diffs (259 lines):

diff -r e551c7f38cf3 -r 6030bcb5cb70 sys/dev/dkwedge/dk.c
--- a/sys/dev/dkwedge/dk.c      Fri Dec 16 15:00:52 2016 +0000
+++ b/sys/dev/dkwedge/dk.c      Fri Dec 16 15:06:39 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: dk.c,v 1.91 2016/05/29 13:11:21 mlelstv Exp $  */
+/*     $NetBSD: dk.c,v 1.92 2016/12/16 15:06:39 mlelstv Exp $  */
 
 /*-
  * Copyright (c) 2004, 2005, 2006, 2007 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.91 2016/05/29 13:11:21 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: dk.c,v 1.92 2016/12/16 15:06:39 mlelstv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_dkwedge.h"
@@ -86,8 +86,10 @@
        struct bufq_state *sc_bufq;     /* buffer queue */
        struct callout  sc_restart_ch;  /* callout to restart I/O */
 
+       kmutex_t        sc_iolock;
+       kcondvar_t      sc_dkdrn;
        u_int           sc_iopend;      /* I/Os pending */
-       int             sc_flags;       /* flags (splbio) */
+       int             sc_flags;       /* flags (sc_iolock) */
 };
 
 #define        DK_F_WAIT_DRAIN         0x0001  /* waiting for I/O to drain */
@@ -123,7 +125,7 @@
        .d_dump = dkdump,
        .d_psize = dksize,
        .d_discard = dkdiscard,
-       .d_flag = D_DISK
+       .d_flag = D_DISK | D_MPSAFE
 };
 
 const struct cdevsw dk_cdevsw = {
@@ -138,7 +140,7 @@
        .d_mmap = nommap,
        .d_kqfilter = nokqfilter,
        .d_discard = dkdiscard,
-       .d_flag = D_DISK
+       .d_flag = D_DISK | D_MPSAFE
 };
 
 static struct dkwedge_softc **dkwedges;
@@ -185,16 +187,17 @@
  * dkwedge_wait_drain:
  *
  *     Wait for I/O on the wedge to drain.
- *     NOTE: Must be called at splbio()!
  */
 static void
 dkwedge_wait_drain(struct dkwedge_softc *sc)
 {
 
+       mutex_enter(&sc->sc_iolock);
        while (sc->sc_iopend != 0) {
                sc->sc_flags |= DK_F_WAIT_DRAIN;
-               (void) tsleep(&sc->sc_iopend, PRIBIO, "dkdrn", 0);
+               cv_wait(&sc->sc_dkdrn, &sc->sc_iolock);
        }
+       mutex_exit(&sc->sc_iolock);
 }
 
 /*
@@ -325,6 +328,9 @@
        callout_init(&sc->sc_restart_ch, 0);
        callout_setfunc(&sc->sc_restart_ch, dkrestart, sc);
 
+       mutex_init(&sc->sc_iolock, MUTEX_DEFAULT, IPL_BIO);
+       cv_init(&sc->sc_dkdrn, "dkdrn");
+
        /*
         * Wedge will be added; increment the wedge count for the parent.
         * Only allow this to happend if RAW_PART is the only thing open.
@@ -568,7 +574,7 @@
 {
        struct dkwedge_softc *sc = NULL;
        u_int unit;
-       int bmaj, cmaj, rc, s;
+       int bmaj, cmaj, rc;
 
        rw_enter(&dkwedges_lock, RW_WRITER);
        for (unit = 0; unit < ndkwedges; unit++) {
@@ -600,10 +606,8 @@
         * state of the wedge is not RUNNING.  Once we've done
         * that, wait for any other pending I/O to complete.
         */
-       s = splbio();
        dkstart(sc);
        dkwedge_wait_drain(sc);
-       splx(s);
 
        /* Nuke the vnodes for any open instances. */
        vdevgone(bmaj, unit, unit, VBLK);
@@ -635,6 +639,9 @@
        sc->sc_state = DKW_STATE_DEAD;
        rw_exit(&dkwedges_lock);
 
+       mutex_destroy(&sc->sc_iolock);
+       cv_destroy(&sc->sc_dkdrn);
+
        free(sc, M_DKWEDGE);
 
        return 0;
@@ -1206,7 +1213,6 @@
 {
        struct dkwedge_softc *sc = dkwedge_lookup(bp->b_dev);
        uint64_t p_size, p_offset;
-       int s;
 
        if (sc == NULL) {
                bp->b_error = ENODEV;
@@ -1234,11 +1240,12 @@
        bp->b_rawblkno = bp->b_blkno + p_offset;
 
        /* Place it in the queue and start I/O on the unit. */
-       s = splbio();
+       mutex_enter(&sc->sc_iolock);
        sc->sc_iopend++;
        bufq_put(sc->sc_bufq, bp);
+       mutex_exit(&sc->sc_iolock);
+
        dkstart(sc);
-       splx(s);
        return;
 
  done:
@@ -1250,7 +1257,6 @@
  * dkstart:
  *
  *     Start I/O that has been enqueued on the wedge.
- *     NOTE: Must be called at splbio()!
  */
 static void
 dkstart(struct dkwedge_softc *sc)
@@ -1258,36 +1264,58 @@
        struct vnode *vp;
        struct buf *bp, *nbp;
 
+       mutex_enter(&sc->sc_iolock);
+
        /* Do as much work as has been enqueued. */
        while ((bp = bufq_peek(sc->sc_bufq)) != NULL) {
+
                if (sc->sc_state != DKW_STATE_RUNNING) {
                        (void) bufq_get(sc->sc_bufq);
                        if (sc->sc_iopend-- == 1 &&
                            (sc->sc_flags & DK_F_WAIT_DRAIN) != 0) {
                                sc->sc_flags &= ~DK_F_WAIT_DRAIN;
-                               wakeup(&sc->sc_iopend);
+                               cv_broadcast(&sc->sc_dkdrn);
                        }
+                       mutex_exit(&sc->sc_iolock);
                        bp->b_error = ENXIO;
                        bp->b_resid = bp->b_bcount;
                        biodone(bp);
+                       mutex_enter(&sc->sc_iolock);
+                       continue;
                }
 
-               /* Instrumentation. */
-               disk_busy(&sc->sc_dk);
-
+               /* fetch an I/O buf with sc_iolock dropped */
+               mutex_exit(&sc->sc_iolock);
                nbp = getiobuf(sc->sc_parent->dk_rawvp, false);
+               mutex_enter(&sc->sc_iolock);
                if (nbp == NULL) {
                        /*
                         * No resources to run this request; leave the
                         * buffer queued up, and schedule a timer to
                         * restart the queue in 1/2 a second.
                         */
-                       disk_unbusy(&sc->sc_dk, 0, bp->b_flags & B_READ);
                        callout_schedule(&sc->sc_restart_ch, hz / 2);
-                       return;
+                       break;
                }
 
-               (void) bufq_get(sc->sc_bufq);
+               /*
+                * fetch buf, this can fail if another thread
+                * has already processed the queue, it can also
+                * return a completely different buf.
+                */
+               bp = bufq_get(sc->sc_bufq);
+               if (bp == NULL) {
+                       mutex_exit(&sc->sc_iolock);
+                       putiobuf(nbp);
+                       mutex_enter(&sc->sc_iolock);
+                       continue;
+               }
+
+               /* Instrumentation. */
+               disk_busy(&sc->sc_dk);
+
+               /* release lock for VOP_STRATEGY */
+               mutex_exit(&sc->sc_iolock);
 
                nbp->b_data = bp->b_data;
                nbp->b_flags = bp->b_flags;
@@ -1308,7 +1336,11 @@
                        mutex_exit(vp->v_interlock);
                }
                VOP_STRATEGY(vp, nbp);
+
+               mutex_enter(&sc->sc_iolock);
        }
+
+       mutex_exit(&sc->sc_iolock);
 }
 
 /*
@@ -1322,26 +1354,25 @@
        struct buf *obp = bp->b_private;
        struct dkwedge_softc *sc = dkwedge_lookup(obp->b_dev);
 
-       int s = splbio();
-
        if (bp->b_error != 0)
                obp->b_error = bp->b_error;
        obp->b_resid = bp->b_resid;
        putiobuf(bp);
 
+       mutex_enter(&sc->sc_iolock);
        if (sc->sc_iopend-- == 1 && (sc->sc_flags & DK_F_WAIT_DRAIN) != 0) {
                sc->sc_flags &= ~DK_F_WAIT_DRAIN;
-               wakeup(&sc->sc_iopend);
+               cv_broadcast(&sc->sc_dkdrn);
        }
 
        disk_unbusy(&sc->sc_dk, obp->b_bcount - obp->b_resid,
            obp->b_flags & B_READ);
+       mutex_exit(&sc->sc_iolock);
 
        biodone(obp);
 
        /* Kick the queue in case there is more work we can do. */
        dkstart(sc);
-       splx(s);
 }
 
 /*
@@ -1354,11 +1385,8 @@
 dkrestart(void *v)
 {
        struct dkwedge_softc *sc = v;
-       int s;
 
-       s = splbio();
        dkstart(sc);
-       splx(s);
 }
 
 /*



Home | Main Index | Thread Index | Old Index