call task_del() from destroy_work_on_stack()
authorjsg <jsg@openbsd.org>
Sat, 14 Aug 2021 03:12:51 +0000 (03:12 +0000)
committerjsg <jsg@openbsd.org>
Sat, 14 Aug 2021 03:12:51 +0000 (03:12 +0000)
prompted by jcs@ reporting a protection fault trap in
drm_mode_rmfb_work_fn() while playing a youtube video in firefox on a
kaby lake machine.  He later saw the same trace on tiger lake.

The previous attempt to avoid this situation by changing work flush
functions from taskq_barrier() to taskq_del_barrier() resulted in
suspend sometimes not working on various intel based thinkpads.

The only code we build which calls destroy_work_on_stack() is in
drm_framebuffer.c so the scope of this change is more limited.
Linux only uses destroy_work_on_stack() for debugging so the workqueue
behaviour still doesn't match.

This version is confirmed to not break suspend on x260 by sthen@ and
x280 by tb@ and still avoids the original problem according to jcs@

sys/dev/pci/drm/include/linux/workqueue.h

index a0c7134..1b541e1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: workqueue.h,v 1.5 2021/05/17 00:17:26 jsg Exp $       */
+/*     $OpenBSD: workqueue.h,v 1.6 2021/08/14 03:12:51 jsg Exp $       */
 /*
  * Copyright (c) 2015 Mark Kettenis
  *
@@ -201,7 +201,13 @@ bool flush_delayed_work(struct delayed_work *);
 #define flush_scheduled_work() flush_workqueue(system_wq)
 #define drain_workqueue(x)     flush_workqueue(x)
 
-#define destroy_work_on_stack(x)
+static inline void
+destroy_work_on_stack(struct work_struct *work)
+{
+       if (work->tq)
+               task_del(work->tq, &work->task);
+}
+
 #define destroy_delayed_work_on_stack(x)
 
 struct rcu_work {