diff options
Diffstat (limited to 'fs/exec.c')
-rw-r--r-- | fs/exec.c | 29 |
1 files changed, 17 insertions, 12 deletions
@@ -1371,13 +1371,7 @@ static void format_corename(char *corename, const char *pattern, long signr) | |||
1371 | static void zap_process(struct task_struct *start) | 1371 | static void zap_process(struct task_struct *start) |
1372 | { | 1372 | { |
1373 | struct task_struct *t; | 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 | start->signal->flags = SIGNAL_GROUP_EXIT; | 1375 | start->signal->flags = SIGNAL_GROUP_EXIT; |
1382 | start->signal->group_stop_count = 0; | 1376 | start->signal->group_stop_count = 0; |
1383 | 1377 | ||
@@ -1389,40 +1383,51 @@ static void zap_process(struct task_struct *start) | |||
1389 | signal_wake_up(t, 1); | 1383 | signal_wake_up(t, 1); |
1390 | } | 1384 | } |
1391 | } while ((t = next_thread(t)) != start); | 1385 | } while ((t = next_thread(t)) != start); |
1392 | |||
1393 | unlock_task_sighand(start, &flags); | ||
1394 | } | 1386 | } |
1395 | 1387 | ||
1396 | static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm, | 1388 | static inline int zap_threads(struct task_struct *tsk, struct mm_struct *mm, |
1397 | int exit_code) | 1389 | int exit_code) |
1398 | { | 1390 | { |
1399 | struct task_struct *g, *p; | 1391 | struct task_struct *g, *p; |
1392 | unsigned long flags; | ||
1400 | int err = -EAGAIN; | 1393 | int err = -EAGAIN; |
1401 | 1394 | ||
1402 | spin_lock_irq(&tsk->sighand->siglock); | 1395 | spin_lock_irq(&tsk->sighand->siglock); |
1403 | if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT)) { | 1396 | if (!(tsk->signal->flags & SIGNAL_GROUP_EXIT)) { |
1404 | tsk->signal->flags = SIGNAL_GROUP_EXIT; | ||
1405 | tsk->signal->group_exit_code = exit_code; | 1397 | tsk->signal->group_exit_code = exit_code; |
1406 | tsk->signal->group_stop_count = 0; | 1398 | zap_process(tsk); |
1407 | err = 0; | 1399 | err = 0; |
1408 | } | 1400 | } |
1409 | spin_unlock_irq(&tsk->sighand->siglock); | 1401 | spin_unlock_irq(&tsk->sighand->siglock); |
1410 | if (err) | 1402 | if (err) |
1411 | return err; | 1403 | return err; |
1412 | 1404 | ||
1405 | if (atomic_read(&mm->mm_users) == mm->core_waiters + 1) | ||
1406 | goto done; | ||
1407 | |||
1413 | rcu_read_lock(); | 1408 | rcu_read_lock(); |
1414 | for_each_process(g) { | 1409 | for_each_process(g) { |
1410 | if (g == tsk->group_leader) | ||
1411 | continue; | ||
1412 | |||
1415 | p = g; | 1413 | p = g; |
1416 | do { | 1414 | do { |
1417 | if (p->mm) { | 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 | zap_process(p); | 1422 | zap_process(p); |
1423 | unlock_task_sighand(p, &flags); | ||
1424 | } | ||
1420 | break; | 1425 | break; |
1421 | } | 1426 | } |
1422 | } while ((p = next_thread(p)) != g); | 1427 | } while ((p = next_thread(p)) != g); |
1423 | } | 1428 | } |
1424 | rcu_read_unlock(); | 1429 | rcu_read_unlock(); |
1425 | 1430 | done: | |
1426 | return mm->core_waiters; | 1431 | return mm->core_waiters; |
1427 | } | 1432 | } |
1428 | 1433 | ||