Module Name: src Committed By: riastradh Date: Sun Dec 19 01:20:00 UTC 2021
Modified Files: src/sys/external/bsd/common/include/linux: workqueue.h src/sys/external/bsd/common/linux: linux_work.c Log Message: drain_workqueue To generate a diff of this commit: cvs rdiff -u -r1.17 -r1.18 \ src/sys/external/bsd/common/include/linux/workqueue.h cvs rdiff -u -r1.49 -r1.50 src/sys/external/bsd/common/linux/linux_work.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/external/bsd/common/include/linux/workqueue.h diff -u src/sys/external/bsd/common/include/linux/workqueue.h:1.17 src/sys/external/bsd/common/include/linux/workqueue.h:1.18 --- src/sys/external/bsd/common/include/linux/workqueue.h:1.17 Sun Dec 19 01:04:05 2021 +++ src/sys/external/bsd/common/include/linux/workqueue.h Sun Dec 19 01:20:00 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: workqueue.h,v 1.17 2021/12/19 01:04:05 riastradh Exp $ */ +/* $NetBSD: workqueue.h,v 1.18 2021/12/19 01:20:00 riastradh Exp $ */ /*- * Copyright (c) 2013, 2018 The NetBSD Foundation, Inc. @@ -47,6 +47,7 @@ #define current_work linux_current_work #define delayed_work_pending linux_delayed_work_pending #define destroy_workqueue linux_destroy_workqueue +#define drain_workqueue linux_drain_workqueue #define flush_delayed_work linux_flush_delayed_work #define flush_scheduled_work linux_flush_scheduled_work #define flush_work linux_flush_work @@ -105,6 +106,7 @@ struct workqueue_struct * alloc_ordered_workqueue(const char *, int); void destroy_workqueue(struct workqueue_struct *); void flush_workqueue(struct workqueue_struct *); +void drain_workqueue(struct workqueue_struct *); void flush_scheduled_work(void); void INIT_WORK(struct work_struct *, void (*)(struct work_struct *)); Index: src/sys/external/bsd/common/linux/linux_work.c diff -u src/sys/external/bsd/common/linux/linux_work.c:1.49 src/sys/external/bsd/common/linux/linux_work.c:1.50 --- src/sys/external/bsd/common/linux/linux_work.c:1.49 Sun Dec 19 01:04:05 2021 +++ src/sys/external/bsd/common/linux/linux_work.c Sun Dec 19 01:20:00 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: linux_work.c,v 1.49 2021/12/19 01:04:05 riastradh Exp $ */ +/* $NetBSD: linux_work.c,v 1.50 2021/12/19 01:20:00 riastradh Exp $ */ /*- * Copyright (c) 2018 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: linux_work.c,v 1.49 2021/12/19 01:04:05 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: linux_work.c,v 1.50 2021/12/19 01:20:00 riastradh Exp $"); #include <sys/types.h> #include <sys/atomic.h> @@ -63,6 +63,7 @@ struct workqueue_struct { bool wq_dying; uint64_t wq_gen; struct lwp *wq_lwp; + const char *wq_name; }; static void __dead linux_workqueue_thread(void *); @@ -249,6 +250,7 @@ alloc_ordered_workqueue(const char *name wq->wq_dying = false; wq->wq_gen = 0; wq->wq_lwp = NULL; + wq->wq_name = name; error = kthread_create(PRI_NONE, KTHREAD_MPSAFE|KTHREAD_TS|KTHREAD_MUSTJOIN, NULL, @@ -1387,14 +1389,16 @@ flush_scheduled_work(void) * flush_workqueue_locked(wq) * * Wait for all work queued on wq to complete. This does not - * include delayed work. + * include delayed work. True if there was work to be flushed, + * false it the queue was empty. * * Caller must hold wq's lock. */ -static void +static bool flush_workqueue_locked(struct workqueue_struct *wq) { uint64_t gen; + bool work_queued = false; KASSERT(mutex_owned(&wq->wq_lock)); @@ -1405,22 +1409,29 @@ flush_workqueue_locked(struct workqueue_ * If there's a batch of work in progress, we must wait for the * worker thread to finish that batch. */ - if (wq->wq_current_work != NULL) + if (wq->wq_current_work != NULL) { gen++; + work_queued = true; + } /* * If there's any work yet to be claimed from the queue by the * worker thread, we must wait for it to finish one more batch * too. */ - if (!TAILQ_EMPTY(&wq->wq_queue) || !TAILQ_EMPTY(&wq->wq_dqueue)) + if (!TAILQ_EMPTY(&wq->wq_queue) || !TAILQ_EMPTY(&wq->wq_dqueue)) { gen++; + work_queued = true; + } /* Wait until the generation number has caught up. */ SDT_PROBE1(sdt, linux, work, flush__start, wq); while (wq->wq_gen < gen) cv_wait(&wq->wq_cv, &wq->wq_lock); SDT_PROBE1(sdt, linux, work, flush__done, wq); + + /* Return whether we had to wait for anything. */ + return work_queued; } /* @@ -1434,7 +1445,27 @@ flush_workqueue(struct workqueue_struct { mutex_enter(&wq->wq_lock); - flush_workqueue_locked(wq); + (void)flush_workqueue_locked(wq); + mutex_exit(&wq->wq_lock); +} + +/* + * drain_workqueue(wq) + * + * Repeatedly flush wq until there is no more work. + */ +void +drain_workqueue(struct workqueue_struct *wq) +{ + unsigned ntries = 0; + + mutex_enter(&wq->wq_lock); + while (flush_workqueue_locked(wq)) { + if (ntries++ == 10 || (ntries % 100) == 0) + printf("linux workqueue %s" + ": still clogged after %u flushes", + wq->wq_name, ntries); + } mutex_exit(&wq->wq_lock); } @@ -1532,7 +1563,7 @@ flush_delayed_work(struct delayed_work * * Waiting for the whole queue to flush is overkill, * but doesn't hurt. */ - flush_workqueue_locked(wq); + (void)flush_workqueue_locked(wq); waited = true; } mutex_exit(&wq->wq_lock);