Commit 5debfa6da5b06954bc79fe8deed0d1062c58dcec
Committed by
Linus Torvalds
1 parent
dcf560c593
Exists in
master
and in
4 other branches
[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>
Showing 1 changed file with 17 additions and 12 deletions Side-by-side Diff
fs/exec.c
... | ... | @@ -1371,13 +1371,7 @@ |
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 | |
1384 | 1378 | |
1385 | 1379 | |
1386 | 1380 | |
1387 | 1381 | |
1388 | 1382 | |
1389 | 1383 | |
1390 | 1384 | |
1391 | 1385 | |
... | ... | @@ -1389,40 +1383,51 @@ |
1389 | 1383 | signal_wake_up(t, 1); |
1390 | 1384 | } |
1391 | 1385 | } while ((t = next_thread(t)) != start); |
1392 | - | |
1393 | - unlock_task_sighand(start, &flags); | |
1394 | 1386 | } |
1395 | 1387 | |
1396 | 1388 | static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm, |
1397 | 1389 | int exit_code) |
1398 | 1390 | { |
1399 | 1391 | struct task_struct *g, *p; |
1392 | + unsigned long flags; | |
1400 | 1393 | int err = -EAGAIN; |
1401 | 1394 | |
1402 | 1395 | spin_lock_irq(&tsk->sighand->siglock); |
1403 | 1396 | if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT)) { |
1404 | - tsk->signal->flags = SIGNAL_GROUP_EXIT; | |
1405 | 1397 | tsk->signal->group_exit_code = exit_code; |
1406 | - tsk->signal->group_stop_count = 0; | |
1398 | + zap_process(tsk); | |
1407 | 1399 | err = 0; |
1408 | 1400 | } |
1409 | 1401 | spin_unlock_irq(&tsk->sighand->siglock); |
1410 | 1402 | if (err) |
1411 | 1403 | return err; |
1412 | 1404 | |
1405 | + if (atomic_read(&mm->mm_users) == mm->core_waiters + 1) | |
1406 | + goto done; | |
1407 | + | |
1413 | 1408 | rcu_read_lock(); |
1414 | 1409 | for_each_process(g) { |
1410 | + if (g == tsk->group_leader) | |
1411 | + continue; | |
1412 | + | |
1415 | 1413 | p = g; |
1416 | 1414 | do { |
1417 | 1415 | if (p->mm) { |
1418 | - if (p->mm == mm) | |
1416 | + if (p->mm == mm) { | |
1417 | + /* | |
1418 | + * p->sighand can't disappear, but | |
1419 | + * may be changed by de_thread() | |
1420 | + */ | |
1421 | + lock_task_sighand(p, &flags); | |
1419 | 1422 | zap_process(p); |
1423 | + unlock_task_sighand(p, &flags); | |
1424 | + } | |
1420 | 1425 | break; |
1421 | 1426 | } |
1422 | 1427 | } while ((p = next_thread(p)) != g); |
1423 | 1428 | } |
1424 | 1429 | rcu_read_unlock(); |
1425 | - | |
1430 | +done: | |
1426 | 1431 | return mm->core_waiters; |
1427 | 1432 | } |
1428 | 1433 |