Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/dev ld(4): Block requests while suspended until resumed.
details: https://anonhg.NetBSD.org/src/rev/022a1821d002
branches: trunk
changeset: 983617:022a1821d002
user: riastradh <riastradh%NetBSD.org@localhost>
date: Sun May 30 11:24:02 2021 +0000
description:
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 122e1f62751d -r 022a1821d002 sys/dev/ld.c
--- a/sys/dev/ld.c Sun May 30 10:39:41 2021 +0000
+++ b/sys/dev/ld.c Sun May 30 11:24:02 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ld.c,v 1.111 2020/08/02 01:17:56 riastradh Exp $ */
+/* $NetBSD: ld.c,v 1.112 2021/05/30 11:24:02 riastradh 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.111 2020/08/02 01:17:56 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.112 2021/05/30 11:24:02 riastradh 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 *);
@@ -166,7 +167,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");
@@ -276,7 +278,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 */
@@ -438,17 +488,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 122e1f62751d -r 022a1821d002 sys/dev/ldvar.h
--- a/sys/dev/ldvar.h Sun May 30 10:39:41 2021 +0000
+++ b/sys/dev/ldvar.h Sun May 30 11:24:02 2021 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: ldvar.h,v 1.34 2020/08/02 01:17:56 riastradh Exp $ */
+/* $NetBSD: ldvar.h,v 1.35 2021/05/30 11:24:02 riastradh Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
@@ -70,6 +70,7 @@
#define LDF_UNUSED0 0x020 /* was LDF_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