git: cdceed0413d0 - stable/14 - LinuxKPI: Add cancel_work() function.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 17 Feb 2024 21:33:06 UTC
The branch stable/14 has been updated by wulf:
URL: https://cgit.FreeBSD.org/src/commit/?id=cdceed0413d0b3e8446fa65e480ec89badfa54c5
commit cdceed0413d0b3e8446fa65e480ec89badfa54c5
Author: Vladimir Kondratyev <wulf@FreeBSD.org>
AuthorDate: 2023-12-24 08:19:59 +0000
Commit: Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2024-02-17 20:58:38 +0000
LinuxKPI: Add cancel_work() function.
Cancel a work not waiting for it to finish.
Sponsored by: Serenity Cyber Security, LLC
Reviewed by: manu, kib
MFC after: 1 week
Differential Revision: https://reviews.freebsd.org/D42811
(cherry picked from commit 1b2f43a7427ebf51561867f6c497833268014512)
---
.../linuxkpi/common/include/linux/workqueue.h | 4 +++
sys/compat/linuxkpi/common/src/linux_work.c | 32 ++++++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/sys/compat/linuxkpi/common/include/linux/workqueue.h b/sys/compat/linuxkpi/common/include/linux/workqueue.h
index 226c2d1f4f0c..1c9df9fcb74d 100644
--- a/sys/compat/linuxkpi/common/include/linux/workqueue.h
+++ b/sys/compat/linuxkpi/common/include/linux/workqueue.h
@@ -188,6 +188,9 @@ do { \
#define delayed_work_pending(dwork) \
linux_work_pending(&(dwork)->work)
+#define cancel_work(work) \
+ linux_cancel_work(work)
+
#define cancel_delayed_work(dwork) \
linux_cancel_delayed_work(dwork)
@@ -243,6 +246,7 @@ extern void linux_destroy_workqueue(struct workqueue_struct *);
extern bool linux_queue_work_on(int cpu, struct workqueue_struct *, struct work_struct *);
extern bool linux_queue_delayed_work_on(int cpu, struct workqueue_struct *,
struct delayed_work *, unsigned delay);
+extern bool linux_cancel_work(struct work_struct *);
extern bool linux_cancel_delayed_work(struct delayed_work *);
extern bool linux_cancel_work_sync(struct work_struct *);
extern bool linux_cancel_delayed_work_sync(struct delayed_work *);
diff --git a/sys/compat/linuxkpi/common/src/linux_work.c b/sys/compat/linuxkpi/common/src/linux_work.c
index c62302ad2346..939bdbbc1434 100644
--- a/sys/compat/linuxkpi/common/src/linux_work.c
+++ b/sys/compat/linuxkpi/common/src/linux_work.c
@@ -360,6 +360,38 @@ linux_delayed_work_timer_fn(void *arg)
}
}
+/*
+ * This function cancels the given work structure in a
+ * non-blocking fashion. It returns non-zero if the work was
+ * successfully cancelled. Else the work may still be busy or already
+ * cancelled.
+ */
+bool
+linux_cancel_work(struct work_struct *work)
+{
+ static const uint8_t states[WORK_ST_MAX] __aligned(8) = {
+ [WORK_ST_IDLE] = WORK_ST_IDLE, /* NOP */
+ [WORK_ST_TIMER] = WORK_ST_TIMER, /* can't happen */
+ [WORK_ST_TASK] = WORK_ST_IDLE, /* cancel */
+ [WORK_ST_EXEC] = WORK_ST_EXEC, /* NOP */
+ [WORK_ST_CANCEL] = WORK_ST_IDLE, /* can't happen */
+ };
+ struct taskqueue *tq;
+
+ MPASS(atomic_read(&work->state) != WORK_ST_TIMER);
+ MPASS(atomic_read(&work->state) != WORK_ST_CANCEL);
+
+ switch (linux_update_state(&work->state, states)) {
+ case WORK_ST_TASK:
+ tq = work->work_queue->taskqueue;
+ if (taskqueue_cancel(tq, &work->work_task, NULL) == 0)
+ return (true);
+ /* FALLTHROUGH */
+ default:
+ return (false);
+ }
+}
+
/*
* This function cancels the given work structure in a synchronous
* fashion. It returns non-zero if the work was successfully