deal with task_work callbacks adding more work
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 27 Jun 2012 07:33:29 +0000 (11:33 +0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Sun, 22 Jul 2012 19:57:57 +0000 (23:57 +0400)
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>
kernel/task_work.c

index fb396089f66a4def58e8c4e57f612cecf3b5b0a6..91d4e1742a0c4ec1cd8805b6663f5a95b5d42b3b 100644 (file)
@@ -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;
+               }
        }
 }