use taskq_del_barrier() instead of taskq_barrier() when flushing work
authorjsg <jsg@openbsd.org>
Sat, 7 Aug 2021 06:23:34 +0000 (06:23 +0000)
committerjsg <jsg@openbsd.org>
Sat, 7 Aug 2021 06:23:34 +0000 (06:23 +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 arguments to drm_mode_rmfb_work_fn() are on the stack in
drm_mode_rmfb() with flush_work() called before return.

taskq_barrier() is only a barrier for running not queued tasks.

I suspect the linux functions expect any previously queued work to
complete not just any currently running work.  I'm not sure if the
difference matters in practice.

sys/dev/pci/drm/drm_linux.c
sys/dev/pci/drm/include/linux/irq_work.h

index 72c5321..5cc7459 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: drm_linux.c,v 1.82 2021/07/28 13:28:04 kettenis Exp $ */
+/*     $OpenBSD: drm_linux.c,v 1.83 2021/08/07 06:23:34 jsg Exp $      */
 /*
  * Copyright (c) 2013 Jonathan Gray <jsg@openbsd.org>
  * Copyright (c) 2015, 2016 Mark Kettenis <kettenis@openbsd.org>
@@ -171,7 +171,7 @@ flush_work(struct work_struct *work)
                return false;
 
        if (work->tq)
-               taskq_barrier(work->tq);
+               taskq_del_barrier(work->tq, &work->task);
        return false;
 }
 
@@ -189,7 +189,7 @@ flush_delayed_work(struct delayed_work *dwork)
        }
 
        if (dwork->tq)
-               taskq_barrier(dwork->tq);
+               taskq_del_barrier(dwork->tq, &dwork->work.task);
        return ret;
 }
 
@@ -288,7 +288,7 @@ kthread_flush_work(struct kthread_work *work)
                return;
 
        if (work->tq)
-               taskq_barrier(work->tq);
+               taskq_del_barrier(work->tq, &work->task);
 }
 
 void
index f9df209..30daa6f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: irq_work.h,v 1.3 2021/07/07 02:38:36 jsg Exp $        */
+/*     $OpenBSD: irq_work.h,v 1.4 2021/08/07 06:23:34 jsg Exp $        */
 /*
  * Copyright (c) 2015 Mark Kettenis
  *
@@ -49,7 +49,7 @@ irq_work_queue(struct irq_work *work)
 static inline void
 irq_work_sync(struct irq_work *work)
 {
-       taskq_barrier(work->tq);
+       taskq_del_barrier(work->tq, &work->task);
 }
 
 #endif