# HG changeset patch # User Taylor R Campbell # Date 1590176371 0 # Fri May 22 19:39:31 2020 +0000 # Branch trunk # Node ID 13c0c4ce491e63a6c0625dacdadbef70a7b489d7 # Parent 1ed1cd6fab61c6d6fab72eec14f71b46f7f8a352 # EXP-Topic riastradh-sdmmc-task-fixes Remove unnecessary wait in ldbegindetach. Like disk_begindetach, ldbegindetach only commits to detaching but doesn't wait for existing xfers to drain; it is up to the driver to abort them, once we are committed, and then ldenddetach to wait for them to drain. diff -r 1ed1cd6fab61 -r 13c0c4ce491e sys/dev/ld.c --- a/sys/dev/ld.c Fri May 22 02:44:03 2020 +0000 +++ b/sys/dev/ld.c Fri May 22 19:39:31 2020 +0000 @@ -189,26 +189,27 @@ int ldbegindetach(struct ld_softc *sc, int flags) { struct dk_softc *dksc = &sc->sc_dksc; - int rv = 0; + int error; + /* If we never attached properly, no problem with detaching. */ if ((sc->sc_flags & LDF_ENABLED) == 0) - return (0); + return 0; - rv = disk_begindetach(&dksc->sc_dkdev, ld_lastclose, dksc->sc_dev, flags); + /* + * If the disk is still open, back out before we commit to + * detaching. + */ + error = disk_begindetach(&dksc->sc_dkdev, ld_lastclose, dksc->sc_dev, + flags); + if (error) + return error; - if (rv != 0) - return rv; - + /* We are now committed to detaching. Prevent new xfers. */ mutex_enter(&sc->sc_mutex); sc->sc_maxqueuecnt = 0; - - while (sc->sc_queuecnt > 0) { - sc->sc_flags |= LDF_DRAIN; - cv_wait(&sc->sc_drain, &sc->sc_mutex); - } mutex_exit(&sc->sc_mutex); - return (rv); + return 0; } void @@ -220,12 +221,17 @@ ldenddetach(struct ld_softc *sc) if ((sc->sc_flags & LDF_ENABLED) == 0) return; + /* Wait for commands queued with the hardware to complete. */ mutex_enter(&sc->sc_mutex); - - /* Wait for commands queued with the hardware to complete. */ - if (sc->sc_queuecnt != 0) { - if (cv_timedwait(&sc->sc_drain, &sc->sc_mutex, 30 * hz)) + while (sc->sc_queuecnt > 0) { + if (cv_timedwait(&sc->sc_drain, &sc->sc_mutex, 30 * hz)) { + /* + * XXX This seems like a recipe for crashing on + * use after free... + */ printf("%s: not drained\n", dksc->sc_xname); + break; + } } mutex_exit(&sc->sc_mutex); @@ -467,10 +473,7 @@ lddone(struct ld_softc *sc, struct buf * mutex_enter(&sc->sc_mutex); if (--sc->sc_queuecnt <= sc->sc_maxqueuecnt) { - if ((sc->sc_flags & LDF_DRAIN) != 0) { - sc->sc_flags &= ~LDF_DRAIN; - cv_broadcast(&sc->sc_drain); - } + cv_broadcast(&sc->sc_drain); mutex_exit(&sc->sc_mutex); dk_start(dksc, NULL); } else diff -r 1ed1cd6fab61 -r 13c0c4ce491e sys/dev/ldvar.h --- a/sys/dev/ldvar.h Fri May 22 02:44:03 2020 +0000 +++ b/sys/dev/ldvar.h Fri May 22 19:39:31 2020 +0000 @@ -67,7 +67,7 @@ struct ld_softc { /* sc_flags */ #define LDF_ENABLED 0x001 /* device enabled */ -#define LDF_DRAIN 0x020 /* maxqueuecnt has changed; drain */ +#define LDF_UNUSED0 0x020 /* was LDF_DRAIN */ #define LDF_NO_RND 0x040 /* do not attach rnd source */ #define LDF_MPSAFE 0x080 /* backend is MPSAFE */