> Does stuffing a couple sync calls somewhere before it starts > suspending devices (wherever that is, I don't know) make the problems > go away?
I use ACPI S3 sleep, and sys_sync() is called in pmf_system_suspend() from acpi_enter_sleep_state(). I'm not sure if it is late enough. > You're right. When a disk driver is suspended, it should exit from > its strategy/start routine early, without error. It looks to me like > sdstrategy() and wdstrategy() may each get this wrong. I was running a kernel with the following diff. I saw "strategy_in_suspend = 0" on every resume, but still, I encountered a crash today. I couldn't see the panicstr or get a crash dump this time. -- KAMADA Ken'ichi <kam...@nanohz.org>
Index: dev/ata/wd.c =================================================================== RCS file: /cvsroot/src/sys/dev/ata/wd.c,v retrieving revision 1.384 diff -p -u -r1.384 wd.c --- dev/ata/wd.c 24 Feb 2010 22:37:57 -0000 1.384 +++ dev/ata/wd.c 14 Apr 2010 19:05:08 -0000 @@ -127,8 +127,11 @@ void wdperror(const struct wd_softc *); static int wdlastclose(device_t); static bool wd_suspend(device_t, const pmf_qual_t *); +static bool wd_resume(device_t, const pmf_qual_t *); static int wd_standby(struct wd_softc *, int); +static int strategy_in_suspend; + CFATTACH_DECL3_NEW(wd, sizeof(struct wd_softc), wdprobe, wdattach, wddetach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN); @@ -389,7 +392,7 @@ wdattach(device_t parent, device_t self, /* Discover wedges on this disk. */ dkwedge_discover(&wd->sc_dk); - if (!pmf_device_register1(self, wd_suspend, NULL, wd_shutdown)) + if (!pmf_device_register1(self, wd_suspend, wd_resume, wd_shutdown)) aprint_error_dev(self, "couldn't establish power handler\n"); } @@ -398,11 +401,22 @@ wd_suspend(device_t dv, const pmf_qual_t { struct wd_softc *sc = device_private(dv); + sc->suspended = 1; wd_flushcache(sc, AT_WAIT); wd_standby(sc, AT_WAIT); return true; } +static bool +wd_resume(device_t dv, const pmf_qual_t *qual) +{ + struct wd_softc *sc = device_private(dv); + + sc->suspended = 0; + printf("strategy_in_suspend = %d\n", strategy_in_suspend); + return true; +} + int wddetach(device_t self, int flags) { @@ -553,7 +567,10 @@ wdstrategy(struct buf *bp) /* Queue transfer on drive, activate drive and controller if idle. */ s = splbio(); bufq_put(wd->sc_q, bp); - wdstart(wd); + if (wd->suspended) + strategy_in_suspend++; + else + wdstart(wd); splx(s); return; done: Index: dev/ata/wdvar.h =================================================================== RCS file: /cvsroot/src/sys/dev/ata/wdvar.h,v retrieving revision 1.38 diff -p -u -r1.38 wdvar.h --- dev/ata/wdvar.h 17 Dec 2009 21:03:10 -0000 1.38 +++ dev/ata/wdvar.h 14 Apr 2010 19:05:08 -0000 @@ -69,6 +69,7 @@ struct wd_softc { #if NRND > 0 rndsource_element_t rnd_source; #endif + int suspended; }; #define sc_drive sc_wdc_bio.drive