diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2012-06-27 03:33:29 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-07-22 15:57:57 -0400 |
| commit | a2d4c71d1559426155e5da8db3265bfa0d8d398d (patch) | |
| tree | e00739a549bd68afeff0685cb9998834b5eca877 /kernel | |
| parent | ed3e694d78cc75fa79bf29698631b146fd27aa35 (diff) | |
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')
| -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) | |||
| 60 | struct task_struct *task = current; | 60 | struct task_struct *task = current; |
| 61 | struct callback_head *p, *q; | 61 | struct callback_head *p, *q; |
| 62 | 62 | ||
| 63 | raw_spin_lock_irq(&task->pi_lock); | 63 | while (1) { |
| 64 | p = task->task_works; | 64 | raw_spin_lock_irq(&task->pi_lock); |
| 65 | task->task_works = NULL; | 65 | p = task->task_works; |
| 66 | raw_spin_unlock_irq(&task->pi_lock); | 66 | task->task_works = NULL; |
| 67 | raw_spin_unlock_irq(&task->pi_lock); | ||
| 67 | 68 | ||
| 68 | if (unlikely(!p)) | 69 | if (unlikely(!p)) |
| 69 | return; | 70 | return; |
| 70 | 71 | ||
| 71 | q = p->next; /* head */ | 72 | q = p->next; /* head */ |
| 72 | p->next = NULL; /* cut it */ | 73 | p->next = NULL; /* cut it */ |
| 73 | while (q) { | 74 | while (q) { |
| 74 | p = q->next; | 75 | p = q->next; |
| 75 | q->func(q); | 76 | q->func(q); |
| 76 | q = p; | 77 | q = p; |
| 78 | } | ||
| 77 | } | 79 | } |
| 78 | } | 80 | } |
