Sun May 30 11:24:02 2021 UTC ()
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.


(riastradh)
diff -r1.111 -r1.112 src/sys/dev/ld.c
diff -r1.34 -r1.35 src/sys/dev/ldvar.h

cvs diff -r1.111 -r1.112 src/sys/dev/ld.c (expand / switch to unified diff)

--- src/sys/dev/ld.c 2020/08/02 01:17:56 1.111
+++ src/sys/dev/ld.c 2021/05/30 11:24:02 1.112
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ld.c,v 1.111 2020/08/02 01:17:56 riastradh Exp $ */ 1/* $NetBSD: ld.c,v 1.112 2021/05/30 11:24:02 riastradh Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc. 4 * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran and Charles M. Hannum. 8 * by Andrew Doran and Charles M. Hannum.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -24,27 +24,27 @@ @@ -24,27 +24,27 @@
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE. 29 * POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32/* 32/*
33 * Disk driver for use by RAID controllers. 33 * Disk driver for use by RAID controllers.
34 */ 34 */
35 35
36#include <sys/cdefs.h> 36#include <sys/cdefs.h>
37__KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.111 2020/08/02 01:17:56 riastradh Exp $"); 37__KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.112 2021/05/30 11:24:02 riastradh Exp $");
38 38
39#include <sys/param.h> 39#include <sys/param.h>
40#include <sys/systm.h> 40#include <sys/systm.h>
41#include <sys/kernel.h> 41#include <sys/kernel.h>
42#include <sys/device.h> 42#include <sys/device.h>
43#include <sys/queue.h> 43#include <sys/queue.h>
44#include <sys/proc.h> 44#include <sys/proc.h>
45#include <sys/buf.h> 45#include <sys/buf.h>
46#include <sys/bufq.h> 46#include <sys/bufq.h>
47#include <sys/endian.h> 47#include <sys/endian.h>
48#include <sys/disklabel.h> 48#include <sys/disklabel.h>
49#include <sys/disk.h> 49#include <sys/disk.h>
50#include <sys/dkio.h> 50#include <sys/dkio.h>
@@ -53,26 +53,27 @@ __KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.111 @@ -53,26 +53,27 @@ __KERNEL_RCSID(0, "$NetBSD: ld.c,v 1.111
53#include <sys/fcntl.h> 53#include <sys/fcntl.h>
54#include <sys/vnode.h> 54#include <sys/vnode.h>
55#include <sys/syslog.h> 55#include <sys/syslog.h>
56#include <sys/mutex.h> 56#include <sys/mutex.h>
57#include <sys/module.h> 57#include <sys/module.h>
58#include <sys/reboot.h> 58#include <sys/reboot.h>
59 59
60#include <dev/ldvar.h> 60#include <dev/ldvar.h>
61 61
62#include "ioconf.h" 62#include "ioconf.h"
63 63
64static void ldminphys(struct buf *bp); 64static void ldminphys(struct buf *bp);
65static bool ld_suspend(device_t, const pmf_qual_t *); 65static bool ld_suspend(device_t, const pmf_qual_t *);
 66static bool ld_resume(device_t, const pmf_qual_t *);
66static bool ld_shutdown(device_t, int); 67static bool ld_shutdown(device_t, int);
67static int ld_diskstart(device_t, struct buf *bp); 68static int ld_diskstart(device_t, struct buf *bp);
68static void ld_iosize(device_t, int *); 69static void ld_iosize(device_t, int *);
69static int ld_dumpblocks(device_t, void *, daddr_t, int); 70static int ld_dumpblocks(device_t, void *, daddr_t, int);
70static void ld_fake_geometry(struct ld_softc *); 71static void ld_fake_geometry(struct ld_softc *);
71static void ld_set_geometry(struct ld_softc *); 72static void ld_set_geometry(struct ld_softc *);
72static void ld_config_interrupts (device_t); 73static void ld_config_interrupts (device_t);
73static int ld_lastclose(device_t); 74static int ld_lastclose(device_t);
74static int ld_discard(device_t, off_t, off_t); 75static int ld_discard(device_t, off_t, off_t);
75static int ld_flush(device_t, bool); 76static int ld_flush(device_t, bool);
76 77
77static dev_type_open(ldopen); 78static dev_type_open(ldopen);
78static dev_type_close(ldclose); 79static dev_type_close(ldclose);
@@ -156,27 +157,28 @@ ldattach(struct ld_softc *sc, const char @@ -156,27 +157,28 @@ ldattach(struct ld_softc *sc, const char
156 sc->sc_disksize512 = sc->sc_secperunit * sc->sc_secsize / DEV_BSIZE; 157 sc->sc_disksize512 = sc->sc_secperunit * sc->sc_secsize / DEV_BSIZE;
157 158
158 if (sc->sc_flags & LDF_NO_RND) 159 if (sc->sc_flags & LDF_NO_RND)
159 dksc->sc_flags |= DKF_NO_RND; 160 dksc->sc_flags |= DKF_NO_RND;
160 161
161 /* Attach dk and disk subsystems */ 162 /* Attach dk and disk subsystems */
162 dk_attach(dksc); 163 dk_attach(dksc);
163 disk_attach(&dksc->sc_dkdev); 164 disk_attach(&dksc->sc_dkdev);
164 ld_set_geometry(sc); 165 ld_set_geometry(sc);
165 166
166 bufq_alloc(&dksc->sc_bufq, default_strategy, BUFQ_SORT_RAWBLOCK); 167 bufq_alloc(&dksc->sc_bufq, default_strategy, BUFQ_SORT_RAWBLOCK);
167 168
168 /* Register with PMF */ 169 /* Register with PMF */
169 if (!pmf_device_register1(dksc->sc_dev, ld_suspend, NULL, ld_shutdown)) 170 if (!pmf_device_register1(dksc->sc_dev, ld_suspend, ld_resume,
 171 ld_shutdown))
170 aprint_error_dev(dksc->sc_dev, 172 aprint_error_dev(dksc->sc_dev,
171 "couldn't establish power handler\n"); 173 "couldn't establish power handler\n");
172 174
173 /* Discover wedges on this disk. */ 175 /* Discover wedges on this disk. */
174 config_interrupts(sc->sc_dv, ld_config_interrupts); 176 config_interrupts(sc->sc_dv, ld_config_interrupts);
175} 177}
176 178
177int 179int
178ldadjqparam(struct ld_softc *sc, int xmax) 180ldadjqparam(struct ld_softc *sc, int xmax)
179{ 181{
180 182
181 mutex_enter(&sc->sc_mutex); 183 mutex_enter(&sc->sc_mutex);
182 sc->sc_maxqueuecnt = xmax; 184 sc->sc_maxqueuecnt = xmax;
@@ -266,27 +268,75 @@ ldenddetach(struct ld_softc *sc) @@ -266,27 +268,75 @@ ldenddetach(struct ld_softc *sc)
266 * XXX perspective. 268 * XXX perspective.
267 */ 269 */
268#if 0 270#if 0
269 ld_flush(dksc->sc_dev, false); 271 ld_flush(dksc->sc_dev, false);
270#endif 272#endif
271 cv_destroy(&sc->sc_drain); 273 cv_destroy(&sc->sc_drain);
272 mutex_destroy(&sc->sc_mutex); 274 mutex_destroy(&sc->sc_mutex);
273} 275}
274 276
275/* ARGSUSED */ 277/* ARGSUSED */
276static bool 278static bool
277ld_suspend(device_t dev, const pmf_qual_t *qual) 279ld_suspend(device_t dev, const pmf_qual_t *qual)
278{ 280{
279 return ld_shutdown(dev, 0); 281 struct ld_softc *sc = device_private(dev);
 282 int queuecnt;
 283 bool ok = false;
 284
 285 /* Block new requests and wait for outstanding requests to drain. */
 286 mutex_enter(&sc->sc_mutex);
 287 KASSERT((sc->sc_flags & LDF_SUSPEND) == 0);
 288 sc->sc_flags |= LDF_SUSPEND;
 289 while ((queuecnt = sc->sc_queuecnt) > 0) {
 290 if (cv_timedwait(&sc->sc_drain, &sc->sc_mutex, 30 * hz))
 291 break;
 292 }
 293 mutex_exit(&sc->sc_mutex);
 294
 295 /* Block suspend if we couldn't drain everything in 30sec. */
 296 if (queuecnt > 0) {
 297 device_printf(dev, "timeout draining buffers\n");
 298 goto out;
 299 }
 300
 301 /* Flush cache before we lose power. If we can't, block suspend. */
 302 if (ld_flush(dev, /*poll*/false) != 0) {
 303 device_printf(dev, "failed to flush cache\n");
 304 goto out;
 305 }
 306
 307 /* Success! */
 308 ok = true;
 309
 310out: if (!ok)
 311 (void)ld_resume(dev, qual);
 312 return ok;
 313}
 314
 315static bool
 316ld_resume(device_t dev, const pmf_qual_t *qual)
 317{
 318 struct ld_softc *sc = device_private(dev);
 319
 320 /* Allow new requests to come in. */
 321 mutex_enter(&sc->sc_mutex);
 322 KASSERT(sc->sc_flags & LDF_SUSPEND);
 323 sc->sc_flags &= ~LDF_SUSPEND;
 324 mutex_exit(&sc->sc_mutex);
 325
 326 /* Restart any pending queued requests. */
 327 dk_start(&sc->sc_dksc, NULL);
 328
 329 return true;
280} 330}
281 331
282/* ARGSUSED */ 332/* ARGSUSED */
283static bool 333static bool
284ld_shutdown(device_t dev, int flags) 334ld_shutdown(device_t dev, int flags)
285{ 335{
286 if ((flags & RB_NOSYNC) == 0 && ld_flush(dev, true) != 0) 336 if ((flags & RB_NOSYNC) == 0 && ld_flush(dev, true) != 0)
287 return false; 337 return false;
288 338
289 return true; 339 return true;
290} 340}
291 341
292/* ARGSUSED */ 342/* ARGSUSED */
@@ -428,37 +478,44 @@ ldstrategy(struct buf *bp) @@ -428,37 +478,44 @@ ldstrategy(struct buf *bp)
428 unit = DISKUNIT(bp->b_dev); 478 unit = DISKUNIT(bp->b_dev);
429 sc = device_lookup_private(&ld_cd, unit); 479 sc = device_lookup_private(&ld_cd, unit);
430 dksc = &sc->sc_dksc; 480 dksc = &sc->sc_dksc;
431 481
432 dk_strategy(dksc, bp); 482 dk_strategy(dksc, bp);
433} 483}
434 484
435static int 485static int
436ld_diskstart(device_t dev, struct buf *bp) 486ld_diskstart(device_t dev, struct buf *bp)
437{ 487{
438 struct ld_softc *sc = device_private(dev); 488 struct ld_softc *sc = device_private(dev);
439 int error; 489 int error;
440 490
441 if (sc->sc_queuecnt >= sc->sc_maxqueuecnt) 491 if (sc->sc_queuecnt >= sc->sc_maxqueuecnt ||
 492 sc->sc_flags & LDF_SUSPEND) {
 493 if (sc->sc_flags & LDF_SUSPEND)
 494 aprint_debug_dev(dev, "i/o blocked while suspended\n");
442 return EAGAIN; 495 return EAGAIN;
 496 }
443 497
444 if ((sc->sc_flags & LDF_MPSAFE) == 0) 498 if ((sc->sc_flags & LDF_MPSAFE) == 0)
445 KERNEL_LOCK(1, curlwp); 499 KERNEL_LOCK(1, curlwp);
446 500
447 mutex_enter(&sc->sc_mutex); 501 mutex_enter(&sc->sc_mutex);
448 502
449 if (sc->sc_queuecnt >= sc->sc_maxqueuecnt) 503 if (sc->sc_queuecnt >= sc->sc_maxqueuecnt ||
 504 sc->sc_flags & LDF_SUSPEND) {
 505 if (sc->sc_flags & LDF_SUSPEND)
 506 aprint_debug_dev(dev, "i/o blocked while suspended\n");
450 error = EAGAIN; 507 error = EAGAIN;
451 else { 508 } else {
452 error = (*sc->sc_start)(sc, bp); 509 error = (*sc->sc_start)(sc, bp);
453 if (error == 0) 510 if (error == 0)
454 sc->sc_queuecnt++; 511 sc->sc_queuecnt++;
455 } 512 }
456 513
457 mutex_exit(&sc->sc_mutex); 514 mutex_exit(&sc->sc_mutex);
458 515
459 if ((sc->sc_flags & LDF_MPSAFE) == 0) 516 if ((sc->sc_flags & LDF_MPSAFE) == 0)
460 KERNEL_UNLOCK_ONE(curlwp); 517 KERNEL_UNLOCK_ONE(curlwp);
461 518
462 return error; 519 return error;
463} 520}
464 521

