This is in preparation for adding a ditto sched_work list. Signed-off-by: Jens Axboe <axboe@xxxxxxxxx> --- kernel/task_work.c | 88 +++++++++++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 32 deletions(-) diff --git a/kernel/task_work.c b/kernel/task_work.c index 825f28259a19..3445421266e7 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -5,6 +5,22 @@ static struct callback_head work_exited; /* all we need is ->next == NULL */ +static int __task_work_add(struct task_struct *task, + struct callback_head **headptr, + struct callback_head *work) +{ + struct callback_head *head; + + do { + head = READ_ONCE(*headptr); + if (unlikely(head == &work_exited)) + return -ESRCH; + work->next = head; + } while (cmpxchg(headptr, head, work) != head); + + return 0; +} + /** * task_work_add - ask the @task to execute @work->func() * @task: the task which should run the callback @@ -27,39 +43,25 @@ static struct callback_head work_exited; /* all we need is ->next == NULL */ int task_work_add(struct task_struct *task, struct callback_head *work, bool notify) { - struct callback_head *head; + int ret; - do { - head = READ_ONCE(task->task_works); - if (unlikely(head == &work_exited)) - return -ESRCH; - work->next = head; - } while (cmpxchg(&task->task_works, head, work) != head); + ret = __task_work_add(task, &task->task_works, work); if (notify) set_notify_resume(task); - return 0; + + return ret; } -/** - * task_work_cancel - cancel a pending work added by task_work_add() - * @task: the task which should execute the work - * @func: identifies the work to remove - * - * Find the last queued pending work with ->func == @func and remove - * it from queue. - * - * RETURNS: - * The found work or NULL if not found. - */ -struct callback_head * -task_work_cancel(struct task_struct *task, task_work_func_t func) +static struct callback_head *__task_work_cancel(struct task_struct *task, + struct callback_head **headptr, + task_work_func_t func) { - struct callback_head **pprev = &task->task_works; + struct callback_head **pprev = headptr; struct callback_head *work; unsigned long flags; - if (likely(!task->task_works)) + if (likely(!(*headptr))) return NULL; /* * If cmpxchg() fails we continue without updating pprev. @@ -80,16 +82,25 @@ task_work_cancel(struct task_struct *task, task_work_func_t func) } /** - * task_work_run - execute the works added by task_work_add() + * task_work_cancel - cancel a pending work added by task_work_add() + * @task: the task which should execute the work + * @func: identifies the work to remove * - * Flush the pending works. Should be used by the core kernel code. - * Called before the task returns to the user-mode or stops, or when - * it exits. In the latter case task_work_add() can no longer add the - * new work after task_work_run() returns. + * Find the last queued pending work with ->func == @func and remove + * it from queue. + * + * RETURNS: + * The found work or NULL if not found. */ -void task_work_run(void) +struct callback_head * +task_work_cancel(struct task_struct *task, task_work_func_t func) +{ + return __task_work_cancel(task, &task->task_works, func); +} + +static void __task_work_run(struct task_struct *task, + struct callback_head **headptr) { - struct task_struct *task = current; struct callback_head *work, *head, *next; for (;;) { @@ -99,14 +110,14 @@ void task_work_run(void) */ do { head = NULL; - work = READ_ONCE(task->task_works); + work = READ_ONCE(*headptr); if (!work) { if (task->flags & PF_EXITING) head = &work_exited; else break; } - } while (cmpxchg(&task->task_works, work, head) != work); + } while (cmpxchg(headptr, work, head) != work); if (!work) break; @@ -126,3 +137,16 @@ void task_work_run(void) } while (work); } } + +/** + * task_work_run - execute the works added by task_work_add() + * + * Flush the pending works. Should be used by the core kernel code. + * Called before the task returns to the user-mode or stops, or when + * it exits. In the latter case task_work_add() can no longer add the + * new work after task_work_run() returns. + */ +void task_work_run(void) +{ + __task_work_run(current, ¤t->task_works); +} -- 2.25.1