run_posix_cpu_timers: don't check ->exit_state, use lock_task_sighand()
PATCH 5/5 run_posix_cpu_timers: don't check ->exit_state, use lock_task_sighand()
run_posix_cpu_timers() doesn't work if current has already passed exit_notify(). This was needed to prevent the races with do_wait().
Since ea6d290c ->signal is always valid and can't go away. We can remove the "tsk->exit_state == 0" in fastpath_timer_check() and convert run_posix_cpu_timers() to use lock_task_sighand().
Note: it makes sense to take group_leader's sighand instead, the sub-thread still uses CPU after release_task(). But we need more changes to do this.
---
kernel/posix-cpu-timers.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
kernel/posix-cpu-timers.c renamed from kernel/posix-cpu-timers.c~5_RUN_PCT_DONT_CK_EXIT_STATE +4 -6
@@ -1272,10 +1272,6 @@ static inline int fastpath_timer_check(s {struct signal_struct *sig; -/* tsk == current, ensure it is safe to use ->signal/sighand */ -if (unlikely (tsk->exit_state)) -return 0 ; -if (!task_cputime_zero (&tsk->cputime_expires)) {struct task_cputime task_sample = { .utime = tsk->utime,
@@ -1308,6 +1304,7 @@ void run_posix_cpu_timers(struct task_st {LIST_HEAD (firing);struct k_itimer *timer, *next; +unsigned long flags;BUG_ON (!irqs_disabled ());
@@ -1318,7 +1315,8 @@ void run_posix_cpu_timers(struct task_stif (!fastpath_timer_check (tsk))return ; -spin_lock (&tsk->sighand->siglock); +if (!lock_task_sighand (tsk, &flags)) +return ;/* * Here we take off tsk->signal->cpu_timers[N] and * tsk->cpu_timers[N] all the timers that are firing, and
@@ -1340,7 +1338,7 @@ void run_posix_cpu_timers(struct task_st* that gets the timer lock before we do will give it up and * spin until we've taken care of that timer below. */ -spin_unlock (&tsk->sighand->siglock); +unlock_task_sighand (tsk, &flags);/* * Now that all the timers on our list have the firing flag,
[PATCH 6/5] fix the racy usage of thread_group_cputimer() in fastpath_timer_check()
fastpath_timer_check()->thread_group_cputimer() is racy and unneeded.
It is racy because another thread can clear ->running before thread_group_cputimer() takes cputimer->lock. In this case thread_group_cputimer() will set ->running = true again and call thread_group_cputime(). But since we do not hold tasklist or siglock, we can race with fork/exit and copy the wrong results into cputimer->cputime.
It is unneeded because if ->running == true we can just use the numbers in cputimer->cputime we already have.
Change fastpath_timer_check() to copy cputimer->cputime into the local variable under cputimer->lock. We do not re-check ->running under cputimer->lock, run_posix_cpu_timers() does this check later.
Note: we can add more optimizations on top of this change.
---
kernel/posix-cpu-timers.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
kernel/posix-cpu-timers.c renamed from kernel/posix-cpu-timers.c~6_FPTC_DONT_SET_RUNNING +4 -1
@@ -1287,7 +1287,10 @@ static inline int fastpath_timer_check(sif (sig->cputimer.running) {struct task_cputime group_sample; -thread_group_cputimer (tsk, &group_sample); +spin_lock (&sig->cputimer.lock); + group_sample = sig->cputimer.cputime; +spin_unlock (&sig->cputimer.lock); +if (task_cputime_expired (&group_sample, &sig->cputime_expires))return 1 ; }
Re: [PATCH 6/5] fix the racy usage of thread_group_cputimer() in fastpath_timer_check()
Quoted 3 lines · Oleg Nesterov
fastpath_timer_check()->thread_group_cputimer() is racy and unneeded.
Just in case... this fix doesn't depend on other patches I sent.
Quoted 37 lines
It is racy because another thread can clear ->running before
thread_group_cputimer()takescputimer->lock. In this casethread_group_cputimer()will set ->running = true again and callthread_group_cputime(). But since we do not hold tasklist or siglock, we can race with fork/exit and copy the wrong results intocputimer->cputime.It is unneeded because if ->running == true we can just use the numbers in
cputimer->cputimewe already have.Change
fastpath_timer_check()to copycputimer->cputimeinto the local variable undercputimer->lock. We do not re-check ->running undercputimer->lock,run_posix_cpu_timers()does this check later.Note: we can add more optimizations on top of this change.
Signed-off-by Oleg Nesterov <[email protected]>---
kernel/posix-cpu-timers.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)kernel/posix-cpu-timers.c renamed from kernel/posix-cpu-timers.c~6_FPTC_DONT_SET_RUNNING +4
-1@@ -1287,7 +1287,10 @@ static inline int fastpath_timer_check(sif (sig->cputimer.running) {struct task_cputime group_sample; -thread_group_cputimer (tsk, &group_sample); +spin_lock (&sig->cputimer.lock); + group_sample = sig->cputimer.cputime; +spin_unlock (&sig->cputimer.lock); +if (task_cputime_expired (&group_sample, &sig->cputime_expires))return 1 ; }
[tip:sched/core] sched: Fix the racy usage of thread_group_cputimer() in fastpath_timer_check()
In reply to Oleg NesterovCommit-ID: 8d1f431cbec115a780cd551ab1b4955c125f8d31 Gitweb: http://git.kernel.org/tip/8d1f431cbec115a780cd551ab1b4955c125f8d31 Author: Oleg Nesterov <[email protected]> AuthorDate: Fri, 11 Jun 2010 20:04:46 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Fri, 18 Jun 2010 10:46:57 +0200
sched: Fix the racy usage of thread_group_cputimer() in fastpath_timer_check()
fastpath_timer_check()->thread_group_cputimer() is racy and unneeded.
It is racy because another thread can clear ->running before thread_group_cputimer() takes cputimer->lock. In this case thread_group_cputimer() will set ->running = true again and call thread_group_cputime(). But since we do not hold tasklist or siglock, we can race with fork/exit and copy the wrong results into cputimer->cputime.
It is unneeded because if ->running == true we can just use the numbers in cputimer->cputime we already have.
Change fastpath_timer_check() to copy cputimer->cputime into the local variable under cputimer->lock. We do not re-check ->running under cputimer->lock, run_posix_cpu_timers() does this check later.
Note: we can add more optimizations on top of this change.
LKML-Reference: <[email protected]>
--- kernel/posix-cpu-timers.c | 5 ++++- 1 files changed, 4 insertions(+), 1 deletions(-)
kernel/posix-cpu-timers.c +4 -1
@@ -1287,7 +1287,10 @@ static inline int fastpath_timer_check(struct task_struct *tsk)if (sig->cputimer.running) {struct task_cputime group_sample; -thread_group_cputimer (tsk, &group_sample); +spin_lock (&sig->cputimer.lock); + group_sample = sig->cputimer.cputime; +spin_unlock (&sig->cputimer.lock); +if (task_cputime_expired (&group_sample, &sig->cputime_expires))return 1 ; }
[tip:sched/core] sched: run_posix_cpu_timers: Don't check ->exit_state, use lock_task_sighand()
In reply to Oleg NesterovCommit-ID: 0bdd2ed4138ec04e09b4f8165981efc99e439f55 Gitweb: http://git.kernel.org/tip/0bdd2ed4138ec04e09b4f8165981efc99e439f55 Author: Oleg Nesterov <[email protected]> AuthorDate: Fri, 11 Jun 2010 01:10:18 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Fri, 18 Jun 2010 10:46:57 +0200
sched: run_posix_cpu_timers: Don't check ->exit_state, use lock_task_sighand()
run_posix_cpu_timers() doesn't work if current has already passed exit_notify(). This was needed to prevent the races with do_wait().
Since ea6d290c ->signal is always valid and can't go away. We can remove the "tsk->exit_state == 0" in fastpath_timer_check() and convert run_posix_cpu_timers() to use lock_task_sighand().
Note: it makes sense to take group_leader's sighand instead, the sub-thread still uses CPU after release_task(). But we need more changes to do this.
LKML-Reference: <[email protected]>
--- kernel/posix-cpu-timers.c | 10 ++++------ 1 files changed, 4 insertions(+), 6 deletions(-)
kernel/posix-cpu-timers.c +4 -6
@@ -1272,10 +1272,6 @@ static inline int fastpath_timer_check(struct task_struct *tsk) {struct signal_struct *sig; -/* tsk == current, ensure it is safe to use ->signal/sighand */ -if (unlikely (tsk->exit_state)) -return 0 ; -if (!task_cputime_zero (&tsk->cputime_expires)) {struct task_cputime task_sample = { .utime = tsk->utime,
@@ -1308,6 +1304,7 @@ void run_posix_cpu_timers(struct task_struct *tsk) {LIST_HEAD (firing);struct k_itimer *timer, *next; +unsigned long flags;BUG_ON (!irqs_disabled ());
@@ -1318,7 +1315,8 @@ void run_posix_cpu_timers(struct task_struct *tsk)if (!fastpath_timer_check (tsk))return ; -spin_lock (&tsk->sighand->siglock); +if (!lock_task_sighand (tsk, &flags)) +return ;/* * Here we take off tsk->signal->cpu_timers[N] and * tsk->cpu_timers[N] all the timers that are firing, and
@@ -1340,7 +1338,7 @@ void run_posix_cpu_timers(struct task_struct *tsk)* that gets the timer lock before we do will give it up and * spin until we've taken care of that timer below. */ -spin_unlock (&tsk->sighand->siglock); +unlock_task_sighand (tsk, &flags);/* * Now that all the timers on our list have the firing flag,