Sensors are run as callbacks inside tasks. During suspend a sensor
authorderaadt <deraadt@openbsd.org>
Sat, 8 Apr 2017 04:06:01 +0000 (04:06 +0000)
committerderaadt <deraadt@openbsd.org>
Sat, 8 Apr 2017 04:06:01 +0000 (04:06 +0000)
could be running inside a driver that will be force-detached, or due
to tsleep end up disrupting the softstate/hardstate contract.  At
suspend time, quisce all these callbacks by waiting for completion.
This issue has never been observed for real, but may be implicated in
suspend/resume failures.
ok kettenis guenther mlarkin

sys/dev/acpi/acpi.c
sys/kern/kern_sensors.c
sys/sys/sensors.h

index 33e5b1d..0949565 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi.c,v 1.327 2017/04/08 01:20:10 deraadt Exp $ */
+/* $OpenBSD: acpi.c,v 1.328 2017/04/08 04:06:01 deraadt Exp $ */
 /*
  * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
  * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
@@ -2405,6 +2405,7 @@ acpi_sleep_state(struct acpi_softc *sc, int sleepmode)
        }
 #endif /* HIBERNATE */
 
+       sensor_quiesce();
        if (config_suspend_all(DVACT_QUIESCE))
                goto fail_quiesce;
 
@@ -2484,6 +2485,7 @@ fail_suspend:
 
 fail_quiesce:
        config_suspend_all(DVACT_WAKEUP);
+       sensor_restart();
 
 #ifdef HIBERNATE
        if (sleepmode == ACPI_SLEEP_HIBERNATE) {
index 5e6c68a..7cbe401 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_sensors.c,v 1.36 2015/03/14 03:38:50 jsg Exp $   */
+/*     $OpenBSD: kern_sensors.c,v 1.37 2017/04/08 04:06:01 deraadt Exp $       */
 
 /*
  * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
@@ -26,6 +26,7 @@
 #include <sys/timeout.h>
 #include <sys/task.h>
 #include <sys/rwlock.h>
+#include <sys/atomic.h>
 
 #include <sys/sensors.h>
 #include "hotplug.h"
@@ -233,17 +234,37 @@ sensor_task_tick(void *arg)
        task_add(sensors_taskq, &st->task);
 }
 
+static int sensors_quiesced;
+static int sensors_running;
+
+void
+sensor_quiesce(void)
+{
+       sensors_quiesced = 1;
+       while (sensors_running > 0)
+               tsleep(&sensors_running, PZERO, "sensorpause", 0);
+       
+}
+void
+sensor_restart(void)
+{
+       sensors_quiesced = 0;
+}
+
 void
 sensor_task_work(void *xst)
 {
        struct sensor_task *st = xst;
        unsigned int period = 0;
 
+       atomic_inc_int(&sensors_running);
        rw_enter_write(&st->lock);
        period = st->period;
-       if (period > 0)
+       if (period > 0 && !sensors_quiesced)
                st->func(st->arg);
        rw_exit_write(&st->lock);
+       if (sensors_quiesced && atomic_dec_int_nv(&sensors_running) == 0)
+               wakeup(&sensors_running);
 
        if (period == 0)
                free(st, M_DEVBUF, sizeof(*st));
index 094d644..0cb3b62 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sensors.h,v 1.34 2014/12/18 20:30:58 tedu Exp $       */
+/*     $OpenBSD: sensors.h,v 1.35 2017/04/08 04:06:01 deraadt Exp $    */
 
 /*
  * Copyright (c) 2003, 2004 Alexander Yurchenko <grange@openbsd.org>
@@ -167,6 +167,8 @@ struct sensor_task;
 struct sensor_task     *sensor_task_register(void *, void (*)(void *),
                             unsigned int);
 void                    sensor_task_unregister(struct sensor_task *);
+void                    sensor_quiesce(void);
+void                    sensor_restart(void);
 
 #endif /* _KERNEL */