Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

[PATCH] run_posix_cpu_timers: remove a bogus BUG_ON()

do_exit() clears ->it_##clock##_expires, but nothing prevents
another cpu to attach the timer to exiting process after that.
arm_timer() tries to protect against this race, but the check
is racy.

After exit_notify() does 'write_unlock_irq(&tasklist_lock)' and
before do_exit() calls 'schedule() local timer interrupt can find
tsk->exit_state != 0. If that state was EXIT_DEAD (or another cpu
does sys_wait4) interrupted task has ->signal == NULL.

At this moment exiting task has no pending cpu timers, they were
cleanuped in __exit_signal()->posix_cpu_timers_exit{,_group}(),
so we can just return from irq.

John Stultz recently confirmed this bug, see

http://marc.theaimsgroup.com/?l=linux-kernel&m=115015841413687

Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Oleg Nesterov and committed by
Linus Torvalds
30f1e3dd 8f17fc20

+18 -26
-8
kernel/exit.c
··· 881 881 882 882 tsk->flags |= PF_EXITING; 883 883 884 - /* 885 - * Make sure we don't try to process any timer firings 886 - * while we are already exiting. 887 - */ 888 - tsk->it_virt_expires = cputime_zero; 889 - tsk->it_prof_expires = cputime_zero; 890 - tsk->it_sched_expires = 0; 891 - 892 884 if (unlikely(in_atomic())) 893 885 printk(KERN_INFO "note: %s[%d] exited with preempt_count %d\n", 894 886 current->comm, current->pid,
+18 -18
kernel/posix-cpu-timers.c
··· 1288 1288 1289 1289 #undef UNEXPIRED 1290 1290 1291 - BUG_ON(tsk->exit_state); 1292 - 1293 1291 /* 1294 1292 * Double-check with locks held. 1295 1293 */ 1296 1294 read_lock(&tasklist_lock); 1297 - spin_lock(&tsk->sighand->siglock); 1295 + if (likely(tsk->signal != NULL)) { 1296 + spin_lock(&tsk->sighand->siglock); 1298 1297 1299 - /* 1300 - * Here we take off tsk->cpu_timers[N] and tsk->signal->cpu_timers[N] 1301 - * all the timers that are firing, and put them on the firing list. 1302 - */ 1303 - check_thread_timers(tsk, &firing); 1304 - check_process_timers(tsk, &firing); 1298 + /* 1299 + * Here we take off tsk->cpu_timers[N] and tsk->signal->cpu_timers[N] 1300 + * all the timers that are firing, and put them on the firing list. 1301 + */ 1302 + check_thread_timers(tsk, &firing); 1303 + check_process_timers(tsk, &firing); 1305 1304 1306 - /* 1307 - * We must release these locks before taking any timer's lock. 1308 - * There is a potential race with timer deletion here, as the 1309 - * siglock now protects our private firing list. We have set 1310 - * the firing flag in each timer, so that a deletion attempt 1311 - * that gets the timer lock before we do will give it up and 1312 - * spin until we've taken care of that timer below. 1313 - */ 1314 - spin_unlock(&tsk->sighand->siglock); 1305 + /* 1306 + * We must release these locks before taking any timer's lock. 1307 + * There is a potential race with timer deletion here, as the 1308 + * siglock now protects our private firing list. We have set 1309 + * the firing flag in each timer, so that a deletion attempt 1310 + * that gets the timer lock before we do will give it up and 1311 + * spin until we've taken care of that timer below. 1312 + */ 1313 + spin_unlock(&tsk->sighand->siglock); 1314 + } 1315 1315 read_unlock(&tasklist_lock); 1316 1316 1317 1317 /*