If task_work has already been run on task exit, we don't always know if it's safe to run again. Check for task_work_exited in the task_work_pending() helper. This makes it less fragile in calling from the exit files path, for example. Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> --- include/linux/task_work.h | 4 +++- kernel/task_work.c | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/linux/task_work.h b/include/linux/task_work.h index 54c911bbf754..24f977a8fc35 100644 --- a/include/linux/task_work.h +++ b/include/linux/task_work.h @@ -7,6 +7,8 @@ typedef void (*task_work_func_t)(struct callback_head *); +extern struct callback_head task_work_exited; + static inline void init_task_work(struct callback_head *twork, task_work_func_t func) { @@ -19,7 +21,7 @@ void __task_work_run(void); static inline bool task_work_pending(void) { - return current->task_works; + return current->task_works && current->task_works != &task_work_exited; } static inline void task_work_run(void) diff --git a/kernel/task_work.c b/kernel/task_work.c index 9620333423a3..d6a8b4ab4858 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -3,7 +3,7 @@ #include <linux/task_work.h> #include <linux/tracehook.h> -static struct callback_head work_exited; /* all we need is ->next == NULL */ +struct callback_head task_work_exited = { }; /** * task_work_add - ask the @task to execute @work->func() @@ -31,7 +31,7 @@ task_work_add(struct task_struct *task, struct callback_head *work, bool notify) do { head = READ_ONCE(task->task_works); - if (unlikely(head == &work_exited)) + if (unlikely(head == &task_work_exited)) return -ESRCH; work->next = head; } while (cmpxchg(&task->task_works, head, work) != head); @@ -95,14 +95,14 @@ void __task_work_run(void) for (;;) { /* * work->func() can do task_work_add(), do not set - * work_exited unless the list is empty. + * task_work_exited unless the list is empty. */ do { head = NULL; work = READ_ONCE(task->task_works); if (!work) { if (task->flags & PF_EXITING) - head = &work_exited; + head = &task_work_exited; else break; } -- 2.26.0