diff options
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 148 |
1 files changed, 82 insertions, 66 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 60d6fdcc9265..e61891f80123 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -976,8 +976,6 @@ NORET_TYPE void do_exit(long code) | |||
976 | disassociate_ctty(1); | 976 | disassociate_ctty(1); |
977 | 977 | ||
978 | module_put(task_thread_info(tsk)->exec_domain->module); | 978 | module_put(task_thread_info(tsk)->exec_domain->module); |
979 | if (tsk->binfmt) | ||
980 | module_put(tsk->binfmt->module); | ||
981 | 979 | ||
982 | proc_exit_connector(tsk); | 980 | proc_exit_connector(tsk); |
983 | 981 | ||
@@ -993,8 +991,6 @@ NORET_TYPE void do_exit(long code) | |||
993 | tsk->mempolicy = NULL; | 991 | tsk->mempolicy = NULL; |
994 | #endif | 992 | #endif |
995 | #ifdef CONFIG_FUTEX | 993 | #ifdef CONFIG_FUTEX |
996 | if (unlikely(!list_empty(&tsk->pi_state_list))) | ||
997 | exit_pi_state_list(tsk); | ||
998 | if (unlikely(current->pi_state_cache)) | 994 | if (unlikely(current->pi_state_cache)) |
999 | kfree(current->pi_state_cache); | 995 | kfree(current->pi_state_cache); |
1000 | #endif | 996 | #endif |
@@ -1097,28 +1093,28 @@ struct wait_opts { | |||
1097 | int __user *wo_stat; | 1093 | int __user *wo_stat; |
1098 | struct rusage __user *wo_rusage; | 1094 | struct rusage __user *wo_rusage; |
1099 | 1095 | ||
1096 | wait_queue_t child_wait; | ||
1100 | int notask_error; | 1097 | int notask_error; |
1101 | }; | 1098 | }; |
1102 | 1099 | ||
1103 | static struct pid *task_pid_type(struct task_struct *task, enum pid_type type) | 1100 | static inline |
1101 | struct pid *task_pid_type(struct task_struct *task, enum pid_type type) | ||
1104 | { | 1102 | { |
1105 | struct pid *pid = NULL; | 1103 | if (type != PIDTYPE_PID) |
1106 | if (type == PIDTYPE_PID) | 1104 | task = task->group_leader; |
1107 | pid = task->pids[type].pid; | 1105 | return task->pids[type].pid; |
1108 | else if (type < PIDTYPE_MAX) | ||
1109 | pid = task->group_leader->pids[type].pid; | ||
1110 | return pid; | ||
1111 | } | 1106 | } |
1112 | 1107 | ||
1113 | static int eligible_child(struct wait_opts *wo, struct task_struct *p) | 1108 | static int eligible_pid(struct wait_opts *wo, struct task_struct *p) |
1114 | { | 1109 | { |
1115 | int err; | 1110 | return wo->wo_type == PIDTYPE_MAX || |
1116 | 1111 | task_pid_type(p, wo->wo_type) == wo->wo_pid; | |
1117 | if (wo->wo_type < PIDTYPE_MAX) { | 1112 | } |
1118 | if (task_pid_type(p, wo->wo_type) != wo->wo_pid) | ||
1119 | return 0; | ||
1120 | } | ||
1121 | 1113 | ||
1114 | static int eligible_child(struct wait_opts *wo, struct task_struct *p) | ||
1115 | { | ||
1116 | if (!eligible_pid(wo, p)) | ||
1117 | return 0; | ||
1122 | /* Wait for all children (clone and not) if __WALL is set; | 1118 | /* Wait for all children (clone and not) if __WALL is set; |
1123 | * otherwise, wait for clone children *only* if __WCLONE is | 1119 | * otherwise, wait for clone children *only* if __WCLONE is |
1124 | * set; otherwise, wait for non-clone children *only*. (Note: | 1120 | * set; otherwise, wait for non-clone children *only*. (Note: |
@@ -1128,10 +1124,6 @@ static int eligible_child(struct wait_opts *wo, struct task_struct *p) | |||
1128 | && !(wo->wo_flags & __WALL)) | 1124 | && !(wo->wo_flags & __WALL)) |
1129 | return 0; | 1125 | return 0; |
1130 | 1126 | ||
1131 | err = security_task_wait(p); | ||
1132 | if (err) | ||
1133 | return err; | ||
1134 | |||
1135 | return 1; | 1127 | return 1; |
1136 | } | 1128 | } |
1137 | 1129 | ||
@@ -1144,18 +1136,20 @@ static int wait_noreap_copyout(struct wait_opts *wo, struct task_struct *p, | |||
1144 | 1136 | ||
1145 | put_task_struct(p); | 1137 | put_task_struct(p); |
1146 | infop = wo->wo_info; | 1138 | infop = wo->wo_info; |
1147 | if (!retval) | 1139 | if (infop) { |
1148 | retval = put_user(SIGCHLD, &infop->si_signo); | 1140 | if (!retval) |
1149 | if (!retval) | 1141 | retval = put_user(SIGCHLD, &infop->si_signo); |
1150 | retval = put_user(0, &infop->si_errno); | 1142 | if (!retval) |
1151 | if (!retval) | 1143 | retval = put_user(0, &infop->si_errno); |
1152 | retval = put_user((short)why, &infop->si_code); | 1144 | if (!retval) |
1153 | if (!retval) | 1145 | retval = put_user((short)why, &infop->si_code); |
1154 | retval = put_user(pid, &infop->si_pid); | 1146 | if (!retval) |
1155 | if (!retval) | 1147 | retval = put_user(pid, &infop->si_pid); |
1156 | retval = put_user(uid, &infop->si_uid); | 1148 | if (!retval) |
1157 | if (!retval) | 1149 | retval = put_user(uid, &infop->si_uid); |
1158 | retval = put_user(status, &infop->si_status); | 1150 | if (!retval) |
1151 | retval = put_user(status, &infop->si_status); | ||
1152 | } | ||
1159 | if (!retval) | 1153 | if (!retval) |
1160 | retval = pid; | 1154 | retval = pid; |
1161 | return retval; | 1155 | return retval; |
@@ -1485,13 +1479,14 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p) | |||
1485 | * then ->notask_error is 0 if @p is an eligible child, | 1479 | * then ->notask_error is 0 if @p is an eligible child, |
1486 | * or another error from security_task_wait(), or still -ECHILD. | 1480 | * or another error from security_task_wait(), or still -ECHILD. |
1487 | */ | 1481 | */ |
1488 | static int wait_consider_task(struct wait_opts *wo, struct task_struct *parent, | 1482 | static int wait_consider_task(struct wait_opts *wo, int ptrace, |
1489 | int ptrace, struct task_struct *p) | 1483 | struct task_struct *p) |
1490 | { | 1484 | { |
1491 | int ret = eligible_child(wo, p); | 1485 | int ret = eligible_child(wo, p); |
1492 | if (!ret) | 1486 | if (!ret) |
1493 | return ret; | 1487 | return ret; |
1494 | 1488 | ||
1489 | ret = security_task_wait(p); | ||
1495 | if (unlikely(ret < 0)) { | 1490 | if (unlikely(ret < 0)) { |
1496 | /* | 1491 | /* |
1497 | * If we have not yet seen any eligible child, | 1492 | * If we have not yet seen any eligible child, |
@@ -1553,7 +1548,7 @@ static int do_wait_thread(struct wait_opts *wo, struct task_struct *tsk) | |||
1553 | * Do not consider detached threads. | 1548 | * Do not consider detached threads. |
1554 | */ | 1549 | */ |
1555 | if (!task_detached(p)) { | 1550 | if (!task_detached(p)) { |
1556 | int ret = wait_consider_task(wo, tsk, 0, p); | 1551 | int ret = wait_consider_task(wo, 0, p); |
1557 | if (ret) | 1552 | if (ret) |
1558 | return ret; | 1553 | return ret; |
1559 | } | 1554 | } |
@@ -1567,7 +1562,7 @@ static int ptrace_do_wait(struct wait_opts *wo, struct task_struct *tsk) | |||
1567 | struct task_struct *p; | 1562 | struct task_struct *p; |
1568 | 1563 | ||
1569 | list_for_each_entry(p, &tsk->ptraced, ptrace_entry) { | 1564 | list_for_each_entry(p, &tsk->ptraced, ptrace_entry) { |
1570 | int ret = wait_consider_task(wo, tsk, 1, p); | 1565 | int ret = wait_consider_task(wo, 1, p); |
1571 | if (ret) | 1566 | if (ret) |
1572 | return ret; | 1567 | return ret; |
1573 | } | 1568 | } |
@@ -1575,15 +1570,38 @@ static int ptrace_do_wait(struct wait_opts *wo, struct task_struct *tsk) | |||
1575 | return 0; | 1570 | return 0; |
1576 | } | 1571 | } |
1577 | 1572 | ||
1573 | static int child_wait_callback(wait_queue_t *wait, unsigned mode, | ||
1574 | int sync, void *key) | ||
1575 | { | ||
1576 | struct wait_opts *wo = container_of(wait, struct wait_opts, | ||
1577 | child_wait); | ||
1578 | struct task_struct *p = key; | ||
1579 | |||
1580 | if (!eligible_pid(wo, p)) | ||
1581 | return 0; | ||
1582 | |||
1583 | if ((wo->wo_flags & __WNOTHREAD) && wait->private != p->parent) | ||
1584 | return 0; | ||
1585 | |||
1586 | return default_wake_function(wait, mode, sync, key); | ||
1587 | } | ||
1588 | |||
1589 | void __wake_up_parent(struct task_struct *p, struct task_struct *parent) | ||
1590 | { | ||
1591 | __wake_up_sync_key(&parent->signal->wait_chldexit, | ||
1592 | TASK_INTERRUPTIBLE, 1, p); | ||
1593 | } | ||
1594 | |||
1578 | static long do_wait(struct wait_opts *wo) | 1595 | static long do_wait(struct wait_opts *wo) |
1579 | { | 1596 | { |
1580 | DECLARE_WAITQUEUE(wait, current); | ||
1581 | struct task_struct *tsk; | 1597 | struct task_struct *tsk; |
1582 | int retval; | 1598 | int retval; |
1583 | 1599 | ||
1584 | trace_sched_process_wait(wo->wo_pid); | 1600 | trace_sched_process_wait(wo->wo_pid); |
1585 | 1601 | ||
1586 | add_wait_queue(¤t->signal->wait_chldexit,&wait); | 1602 | init_waitqueue_func_entry(&wo->child_wait, child_wait_callback); |
1603 | wo->child_wait.private = current; | ||
1604 | add_wait_queue(¤t->signal->wait_chldexit, &wo->child_wait); | ||
1587 | repeat: | 1605 | repeat: |
1588 | /* | 1606 | /* |
1589 | * If there is nothing that can match our critiera just get out. | 1607 | * If there is nothing that can match our critiera just get out. |
@@ -1624,32 +1642,7 @@ notask: | |||
1624 | } | 1642 | } |
1625 | end: | 1643 | end: |
1626 | __set_current_state(TASK_RUNNING); | 1644 | __set_current_state(TASK_RUNNING); |
1627 | remove_wait_queue(¤t->signal->wait_chldexit,&wait); | 1645 | remove_wait_queue(¤t->signal->wait_chldexit, &wo->child_wait); |
1628 | if (wo->wo_info) { | ||
1629 | struct siginfo __user *infop = wo->wo_info; | ||
1630 | |||
1631 | if (retval > 0) | ||
1632 | retval = 0; | ||
1633 | else { | ||
1634 | /* | ||
1635 | * For a WNOHANG return, clear out all the fields | ||
1636 | * we would set so the user can easily tell the | ||
1637 | * difference. | ||
1638 | */ | ||
1639 | if (!retval) | ||
1640 | retval = put_user(0, &infop->si_signo); | ||
1641 | if (!retval) | ||
1642 | retval = put_user(0, &infop->si_errno); | ||
1643 | if (!retval) | ||
1644 | retval = put_user(0, &infop->si_code); | ||
1645 | if (!retval) | ||
1646 | retval = put_user(0, &infop->si_pid); | ||
1647 | if (!retval) | ||
1648 | retval = put_user(0, &infop->si_uid); | ||
1649 | if (!retval) | ||
1650 | retval = put_user(0, &infop->si_status); | ||
1651 | } | ||
1652 | } | ||
1653 | return retval; | 1646 | return retval; |
1654 | } | 1647 | } |
1655 | 1648 | ||
@@ -1694,6 +1687,29 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, | |||
1694 | wo.wo_stat = NULL; | 1687 | wo.wo_stat = NULL; |
1695 | wo.wo_rusage = ru; | 1688 | wo.wo_rusage = ru; |
1696 | ret = do_wait(&wo); | 1689 | ret = do_wait(&wo); |
1690 | |||
1691 | if (ret > 0) { | ||
1692 | ret = 0; | ||
1693 | } else if (infop) { | ||
1694 | /* | ||
1695 | * For a WNOHANG return, clear out all the fields | ||
1696 | * we would set so the user can easily tell the | ||
1697 | * difference. | ||
1698 | */ | ||
1699 | if (!ret) | ||
1700 | ret = put_user(0, &infop->si_signo); | ||
1701 | if (!ret) | ||
1702 | ret = put_user(0, &infop->si_errno); | ||
1703 | if (!ret) | ||
1704 | ret = put_user(0, &infop->si_code); | ||
1705 | if (!ret) | ||
1706 | ret = put_user(0, &infop->si_pid); | ||
1707 | if (!ret) | ||
1708 | ret = put_user(0, &infop->si_uid); | ||
1709 | if (!ret) | ||
1710 | ret = put_user(0, &infop->si_status); | ||
1711 | } | ||
1712 | |||
1697 | put_pid(pid); | 1713 | put_pid(pid); |
1698 | 1714 | ||
1699 | /* avoid REGPARM breakage on x86: */ | 1715 | /* avoid REGPARM breakage on x86: */ |