summaryrefslogtreecommitdiffstats
path: root/kernel/task_work.c
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2021-05-18 09:45:08 +0300
committerTony Lindgren <tony@atomide.com>2021-05-18 09:45:08 +0300
commit85ebe5aeef9b0bf4c91ff91652b32f9c54f71d34 (patch)
treedc6b176404218efac28a4a1a0c240cb36f1e9173 /kernel/task_work.c
parente9aa9c75c58e2e16be16ec2b5db5e14804d07213 (diff)
parent040ab72ee10ea88e1883ad143b3e2b77596abc31 (diff)
downloadlinux-85ebe5aeef9b0bf4c91ff91652b32f9c54f71d34.tar.gz
linux-85ebe5aeef9b0bf4c91ff91652b32f9c54f71d34.zip
Merge branch 'fixes-rc1' into fixes
Diffstat (limited to 'kernel/task_work.c')
-rw-r--r--kernel/task_work.c38
1 files changed, 31 insertions, 7 deletions
diff --git a/kernel/task_work.c b/kernel/task_work.c
index 9cde961875c0..1698fbe6f0e1 100644
--- a/kernel/task_work.c
+++ b/kernel/task_work.c
@@ -34,6 +34,9 @@ int task_work_add(struct task_struct *task, struct callback_head *work,
{
struct callback_head *head;
+ /* record the work call stack in order to print it in KASAN reports */
+ kasan_record_aux_stack(work);
+
do {
head = READ_ONCE(task->task_works);
if (unlikely(head == &work_exited))
@@ -59,18 +62,17 @@ int task_work_add(struct task_struct *task, struct callback_head *work,
}
/**
- * task_work_cancel - cancel a pending work added by task_work_add()
+ * task_work_cancel_match - 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.
+ * @match: match function to call
*
* RETURNS:
* The found work or NULL if not found.
*/
struct callback_head *
-task_work_cancel(struct task_struct *task, task_work_func_t func)
+task_work_cancel_match(struct task_struct *task,
+ bool (*match)(struct callback_head *, void *data),
+ void *data)
{
struct callback_head **pprev = &task->task_works;
struct callback_head *work;
@@ -86,7 +88,7 @@ task_work_cancel(struct task_struct *task, task_work_func_t func)
*/
raw_spin_lock_irqsave(&task->pi_lock, flags);
while ((work = READ_ONCE(*pprev))) {
- if (work->func != func)
+ if (!match(work, data))
pprev = &work->next;
else if (cmpxchg(pprev, work, work->next) == work)
break;
@@ -96,6 +98,28 @@ task_work_cancel(struct task_struct *task, task_work_func_t func)
return work;
}
+static bool task_work_func_match(struct callback_head *cb, void *data)
+{
+ return cb->func == data;
+}
+
+/**
+ * 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)
+{
+ return task_work_cancel_match(task, task_work_func_match, func);
+}
+
/**
* task_work_run - execute the works added by task_work_add()
*