Source-Changes-HG archive

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

[src/jdolecek-ncq]: src/sys/dev/ata change wd_standby() to remove the ata_cha...



details:   https://anonhg.NetBSD.org/src/rev/07a92edc3525
branches:  jdolecek-ncq
changeset: 822939:07a92edc3525
user:      jdolecek <jdolecek%NetBSD.org@localhost>
date:      Fri Jun 23 22:11:13 2017 +0000

description:
change wd_standby() to remove the ata_channel_start() call - the purpose
of that particular command is to make the drive idle

fix locking bug in wddetach() exposed by calling ata_channel_start()
in wd_standby() - move wd_standby() call out of the section protected
by drive mutex, to avoid lock against itself should it need to get
the lock

change wd_flushcache() to only call ata_channel_start() when called from
the ioctl; particularly, don't call it when suspending, closing, or on shutdown

diffstat:

 sys/dev/ata/wd.c |  24 +++++++++++++-----------
 1 files changed, 13 insertions(+), 11 deletions(-)

diffs (101 lines):

diff -r daf5cd436c4a -r 07a92edc3525 sys/dev/ata/wd.c
--- a/sys/dev/ata/wd.c  Fri Jun 23 20:40:51 2017 +0000
+++ b/sys/dev/ata/wd.c  Fri Jun 23 22:11:13 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: wd.c,v 1.428.2.20 2017/06/23 20:40:51 jdolecek Exp $ */
+/*     $NetBSD: wd.c,v 1.428.2.21 2017/06/23 22:11:13 jdolecek Exp $ */
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -54,7 +54,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.20 2017/06/23 20:40:51 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: wd.c,v 1.428.2.21 2017/06/23 22:11:13 jdolecek Exp $");
 
 #include "opt_ata.h"
 
@@ -198,7 +198,7 @@
 void  wddone(device_t, struct ata_xfer *);
 static void wd_params_to_properties(struct wd_softc *);
 int   wd_get_params(struct wd_softc *, uint8_t, struct ataparams *);
-int   wd_flushcache(struct wd_softc *, int);
+int   wd_flushcache(struct wd_softc *, int, bool);
 int   wd_trim(struct wd_softc *, int, daddr_t, long);
 bool  wd_shutdown(device_t, int);
 
@@ -458,7 +458,7 @@
        if (sc->atabus->ata_addref(sc->drvp))
                return true; /* no need to complain */
 
-       wd_flushcache(sc, AT_WAIT);
+       wd_flushcache(sc, AT_WAIT, false);
        wd_standby(sc, AT_WAIT);
 
        sc->atabus->ata_delref(sc->drvp);
@@ -494,10 +494,11 @@
        bufq_drain(sc->sc_q);
 
        sc->atabus->ata_killpending(sc->drvp);
+       mutex_exit(&sc->sc_lock);
+
        if (flags & DETACH_POWEROFF)
                wd_standby(sc, AT_POLL);
 
-       mutex_exit(&sc->sc_lock);
        bufq_free(sc->sc_q);
 
        /* Detach disk. */
@@ -1035,7 +1036,7 @@
 {
        struct wd_softc *wd = device_private(self);
 
-       wd_flushcache(wd, AT_WAIT);
+       wd_flushcache(wd, AT_WAIT, false);
 
        if (! (wd->sc_flags & WDF_KLABEL))
                wd->sc_flags &= ~WDF_LOADED;
@@ -1416,7 +1417,7 @@
                return wd_setcache(wd, *(int *)addr);
 
        case DIOCCACHESYNC:
-               return wd_flushcache(wd, AT_WAIT);
+               return wd_flushcache(wd, AT_WAIT, true);
 
        case ATAIOCCOMMAND:
                /*
@@ -1917,12 +1918,12 @@
 
 out:
        ata_free_xfer(wd->drvp->chnl_softc, xfer);
-       ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive);
+       /* drive is supposed to go idle, do not call ata_channel_start() */
        return error;
 }
 
 int
-wd_flushcache(struct wd_softc *wd, int flags)
+wd_flushcache(struct wd_softc *wd, int flags, bool start)
 {
        struct ata_xfer *xfer;
        int error;
@@ -1989,7 +1990,8 @@
 
 out:
        /* kick queue processing blocked while waiting for flush xfer */
-       ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive);
+       if (start)
+               ata_channel_start(wd->drvp->chnl_softc, wd->drvp->drive);
 
        return error;
 }
@@ -2067,7 +2069,7 @@
        if (wd->atabus->ata_addref(wd->drvp))
                return true; /* no need to complain */
 
-       wd_flushcache(wd, AT_POLL);
+       wd_flushcache(wd, AT_POLL, false);
        if ((how & RB_POWERDOWN) == RB_POWERDOWN)
                wd_standby(wd, AT_POLL);
        return true;



Home | Main Index | Thread Index | Old Index