cvs diff -r1.34 -r1.35 src/sys/dev/ldvar.h (expand / switch to unified diff)

--- src/sys/dev/ldvar.h 2020/08/02 01:17:56 1.34
+++ src/sys/dev/ldvar.h 2021/05/30 11:24:02 1.35
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: ldvar.h,v 1.34 2020/08/02 01:17:56 riastradh Exp $ */ 1/* $NetBSD: ldvar.h,v 1.35 2021/05/30 11:24:02 riastradh Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * This code is derived from software contributed to The NetBSD Foundation 7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran. 8 * by Andrew Doran.
9 * 9 *
10 * Redistribution and use in source and binary forms, with or without 10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions 11 * modification, are permitted provided that the following conditions
12 * are met: 12 * are met:
13 * 1. Redistributions of source code must retain the above copyright 13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer. 14 * notice, this list of conditions and the following disclaimer.
@@ -60,22 +60,23 @@ struct ld_softc { @@ -60,22 +60,23 @@ struct ld_softc {
60 char *sc_typename; /* inquiry data */ 60 char *sc_typename; /* inquiry data */
61 61
62 int (*sc_dump)(struct ld_softc *, void *, int, int); 62 int (*sc_dump)(struct ld_softc *, void *, int, int);
63 int (*sc_ioctl)(struct ld_softc *, u_long, void *, int32_t, bool); 63 int (*sc_ioctl)(struct ld_softc *, u_long, void *, int32_t, bool);
64 int (*sc_start)(struct ld_softc *, struct buf *); 64 int (*sc_start)(struct ld_softc *, struct buf *);
65 int (*sc_discard)(struct ld_softc *, struct buf *); 65 int (*sc_discard)(struct ld_softc *, struct buf *);
66}; 66};
67 67
68/* sc_flags */ 68/* sc_flags */
69#define LDF_ENABLED 0x001 /* device enabled */ 69#define LDF_ENABLED 0x001 /* device enabled */
70#define LDF_UNUSED0 0x020 /* was LDF_DRAIN */ 70#define LDF_UNUSED0 0x020 /* was LDF_DRAIN */
71#define LDF_NO_RND 0x040 /* do not attach rnd source */ 71#define LDF_NO_RND 0x040 /* do not attach rnd source */
72#define LDF_MPSAFE 0x080 /* backend is MPSAFE */ 72#define LDF_MPSAFE 0x080 /* backend is MPSAFE */
 73#define LDF_SUSPEND 0x100 /* disk is suspended until resume */
73 74
74int ldadjqparam(struct ld_softc *, int); 75int ldadjqparam(struct ld_softc *, int);
75void ldattach(struct ld_softc *, const char *); 76void ldattach(struct ld_softc *, const char *);
76int ldbegindetach(struct ld_softc *, int); 77int ldbegindetach(struct ld_softc *, int);
77void ldenddetach(struct ld_softc *); 78void ldenddetach(struct ld_softc *);
78void lddone(struct ld_softc *, struct buf *); 79void lddone(struct ld_softc *, struct buf *);
79void lddiscardend(struct ld_softc *, struct buf *); 80void lddiscardend(struct ld_softc *, struct buf *);
80 81
81#endif /* !_DEV_LDVAR_H_ */ 82#endif /* !_DEV_LDVAR_H_ */