Source-Changes-HG archive

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

[src/netbsd-9]: src/sys/dev Pull up following revision(s) (requested by riast...



details:   https://anonhg.NetBSD.org/src/rev/b01b7ed8b2f2
branches:  netbsd-9
changeset: 984098:b01b7ed8b2f2
user:      martin <martin%NetBSD.org@localhost>
date:      Mon Jun 21 17:23:13 2021 +0000

description:
Pull up following revision(s) (requested by riastradh in ticket #1304):

        sys/dev/ldvar.h: revision 1.35
        sys/dev/ld.c: revision 1.112

ld(4): Block requests while suspended until resumed.

Otherwise nothing stops us from continuing to feed I/O to the disk
controller when it expects that the queues are quiesced as it pokes
registers to change its power states.  Fixes resume during disk
activity on my T480 with nvme.

diffstat:

 sys/dev/ld.c    |  71 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 sys/dev/ldvar.h |   3 +-
 2 files changed, 66 insertions(+), 8 deletions(-)

diffs (138 lines):

diff -r c00822b87574 -r b01b7ed8b2f2 sys/dev/ld.c
--- a/sys/dev/ld.c      Mon Jun 21 17:19:55 2021 +0000
+++ b/sys/dev/ld.c      Mon Jun 21 17:23:13 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ld.c,v 1.106.4.2 2020/03/21 15:52:09 martin Exp $      */
+/*     $NetBSD: ld.c,v 1.106.4.3 2021/06/21 17:23:13 martin Exp $      */
 
 /*-
  * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.106.4.2 2020/03/21 15:52:09 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.106.4.3 2021/06/21 17:23:13 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -63,6 +63,7 @@
 
 static void    ldminphys(struct buf *bp);
 static bool    ld_suspend(device_t, const pmf_qual_t *);
+static bool    ld_resume(device_t, const pmf_qual_t *);
 static bool    ld_shutdown(device_t, int);
 static int     ld_diskstart(device_t, struct buf *bp);
 static void    ld_iosize(device_t, int *);
@@ -160,7 +161,8 @@
        bufq_alloc(&dksc->sc_bufq, default_strategy, BUFQ_SORT_RAWBLOCK);
 
        /* Register with PMF */
-       if (!pmf_device_register1(dksc->sc_dev, ld_suspend, NULL, ld_shutdown))
+       if (!pmf_device_register1(dksc->sc_dev, ld_suspend, ld_resume,
+               ld_shutdown))
                aprint_error_dev(dksc->sc_dev,
                    "couldn't establish power handler\n");
 
@@ -266,7 +268,55 @@
 static bool
 ld_suspend(device_t dev, const pmf_qual_t *qual)
 {
-       return ld_shutdown(dev, 0);
+       struct ld_softc *sc = device_private(dev);
+       int queuecnt;
+       bool ok = false;
+
+       /* Block new requests and wait for outstanding requests to drain.  */
+       mutex_enter(&sc->sc_mutex);
+       KASSERT((sc->sc_flags & LDF_SUSPEND) == 0);
+       sc->sc_flags |= LDF_SUSPEND;
+       while ((queuecnt = sc->sc_queuecnt) > 0) {
+               if (cv_timedwait(&sc->sc_drain, &sc->sc_mutex, 30 * hz))
+                       break;
+       }
+       mutex_exit(&sc->sc_mutex);
+
+       /* Block suspend if we couldn't drain everything in 30sec.  */
+       if (queuecnt > 0) {
+               device_printf(dev, "timeout draining buffers\n");
+               goto out;
+       }
+
+       /* Flush cache before we lose power.  If we can't, block suspend.  */
+       if (ld_flush(dev, /*poll*/false) != 0) {
+               device_printf(dev, "failed to flush cache\n");
+               goto out;
+       }
+
+       /* Success!  */
+       ok = true;
+
+out:   if (!ok)
+               (void)ld_resume(dev, qual);
+       return ok;
+}
+
+static bool
+ld_resume(device_t dev, const pmf_qual_t *qual)
+{
+       struct ld_softc *sc = device_private(dev);
+
+       /* Allow new requests to come in.  */
+       mutex_enter(&sc->sc_mutex);
+       KASSERT(sc->sc_flags & LDF_SUSPEND);
+       sc->sc_flags &= ~LDF_SUSPEND;
+       mutex_exit(&sc->sc_mutex);
+
+       /* Restart any pending queued requests.  */
+       dk_start(&sc->sc_dksc, NULL);
+
+       return true;
 }
 
 /* ARGSUSED */
@@ -428,17 +478,24 @@
        struct ld_softc *sc = device_private(dev);
        int error;
 
-       if (sc->sc_queuecnt >= sc->sc_maxqueuecnt)
+       if (sc->sc_queuecnt >= sc->sc_maxqueuecnt ||
+           sc->sc_flags & LDF_SUSPEND) {
+               if (sc->sc_flags & LDF_SUSPEND)
+                       aprint_debug_dev(dev, "i/o blocked while suspended\n");
                return EAGAIN;
+       }
 
        if ((sc->sc_flags & LDF_MPSAFE) == 0)
                KERNEL_LOCK(1, curlwp);
 
        mutex_enter(&sc->sc_mutex);
 
-       if (sc->sc_queuecnt >= sc->sc_maxqueuecnt)
+       if (sc->sc_queuecnt >= sc->sc_maxqueuecnt ||
+           sc->sc_flags & LDF_SUSPEND) {
+               if (sc->sc_flags & LDF_SUSPEND)
+                       aprint_debug_dev(dev, "i/o blocked while suspended\n");
                error = EAGAIN;
-       else {
+       } else {
                error = (*sc->sc_start)(sc, bp);
                if (error == 0)
                        sc->sc_queuecnt++;
diff -r c00822b87574 -r b01b7ed8b2f2 sys/dev/ldvar.h
--- a/sys/dev/ldvar.h   Mon Jun 21 17:19:55 2021 +0000
+++ b/sys/dev/ldvar.h   Mon Jun 21 17:23:13 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ldvar.h,v 1.33 2019/03/19 07:01:14 mlelstv Exp $       */
+/*     $NetBSD: ldvar.h,v 1.33.4.1 2021/06/21 17:23:13 martin Exp $    */
 
 /*-
  * Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -70,6 +70,7 @@
 #define        LDF_DRAIN       0x020           /* maxqueuecnt has changed; drain */
 #define        LDF_NO_RND      0x040           /* do not attach rnd source */
 #define        LDF_MPSAFE      0x080           /* backend is MPSAFE */
+#define        LDF_SUSPEND     0x100           /* disk is suspended until resume */
 
 int    ldadjqparam(struct ld_softc *, int);
 void   ldattach(struct ld_softc *, const char *);



Home | Main Index | Thread Index | Old Index