Module Name: src
Committed By: jdolecek
Date: Fri Jun 23 22:11:13 UTC 2017
Modified Files:
src/sys/dev/ata [jdolecek-ncq]: wd.c
Log Message:
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
To generate a diff of this commit:
cvs rdiff -u -r1.428.2.20 -r1.428.2.21 src/sys/dev/ata/wd.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/ata/wd.c
diff -u src/sys/dev/ata/wd.c:1.428.2.20 src/sys/dev/ata/wd.c:1.428.2.21
--- src/sys/dev/ata/wd.c:1.428.2.20 Fri Jun 23 20:40:51 2017
+++ src/sys/dev/ata/wd.c Fri Jun 23 22:11:13 2017
@@ -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 wdrestart(void *);
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 @@ wd_suspend(device_t dv, const pmf_qual_t
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 @@ wddetach(device_t self, int flags)
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 @@ wdlastclose(device_t self)
{
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 @@ wdioctl(dev_t dev, u_long xfer, void *ad
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 @@ wd_standby(struct wd_softc *wd, int flag
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_xfer:
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 @@ wd_shutdown(device_t dev, int how)
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;