diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-06-27 11:33:29 +0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-22 23:57:57 +0400 |
commit | a2d4c71d1559426155e5da8db3265bfa0d8d398d (patch) | |
tree | e00739a549bd68afeff0685cb9998834b5eca877 /kernel/task_work.c | |
parent | ed3e694d78cc75fa79bf29698631b146fd27aa35 (diff) | |
download | lwn-a2d4c71d1559426155e5da8db3265bfa0d8d398d.tar.gz lwn-a2d4c71d1559426155e5da8db3265bfa0d8d398d.zip |
deal with task_work callbacks adding more work
It doesn't matter on normal return to userland path (we'll recheck the
NOTIFY_RESUME flag anyway), but in case of exit_task_work() we'll
need that as soon as we get callbacks capable of triggering more
task_work_add().
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'kernel/task_work.c')
-rw-r--r-- | kernel/task_work.c | 26 |
1 files changed, 14 insertions, 12 deletions
diff --git a/kernel/task_work.c b/kernel/task_work.c index fb396089f66a..91d4e1742a0c 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -60,19 +60,21 @@ void task_work_run(void) struct task_struct *task = current; struct callback_head *p, *q; - raw_spin_lock_irq(&task->pi_lock); - p = task->task_works; - task->task_works = NULL; - raw_spin_unlock_irq(&task->pi_lock); + while (1) { + raw_spin_lock_irq(&task->pi_lock); + p = task->task_works; + task->task_works = NULL; + raw_spin_unlock_irq(&task->pi_lock); - if (unlikely(!p)) - return; + if (unlikely(!p)) + return; - q = p->next; /* head */ - p->next = NULL; /* cut it */ - while (q) { - p = q->next; - q->func(q); - q = p; + q = p->next; /* head */ + p->next = NULL; /* cut it */ + while (q) { + p = q->next; + q->func(q); + q = p; + } } } |