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