Messages in this thread Patch in this message | | | Date | Wed, 27 Jun 2012 20:38:13 +0200 | From | Oleg Nesterov <> | Subject | [PATCH 3/4] task_work: deal with task_work callbacks adding more work |
| |
Shamelessly stolen Al Viro's patch and the changelog, just I didn't dare to add the proper From tag.
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().
Suggested-by: Al Viro <viro@ZenIV.linux.org.uk> Signed-off-by: Oleg Nesterov <oleg@redhat.com> --- kernel/task_work.c | 33 +++++++++++++++++++++------------ 1 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/kernel/task_work.c b/kernel/task_work.c index b2ff3b7..8dfc48c 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -76,18 +76,27 @@ void task_work_run(void) struct task_struct *task = current; struct task_work *last, *next, *twork; - raw_spin_lock_irq(&task->pi_lock); - last = task->last_twork; - task->last_twork = (task->flags & PF_EXITING) ? TWORK_EXITED : NULL; - raw_spin_unlock_irq(&task->pi_lock); + for (;;) { + /* + * twork->func() can do task_work_add(), do not + * set TWORK_EXITED until the list becomes empty. + */ + raw_spin_lock_irq(&task->pi_lock); + last = task->last_twork; + if (last) + task->last_twork = NULL; + else if (task->flags & PF_EXITING) + task->last_twork = TWORK_EXITED; + raw_spin_unlock_irq(&task->pi_lock); - if (!last) - return; + if (!last) + return; - next = last->next; - do { - twork = next; - next = twork->next; - twork->func(twork); - } while (twork != last); + next = last->next; + do { + twork = next; + next = twork->next; + twork->func(twork); + } while (twork != last); + } } -- 1.5.5.1
| |