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

[PATCH] coredump: shutdown current process first

This patch optimizes zap_threads() for the case when there are no ->mm
users except the current's thread group. In that case we can avoid
'for_each_process()' loop.

It also adds a useful invariant: SIGNAL_GROUP_EXIT (if checked under
->siglock) always implies that all threads (except may be current) have
pending SIGKILL.

Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Oleg Nesterov and committed by
Linus Torvalds
5debfa6d dcf560c5

+17 -12
+17 -12
fs/exec.c
··· 1371 1371 static void zap_process(struct task_struct *start) 1372 1372 { 1373 1373 struct task_struct *t; 1374 - unsigned long flags; 1375 1374 1376 - /* 1377 - * start->sighand can't disappear, but may be 1378 - * changed by de_thread() 1379 - */ 1380 - lock_task_sighand(start, &flags); 1381 1375 start->signal->flags = SIGNAL_GROUP_EXIT; 1382 1376 start->signal->group_stop_count = 0; 1383 1377 ··· 1383 1389 signal_wake_up(t, 1); 1384 1390 } 1385 1391 } while ((t = next_thread(t)) != start); 1386 - 1387 - unlock_task_sighand(start, &flags); 1388 1392 } 1389 1393 1390 1394 static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm, 1391 1395 int exit_code) 1392 1396 { 1393 1397 struct task_struct *g, *p; 1398 + unsigned long flags; 1394 1399 int err = -EAGAIN; 1395 1400 1396 1401 spin_lock_irq(&tsk->sighand->siglock); 1397 1402 if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT)) { 1398 - tsk->signal->flags = SIGNAL_GROUP_EXIT; 1399 1403 tsk->signal->group_exit_code = exit_code; 1400 - tsk->signal->group_stop_count = 0; 1404 + zap_process(tsk); 1401 1405 err = 0; 1402 1406 } 1403 1407 spin_unlock_irq(&tsk->sighand->siglock); 1404 1408 if (err) 1405 1409 return err; 1406 1410 1411 + if (atomic_read(&mm->mm_users) == mm->core_waiters + 1) 1412 + goto done; 1413 + 1407 1414 rcu_read_lock(); 1408 1415 for_each_process(g) { 1416 + if (g == tsk->group_leader) 1417 + continue; 1418 + 1409 1419 p = g; 1410 1420 do { 1411 1421 if (p->mm) { 1412 - if (p->mm == mm) 1422 + if (p->mm == mm) { 1423 + /* 1424 + * p->sighand can't disappear, but 1425 + * may be changed by de_thread() 1426 + */ 1427 + lock_task_sighand(p, &flags); 1413 1428 zap_process(p); 1429 + unlock_task_sighand(p, &flags); 1430 + } 1414 1431 break; 1415 1432 } 1416 1433 } while ((p = next_thread(p)) != g); 1417 1434 } 1418 1435 rcu_read_unlock(); 1419 - 1436 + done: 1420 1437 return mm->core_waiters; 1421 1438 } 1422 1439