From 1b45cbc27347f889e04be0be3ce83e79d5792222 Mon Sep 17 00:00:00 2001 From: deraadt Date: Sat, 8 Apr 2017 04:06:01 +0000 Subject: [PATCH] Sensors are run as callbacks inside tasks. During suspend a sensor 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 | 4 +++- sys/kern/kern_sensors.c | 25 +++++++++++++++++++++++-- sys/sys/sensors.h | 4 +++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index 33e5b1d7b66..09495657aad 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -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 * Copyright (c) 2005 Jordan Hargrave @@ -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) { diff --git a/sys/kern/kern_sensors.c b/sys/kern/kern_sensors.c index 5e6c68ad0c5..7cbe4019388 100644 --- a/sys/kern/kern_sensors.c +++ b/sys/kern/kern_sensors.c @@ -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 @@ -26,6 +26,7 @@ #include #include #include +#include #include #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)); diff --git a/sys/sys/sensors.h b/sys/sys/sensors.h index 094d644df83..0cb3b62d6d0 100644 --- a/sys/sys/sensors.h +++ b/sys/sys/sensors.h @@ -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 @@ -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 */ -- 2.20.1