diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2017-05-27 16:22:20 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2017-05-27 16:22:20 -0400 |
commit | 33dd955df2d35bfca0fc851bcde9189839eb687a (patch) | |
tree | a06379ac5a9df04f03c8a150b58e79a5a8e69e88 | |
parent | 9ba3eb5103cf56f0daaf07de4507df76e7813ed7 (diff) | |
parent | 92ebce5ac55dba258c608248dddf59eca3f7f514 (diff) |
Merge branch 'work.sys_wait' into misc.alpha
-rw-r--r-- | arch/alpha/kernel/osf_sys.c | 51 | ||||
-rw-r--r-- | arch/x86/include/asm/uaccess.h | 2 | ||||
-rw-r--r-- | include/linux/resource.h | 2 | ||||
-rw-r--r-- | include/linux/sched/task.h | 2 | ||||
-rw-r--r-- | kernel/compat.c | 66 | ||||
-rw-r--r-- | kernel/exit.c | 307 | ||||
-rw-r--r-- | kernel/sys.c | 16 |
7 files changed, 188 insertions, 258 deletions
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index c4e135db1704..05dbbf9f42f4 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c | |||
@@ -1178,46 +1178,23 @@ SYSCALL_DEFINE2(osf_getrusage, int, who, struct rusage32 __user *, ru) | |||
1178 | SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options, | 1178 | SYSCALL_DEFINE4(osf_wait4, pid_t, pid, int __user *, ustatus, int, options, |
1179 | struct rusage32 __user *, ur) | 1179 | struct rusage32 __user *, ur) |
1180 | { | 1180 | { |
1181 | struct rusage r; | ||
1182 | long ret, err; | ||
1183 | unsigned int status = 0; | 1181 | unsigned int status = 0; |
1184 | mm_segment_t old_fs; | 1182 | struct rusage r; |
1185 | 1183 | long err = kernel_wait4(pid, &status, options, &r); | |
1184 | if (err <= 0) | ||
1185 | return err; | ||
1186 | if (put_user(status, ustatus)) | ||
1187 | return -EFAULT; | ||
1186 | if (!ur) | 1188 | if (!ur) |
1187 | return sys_wait4(pid, ustatus, options, NULL); | 1189 | return err; |
1188 | 1190 | if (put_tv32(&ur->ru_utime, &r.ru_utime)) | |
1189 | old_fs = get_fs(); | ||
1190 | |||
1191 | set_fs (KERNEL_DS); | ||
1192 | ret = sys_wait4(pid, (unsigned int __user *) &status, options, | ||
1193 | (struct rusage __user *) &r); | ||
1194 | set_fs (old_fs); | ||
1195 | |||
1196 | if (!access_ok(VERIFY_WRITE, ur, sizeof(*ur))) | ||
1197 | return -EFAULT; | 1191 | return -EFAULT; |
1198 | 1192 | if (put_tv32(&ur->ru_stime, &r.ru_stime)) | |
1199 | err = 0; | 1193 | return -EFAULT; |
1200 | err |= put_user(status, ustatus); | 1194 | if (copy_to_user(&ur->ru_maxrss, &r.ru_maxrss, |
1201 | err |= __put_user(r.ru_utime.tv_sec, &ur->ru_utime.tv_sec); | 1195 | sizeof(struct rusage32) - offsetof(struct rusage32, ru_maxrss))) |
1202 | err |= __put_user(r.ru_utime.tv_usec, &ur->ru_utime.tv_usec); | 1196 | return -EFAULT; |
1203 | err |= __put_user(r.ru_stime.tv_sec, &ur->ru_stime.tv_sec); | 1197 | return err; |
1204 | err |= __put_user(r.ru_stime.tv_usec, &ur->ru_stime.tv_usec); | ||
1205 | err |= __put_user(r.ru_maxrss, &ur->ru_maxrss); | ||
1206 | err |= __put_user(r.ru_ixrss, &ur->ru_ixrss); | ||
1207 | err |= __put_user(r.ru_idrss, &ur->ru_idrss); | ||
1208 | err |= __put_user(r.ru_isrss, &ur->ru_isrss); | ||
1209 | err |= __put_user(r.ru_minflt, &ur->ru_minflt); | ||
1210 | err |= __put_user(r.ru_majflt, &ur->ru_majflt); | ||
1211 | err |= __put_user(r.ru_nswap, &ur->ru_nswap); | ||
1212 | err |= __put_user(r.ru_inblock, &ur->ru_inblock); | ||
1213 | err |= __put_user(r.ru_oublock, &ur->ru_oublock); | ||
1214 | err |= __put_user(r.ru_msgsnd, &ur->ru_msgsnd); | ||
1215 | err |= __put_user(r.ru_msgrcv, &ur->ru_msgrcv); | ||
1216 | err |= __put_user(r.ru_nsignals, &ur->ru_nsignals); | ||
1217 | err |= __put_user(r.ru_nvcsw, &ur->ru_nvcsw); | ||
1218 | err |= __put_user(r.ru_nivcsw, &ur->ru_nivcsw); | ||
1219 | |||
1220 | return err ? err : ret; | ||
1221 | } | 1198 | } |
1222 | 1199 | ||
1223 | /* | 1200 | /* |
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h index 68766b276d9e..d9668c3beb5b 100644 --- a/arch/x86/include/asm/uaccess.h +++ b/arch/x86/include/asm/uaccess.h | |||
@@ -703,7 +703,7 @@ extern struct movsl_mask { | |||
703 | #define unsafe_put_user(x, ptr, err_label) \ | 703 | #define unsafe_put_user(x, ptr, err_label) \ |
704 | do { \ | 704 | do { \ |
705 | int __pu_err; \ | 705 | int __pu_err; \ |
706 | __put_user_size((x), (ptr), sizeof(*(ptr)), __pu_err, -EFAULT); \ | 706 | __put_user_size((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), __pu_err, -EFAULT); \ |
707 | if (unlikely(__pu_err)) goto err_label; \ | 707 | if (unlikely(__pu_err)) goto err_label; \ |
708 | } while (0) | 708 | } while (0) |
709 | 709 | ||
diff --git a/include/linux/resource.h b/include/linux/resource.h index 5bc3116e649c..277afdad6589 100644 --- a/include/linux/resource.h +++ b/include/linux/resource.h | |||
@@ -6,7 +6,7 @@ | |||
6 | 6 | ||
7 | struct task_struct; | 7 | struct task_struct; |
8 | 8 | ||
9 | int getrusage(struct task_struct *p, int who, struct rusage __user *ru); | 9 | void getrusage(struct task_struct *p, int who, struct rusage *ru); |
10 | int do_prlimit(struct task_struct *tsk, unsigned int resource, | 10 | int do_prlimit(struct task_struct *tsk, unsigned int resource, |
11 | struct rlimit *new_rlim, struct rlimit *old_rlim); | 11 | struct rlimit *new_rlim, struct rlimit *old_rlim); |
12 | 12 | ||
diff --git a/include/linux/sched/task.h b/include/linux/sched/task.h index a978d7189cfd..6b830fd9d809 100644 --- a/include/linux/sched/task.h +++ b/include/linux/sched/task.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/sched.h> | 9 | #include <linux/sched.h> |
10 | 10 | ||
11 | struct task_struct; | 11 | struct task_struct; |
12 | struct rusage; | ||
12 | union thread_union; | 13 | union thread_union; |
13 | 14 | ||
14 | /* | 15 | /* |
@@ -74,6 +75,7 @@ extern long _do_fork(unsigned long, unsigned long, unsigned long, int __user *, | |||
74 | extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *); | 75 | extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *); |
75 | struct task_struct *fork_idle(int); | 76 | struct task_struct *fork_idle(int); |
76 | extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); | 77 | extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); |
78 | extern long kernel_wait4(pid_t, int *, int, struct rusage *); | ||
77 | 79 | ||
78 | extern void free_task(struct task_struct *tsk); | 80 | extern void free_task(struct task_struct *tsk); |
79 | 81 | ||
diff --git a/kernel/compat.c b/kernel/compat.c index 933bcb31ae10..b4cdba6bbd02 100644 --- a/kernel/compat.c +++ b/kernel/compat.c | |||
@@ -543,72 +543,6 @@ int put_compat_rusage(const struct rusage *r, struct compat_rusage __user *ru) | |||
543 | return 0; | 543 | return 0; |
544 | } | 544 | } |
545 | 545 | ||
546 | COMPAT_SYSCALL_DEFINE4(wait4, | ||
547 | compat_pid_t, pid, | ||
548 | compat_uint_t __user *, stat_addr, | ||
549 | int, options, | ||
550 | struct compat_rusage __user *, ru) | ||
551 | { | ||
552 | if (!ru) { | ||
553 | return sys_wait4(pid, stat_addr, options, NULL); | ||
554 | } else { | ||
555 | struct rusage r; | ||
556 | int ret; | ||
557 | unsigned int status; | ||
558 | mm_segment_t old_fs = get_fs(); | ||
559 | |||
560 | set_fs (KERNEL_DS); | ||
561 | ret = sys_wait4(pid, | ||
562 | (stat_addr ? | ||
563 | (unsigned int __user *) &status : NULL), | ||
564 | options, (struct rusage __user *) &r); | ||
565 | set_fs (old_fs); | ||
566 | |||
567 | if (ret > 0) { | ||
568 | if (put_compat_rusage(&r, ru)) | ||
569 | return -EFAULT; | ||
570 | if (stat_addr && put_user(status, stat_addr)) | ||
571 | return -EFAULT; | ||
572 | } | ||
573 | return ret; | ||
574 | } | ||
575 | } | ||
576 | |||
577 | COMPAT_SYSCALL_DEFINE5(waitid, | ||
578 | int, which, compat_pid_t, pid, | ||
579 | struct compat_siginfo __user *, uinfo, int, options, | ||
580 | struct compat_rusage __user *, uru) | ||
581 | { | ||
582 | siginfo_t info; | ||
583 | struct rusage ru; | ||
584 | long ret; | ||
585 | mm_segment_t old_fs = get_fs(); | ||
586 | |||
587 | memset(&info, 0, sizeof(info)); | ||
588 | |||
589 | set_fs(KERNEL_DS); | ||
590 | ret = sys_waitid(which, pid, (siginfo_t __user *)&info, options, | ||
591 | uru ? (struct rusage __user *)&ru : NULL); | ||
592 | set_fs(old_fs); | ||
593 | |||
594 | if ((ret < 0) || (info.si_signo == 0)) | ||
595 | return ret; | ||
596 | |||
597 | if (uru) { | ||
598 | /* sys_waitid() overwrites everything in ru */ | ||
599 | if (COMPAT_USE_64BIT_TIME) | ||
600 | ret = copy_to_user(uru, &ru, sizeof(ru)); | ||
601 | else | ||
602 | ret = put_compat_rusage(&ru, uru); | ||
603 | if (ret) | ||
604 | return -EFAULT; | ||
605 | } | ||
606 | |||
607 | BUG_ON(info.si_code & __SI_MASK); | ||
608 | info.si_code |= __SI_CHLD; | ||
609 | return copy_siginfo_to_user32(uinfo, &info); | ||
610 | } | ||
611 | |||
612 | static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr, | 546 | static int compat_get_user_cpu_mask(compat_ulong_t __user *user_mask_ptr, |
613 | unsigned len, struct cpumask *new_mask) | 547 | unsigned len, struct cpumask *new_mask) |
614 | { | 548 | { |
diff --git a/kernel/exit.c b/kernel/exit.c index 516acdb0e0ec..462fc25eec6e 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <linux/kcov.h> | 62 | #include <linux/kcov.h> |
63 | #include <linux/random.h> | 63 | #include <linux/random.h> |
64 | #include <linux/rcuwait.h> | 64 | #include <linux/rcuwait.h> |
65 | #include <linux/compat.h> | ||
65 | 66 | ||
66 | #include <linux/uaccess.h> | 67 | #include <linux/uaccess.h> |
67 | #include <asm/unistd.h> | 68 | #include <asm/unistd.h> |
@@ -995,14 +996,21 @@ SYSCALL_DEFINE1(exit_group, int, error_code) | |||
995 | return 0; | 996 | return 0; |
996 | } | 997 | } |
997 | 998 | ||
999 | struct waitid_info { | ||
1000 | pid_t pid; | ||
1001 | uid_t uid; | ||
1002 | int status; | ||
1003 | int cause; | ||
1004 | }; | ||
1005 | |||
998 | struct wait_opts { | 1006 | struct wait_opts { |
999 | enum pid_type wo_type; | 1007 | enum pid_type wo_type; |
1000 | int wo_flags; | 1008 | int wo_flags; |
1001 | struct pid *wo_pid; | 1009 | struct pid *wo_pid; |
1002 | 1010 | ||
1003 | struct siginfo __user *wo_info; | 1011 | struct waitid_info *wo_info; |
1004 | int __user *wo_stat; | 1012 | int wo_stat; |
1005 | struct rusage __user *wo_rusage; | 1013 | struct rusage *wo_rusage; |
1006 | 1014 | ||
1007 | wait_queue_t child_wait; | 1015 | wait_queue_t child_wait; |
1008 | int notask_error; | 1016 | int notask_error; |
@@ -1049,34 +1057,6 @@ eligible_child(struct wait_opts *wo, bool ptrace, struct task_struct *p) | |||
1049 | return 1; | 1057 | return 1; |
1050 | } | 1058 | } |
1051 | 1059 | ||
1052 | static int wait_noreap_copyout(struct wait_opts *wo, struct task_struct *p, | ||
1053 | pid_t pid, uid_t uid, int why, int status) | ||
1054 | { | ||
1055 | struct siginfo __user *infop; | ||
1056 | int retval = wo->wo_rusage | ||
1057 | ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0; | ||
1058 | |||
1059 | put_task_struct(p); | ||
1060 | infop = wo->wo_info; | ||
1061 | if (infop) { | ||
1062 | if (!retval) | ||
1063 | retval = put_user(SIGCHLD, &infop->si_signo); | ||
1064 | if (!retval) | ||
1065 | retval = put_user(0, &infop->si_errno); | ||
1066 | if (!retval) | ||
1067 | retval = put_user((short)why, &infop->si_code); | ||
1068 | if (!retval) | ||
1069 | retval = put_user(pid, &infop->si_pid); | ||
1070 | if (!retval) | ||
1071 | retval = put_user(uid, &infop->si_uid); | ||
1072 | if (!retval) | ||
1073 | retval = put_user(status, &infop->si_status); | ||
1074 | } | ||
1075 | if (!retval) | ||
1076 | retval = pid; | ||
1077 | return retval; | ||
1078 | } | ||
1079 | |||
1080 | /* | 1060 | /* |
1081 | * Handle sys_wait4 work for one task in state EXIT_ZOMBIE. We hold | 1061 | * Handle sys_wait4 work for one task in state EXIT_ZOMBIE. We hold |
1082 | * read_lock(&tasklist_lock) on entry. If we return zero, we still hold | 1062 | * read_lock(&tasklist_lock) on entry. If we return zero, we still hold |
@@ -1085,30 +1065,23 @@ static int wait_noreap_copyout(struct wait_opts *wo, struct task_struct *p, | |||
1085 | */ | 1065 | */ |
1086 | static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) | 1066 | static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) |
1087 | { | 1067 | { |
1088 | int state, retval, status; | 1068 | int state, status; |
1089 | pid_t pid = task_pid_vnr(p); | 1069 | pid_t pid = task_pid_vnr(p); |
1090 | uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p)); | 1070 | uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p)); |
1091 | struct siginfo __user *infop; | 1071 | struct waitid_info *infop; |
1092 | 1072 | ||
1093 | if (!likely(wo->wo_flags & WEXITED)) | 1073 | if (!likely(wo->wo_flags & WEXITED)) |
1094 | return 0; | 1074 | return 0; |
1095 | 1075 | ||
1096 | if (unlikely(wo->wo_flags & WNOWAIT)) { | 1076 | if (unlikely(wo->wo_flags & WNOWAIT)) { |
1097 | int exit_code = p->exit_code; | 1077 | status = p->exit_code; |
1098 | int why; | ||
1099 | |||
1100 | get_task_struct(p); | 1078 | get_task_struct(p); |
1101 | read_unlock(&tasklist_lock); | 1079 | read_unlock(&tasklist_lock); |
1102 | sched_annotate_sleep(); | 1080 | sched_annotate_sleep(); |
1103 | 1081 | if (wo->wo_rusage) | |
1104 | if ((exit_code & 0x7f) == 0) { | 1082 | getrusage(p, RUSAGE_BOTH, wo->wo_rusage); |
1105 | why = CLD_EXITED; | 1083 | put_task_struct(p); |
1106 | status = exit_code >> 8; | 1084 | goto out_info; |
1107 | } else { | ||
1108 | why = (exit_code & 0x80) ? CLD_DUMPED : CLD_KILLED; | ||
1109 | status = exit_code & 0x7f; | ||
1110 | } | ||
1111 | return wait_noreap_copyout(wo, p, pid, uid, why, status); | ||
1112 | } | 1085 | } |
1113 | /* | 1086 | /* |
1114 | * Move the task's state to DEAD/TRACE, only one thread can do this. | 1087 | * Move the task's state to DEAD/TRACE, only one thread can do this. |
@@ -1181,38 +1154,11 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) | |||
1181 | spin_unlock_irq(¤t->sighand->siglock); | 1154 | spin_unlock_irq(¤t->sighand->siglock); |
1182 | } | 1155 | } |
1183 | 1156 | ||
1184 | retval = wo->wo_rusage | 1157 | if (wo->wo_rusage) |
1185 | ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0; | 1158 | getrusage(p, RUSAGE_BOTH, wo->wo_rusage); |
1186 | status = (p->signal->flags & SIGNAL_GROUP_EXIT) | 1159 | status = (p->signal->flags & SIGNAL_GROUP_EXIT) |
1187 | ? p->signal->group_exit_code : p->exit_code; | 1160 | ? p->signal->group_exit_code : p->exit_code; |
1188 | if (!retval && wo->wo_stat) | 1161 | wo->wo_stat = status; |
1189 | retval = put_user(status, wo->wo_stat); | ||
1190 | |||
1191 | infop = wo->wo_info; | ||
1192 | if (!retval && infop) | ||
1193 | retval = put_user(SIGCHLD, &infop->si_signo); | ||
1194 | if (!retval && infop) | ||
1195 | retval = put_user(0, &infop->si_errno); | ||
1196 | if (!retval && infop) { | ||
1197 | int why; | ||
1198 | |||
1199 | if ((status & 0x7f) == 0) { | ||
1200 | why = CLD_EXITED; | ||
1201 | status >>= 8; | ||
1202 | } else { | ||
1203 | why = (status & 0x80) ? CLD_DUMPED : CLD_KILLED; | ||
1204 | status &= 0x7f; | ||
1205 | } | ||
1206 | retval = put_user((short)why, &infop->si_code); | ||
1207 | if (!retval) | ||
1208 | retval = put_user(status, &infop->si_status); | ||
1209 | } | ||
1210 | if (!retval && infop) | ||
1211 | retval = put_user(pid, &infop->si_pid); | ||
1212 | if (!retval && infop) | ||
1213 | retval = put_user(uid, &infop->si_uid); | ||
1214 | if (!retval) | ||
1215 | retval = pid; | ||
1216 | 1162 | ||
1217 | if (state == EXIT_TRACE) { | 1163 | if (state == EXIT_TRACE) { |
1218 | write_lock_irq(&tasklist_lock); | 1164 | write_lock_irq(&tasklist_lock); |
@@ -1229,7 +1175,21 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) | |||
1229 | if (state == EXIT_DEAD) | 1175 | if (state == EXIT_DEAD) |
1230 | release_task(p); | 1176 | release_task(p); |
1231 | 1177 | ||
1232 | return retval; | 1178 | out_info: |
1179 | infop = wo->wo_info; | ||
1180 | if (infop) { | ||
1181 | if ((status & 0x7f) == 0) { | ||
1182 | infop->cause = CLD_EXITED; | ||
1183 | infop->status = status >> 8; | ||
1184 | } else { | ||
1185 | infop->cause = (status & 0x80) ? CLD_DUMPED : CLD_KILLED; | ||
1186 | infop->status = status & 0x7f; | ||
1187 | } | ||
1188 | infop->pid = pid; | ||
1189 | infop->uid = uid; | ||
1190 | } | ||
1191 | |||
1192 | return pid; | ||
1233 | } | 1193 | } |
1234 | 1194 | ||
1235 | static int *task_stopped_code(struct task_struct *p, bool ptrace) | 1195 | static int *task_stopped_code(struct task_struct *p, bool ptrace) |
@@ -1265,8 +1225,8 @@ static int *task_stopped_code(struct task_struct *p, bool ptrace) | |||
1265 | static int wait_task_stopped(struct wait_opts *wo, | 1225 | static int wait_task_stopped(struct wait_opts *wo, |
1266 | int ptrace, struct task_struct *p) | 1226 | int ptrace, struct task_struct *p) |
1267 | { | 1227 | { |
1268 | struct siginfo __user *infop; | 1228 | struct waitid_info *infop; |
1269 | int retval, exit_code, *p_code, why; | 1229 | int exit_code, *p_code, why; |
1270 | uid_t uid = 0; /* unneeded, required by compiler */ | 1230 | uid_t uid = 0; /* unneeded, required by compiler */ |
1271 | pid_t pid; | 1231 | pid_t pid; |
1272 | 1232 | ||
@@ -1311,34 +1271,21 @@ unlock_sig: | |||
1311 | why = ptrace ? CLD_TRAPPED : CLD_STOPPED; | 1271 | why = ptrace ? CLD_TRAPPED : CLD_STOPPED; |
1312 | read_unlock(&tasklist_lock); | 1272 | read_unlock(&tasklist_lock); |
1313 | sched_annotate_sleep(); | 1273 | sched_annotate_sleep(); |
1274 | if (wo->wo_rusage) | ||
1275 | getrusage(p, RUSAGE_BOTH, wo->wo_rusage); | ||
1276 | put_task_struct(p); | ||
1314 | 1277 | ||
1315 | if (unlikely(wo->wo_flags & WNOWAIT)) | 1278 | if (likely(!(wo->wo_flags & WNOWAIT))) |
1316 | return wait_noreap_copyout(wo, p, pid, uid, why, exit_code); | 1279 | wo->wo_stat = (exit_code << 8) | 0x7f; |
1317 | |||
1318 | retval = wo->wo_rusage | ||
1319 | ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0; | ||
1320 | if (!retval && wo->wo_stat) | ||
1321 | retval = put_user((exit_code << 8) | 0x7f, wo->wo_stat); | ||
1322 | 1280 | ||
1323 | infop = wo->wo_info; | 1281 | infop = wo->wo_info; |
1324 | if (!retval && infop) | 1282 | if (infop) { |
1325 | retval = put_user(SIGCHLD, &infop->si_signo); | 1283 | infop->cause = why; |
1326 | if (!retval && infop) | 1284 | infop->status = exit_code; |
1327 | retval = put_user(0, &infop->si_errno); | 1285 | infop->pid = pid; |
1328 | if (!retval && infop) | 1286 | infop->uid = uid; |
1329 | retval = put_user((short)why, &infop->si_code); | 1287 | } |
1330 | if (!retval && infop) | 1288 | return pid; |
1331 | retval = put_user(exit_code, &infop->si_status); | ||
1332 | if (!retval && infop) | ||
1333 | retval = put_user(pid, &infop->si_pid); | ||
1334 | if (!retval && infop) | ||
1335 | retval = put_user(uid, &infop->si_uid); | ||
1336 | if (!retval) | ||
1337 | retval = pid; | ||
1338 | put_task_struct(p); | ||
1339 | |||
1340 | BUG_ON(!retval); | ||
1341 | return retval; | ||
1342 | } | 1289 | } |
1343 | 1290 | ||
1344 | /* | 1291 | /* |
@@ -1349,7 +1296,7 @@ unlock_sig: | |||
1349 | */ | 1296 | */ |
1350 | static int wait_task_continued(struct wait_opts *wo, struct task_struct *p) | 1297 | static int wait_task_continued(struct wait_opts *wo, struct task_struct *p) |
1351 | { | 1298 | { |
1352 | int retval; | 1299 | struct waitid_info *infop; |
1353 | pid_t pid; | 1300 | pid_t pid; |
1354 | uid_t uid; | 1301 | uid_t uid; |
1355 | 1302 | ||
@@ -1374,22 +1321,20 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p) | |||
1374 | get_task_struct(p); | 1321 | get_task_struct(p); |
1375 | read_unlock(&tasklist_lock); | 1322 | read_unlock(&tasklist_lock); |
1376 | sched_annotate_sleep(); | 1323 | sched_annotate_sleep(); |
1324 | if (wo->wo_rusage) | ||
1325 | getrusage(p, RUSAGE_BOTH, wo->wo_rusage); | ||
1326 | put_task_struct(p); | ||
1377 | 1327 | ||
1378 | if (!wo->wo_info) { | 1328 | infop = wo->wo_info; |
1379 | retval = wo->wo_rusage | 1329 | if (!infop) { |
1380 | ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0; | 1330 | wo->wo_stat = 0xffff; |
1381 | put_task_struct(p); | ||
1382 | if (!retval && wo->wo_stat) | ||
1383 | retval = put_user(0xffff, wo->wo_stat); | ||
1384 | if (!retval) | ||
1385 | retval = pid; | ||
1386 | } else { | 1331 | } else { |
1387 | retval = wait_noreap_copyout(wo, p, pid, uid, | 1332 | infop->cause = CLD_CONTINUED; |
1388 | CLD_CONTINUED, SIGCONT); | 1333 | infop->pid = pid; |
1389 | BUG_ON(retval == 0); | 1334 | infop->uid = uid; |
1335 | infop->status = SIGCONT; | ||
1390 | } | 1336 | } |
1391 | 1337 | return pid; | |
1392 | return retval; | ||
1393 | } | 1338 | } |
1394 | 1339 | ||
1395 | /* | 1340 | /* |
@@ -1617,8 +1562,8 @@ end: | |||
1617 | return retval; | 1562 | return retval; |
1618 | } | 1563 | } |
1619 | 1564 | ||
1620 | SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, | 1565 | static long kernel_waitid(int which, pid_t upid, struct waitid_info *infop, |
1621 | infop, int, options, struct rusage __user *, ru) | 1566 | int options, struct rusage *ru) |
1622 | { | 1567 | { |
1623 | struct wait_opts wo; | 1568 | struct wait_opts wo; |
1624 | struct pid *pid = NULL; | 1569 | struct pid *pid = NULL; |
@@ -1656,38 +1601,46 @@ SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, | |||
1656 | wo.wo_pid = pid; | 1601 | wo.wo_pid = pid; |
1657 | wo.wo_flags = options; | 1602 | wo.wo_flags = options; |
1658 | wo.wo_info = infop; | 1603 | wo.wo_info = infop; |
1659 | wo.wo_stat = NULL; | ||
1660 | wo.wo_rusage = ru; | 1604 | wo.wo_rusage = ru; |
1661 | ret = do_wait(&wo); | 1605 | ret = do_wait(&wo); |
1662 | 1606 | ||
1663 | if (ret > 0) { | 1607 | if (ret > 0) |
1664 | ret = 0; | 1608 | ret = 0; |
1665 | } else if (infop) { | ||
1666 | /* | ||
1667 | * For a WNOHANG return, clear out all the fields | ||
1668 | * we would set so the user can easily tell the | ||
1669 | * difference. | ||
1670 | */ | ||
1671 | if (!ret) | ||
1672 | ret = put_user(0, &infop->si_signo); | ||
1673 | if (!ret) | ||
1674 | ret = put_user(0, &infop->si_errno); | ||
1675 | if (!ret) | ||
1676 | ret = put_user(0, &infop->si_code); | ||
1677 | if (!ret) | ||
1678 | ret = put_user(0, &infop->si_pid); | ||
1679 | if (!ret) | ||
1680 | ret = put_user(0, &infop->si_uid); | ||
1681 | if (!ret) | ||
1682 | ret = put_user(0, &infop->si_status); | ||
1683 | } | ||
1684 | 1609 | ||
1685 | put_pid(pid); | 1610 | put_pid(pid); |
1686 | return ret; | 1611 | return ret; |
1687 | } | 1612 | } |
1688 | 1613 | ||
1689 | SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr, | 1614 | SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, |
1690 | int, options, struct rusage __user *, ru) | 1615 | infop, int, options, struct rusage __user *, ru) |
1616 | { | ||
1617 | struct rusage r; | ||
1618 | struct waitid_info info = {.status = 0}; | ||
1619 | long err = kernel_waitid(which, upid, &info, options, ru ? &r : NULL); | ||
1620 | |||
1621 | if (!err) { | ||
1622 | if (ru && copy_to_user(ru, &r, sizeof(struct rusage))) | ||
1623 | return -EFAULT; | ||
1624 | } | ||
1625 | if (!infop) | ||
1626 | return err; | ||
1627 | |||
1628 | user_access_begin(); | ||
1629 | unsafe_put_user(err ? 0 : SIGCHLD, &infop->si_signo, Efault); | ||
1630 | unsafe_put_user(0, &infop->si_errno, Efault); | ||
1631 | unsafe_put_user((short)info.cause, &infop->si_code, Efault); | ||
1632 | unsafe_put_user(info.pid, &infop->si_pid, Efault); | ||
1633 | unsafe_put_user(info.uid, &infop->si_uid, Efault); | ||
1634 | unsafe_put_user(info.status, &infop->si_status, Efault); | ||
1635 | user_access_end(); | ||
1636 | return err; | ||
1637 | Efault: | ||
1638 | user_access_end(); | ||
1639 | return -EFAULT; | ||
1640 | } | ||
1641 | |||
1642 | long kernel_wait4(pid_t upid, int __user *stat_addr, int options, | ||
1643 | struct rusage *ru) | ||
1691 | { | 1644 | { |
1692 | struct wait_opts wo; | 1645 | struct wait_opts wo; |
1693 | struct pid *pid = NULL; | 1646 | struct pid *pid = NULL; |
@@ -1715,14 +1668,29 @@ SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr, | |||
1715 | wo.wo_pid = pid; | 1668 | wo.wo_pid = pid; |
1716 | wo.wo_flags = options | WEXITED; | 1669 | wo.wo_flags = options | WEXITED; |
1717 | wo.wo_info = NULL; | 1670 | wo.wo_info = NULL; |
1718 | wo.wo_stat = stat_addr; | 1671 | wo.wo_stat = 0; |
1719 | wo.wo_rusage = ru; | 1672 | wo.wo_rusage = ru; |
1720 | ret = do_wait(&wo); | 1673 | ret = do_wait(&wo); |
1721 | put_pid(pid); | 1674 | put_pid(pid); |
1675 | if (ret > 0 && stat_addr && put_user(wo.wo_stat, stat_addr)) | ||
1676 | ret = -EFAULT; | ||
1722 | 1677 | ||
1723 | return ret; | 1678 | return ret; |
1724 | } | 1679 | } |
1725 | 1680 | ||
1681 | SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr, | ||
1682 | int, options, struct rusage __user *, ru) | ||
1683 | { | ||
1684 | struct rusage r; | ||
1685 | long err = kernel_wait4(upid, stat_addr, options, ru ? &r : NULL); | ||
1686 | |||
1687 | if (err > 0) { | ||
1688 | if (ru && copy_to_user(ru, &r, sizeof(struct rusage))) | ||
1689 | return -EFAULT; | ||
1690 | } | ||
1691 | return err; | ||
1692 | } | ||
1693 | |||
1726 | #ifdef __ARCH_WANT_SYS_WAITPID | 1694 | #ifdef __ARCH_WANT_SYS_WAITPID |
1727 | 1695 | ||
1728 | /* | 1696 | /* |
@@ -1735,3 +1703,56 @@ SYSCALL_DEFINE3(waitpid, pid_t, pid, int __user *, stat_addr, int, options) | |||
1735 | } | 1703 | } |
1736 | 1704 | ||
1737 | #endif | 1705 | #endif |
1706 | |||
1707 | #ifdef CONFIG_COMPAT | ||
1708 | COMPAT_SYSCALL_DEFINE4(wait4, | ||
1709 | compat_pid_t, pid, | ||
1710 | compat_uint_t __user *, stat_addr, | ||
1711 | int, options, | ||
1712 | struct compat_rusage __user *, ru) | ||
1713 | { | ||
1714 | struct rusage r; | ||
1715 | long err = kernel_wait4(pid, stat_addr, options, ru ? &r : NULL); | ||
1716 | if (err > 0) { | ||
1717 | if (ru && put_compat_rusage(&r, ru)) | ||
1718 | return -EFAULT; | ||
1719 | } | ||
1720 | return err; | ||
1721 | } | ||
1722 | |||
1723 | COMPAT_SYSCALL_DEFINE5(waitid, | ||
1724 | int, which, compat_pid_t, pid, | ||
1725 | struct compat_siginfo __user *, infop, int, options, | ||
1726 | struct compat_rusage __user *, uru) | ||
1727 | { | ||
1728 | struct rusage ru; | ||
1729 | struct waitid_info info = {.status = 0}; | ||
1730 | long err = kernel_waitid(which, pid, &info, options, uru ? &ru : NULL); | ||
1731 | |||
1732 | if (!err && uru) { | ||
1733 | /* kernel_waitid() overwrites everything in ru */ | ||
1734 | if (COMPAT_USE_64BIT_TIME) | ||
1735 | err = copy_to_user(uru, &ru, sizeof(ru)); | ||
1736 | else | ||
1737 | err = put_compat_rusage(&ru, uru); | ||
1738 | if (err) | ||
1739 | return -EFAULT; | ||
1740 | } | ||
1741 | |||
1742 | if (!infop) | ||
1743 | return err; | ||
1744 | |||
1745 | user_access_begin(); | ||
1746 | unsafe_put_user(err ? 0 : SIGCHLD, &infop->si_signo, Efault); | ||
1747 | unsafe_put_user(0, &infop->si_errno, Efault); | ||
1748 | unsafe_put_user((short)info.cause, &infop->si_code, Efault); | ||
1749 | unsafe_put_user(info.pid, &infop->si_pid, Efault); | ||
1750 | unsafe_put_user(info.uid, &infop->si_uid, Efault); | ||
1751 | unsafe_put_user(info.status, &infop->si_status, Efault); | ||
1752 | user_access_end(); | ||
1753 | return err; | ||
1754 | Efault: | ||
1755 | user_access_end(); | ||
1756 | return -EFAULT; | ||
1757 | } | ||
1758 | #endif | ||
diff --git a/kernel/sys.c b/kernel/sys.c index 8a94b4eabcaa..dab1a0658a92 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -1552,7 +1552,7 @@ static void accumulate_thread_rusage(struct task_struct *t, struct rusage *r) | |||
1552 | r->ru_oublock += task_io_get_oublock(t); | 1552 | r->ru_oublock += task_io_get_oublock(t); |
1553 | } | 1553 | } |
1554 | 1554 | ||
1555 | static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | 1555 | void getrusage(struct task_struct *p, int who, struct rusage *r) |
1556 | { | 1556 | { |
1557 | struct task_struct *t; | 1557 | struct task_struct *t; |
1558 | unsigned long flags; | 1558 | unsigned long flags; |
@@ -1626,20 +1626,16 @@ out: | |||
1626 | r->ru_maxrss = maxrss * (PAGE_SIZE / 1024); /* convert pages to KBs */ | 1626 | r->ru_maxrss = maxrss * (PAGE_SIZE / 1024); /* convert pages to KBs */ |
1627 | } | 1627 | } |
1628 | 1628 | ||
1629 | int getrusage(struct task_struct *p, int who, struct rusage __user *ru) | 1629 | SYSCALL_DEFINE2(getrusage, int, who, struct rusage __user *, ru) |
1630 | { | 1630 | { |
1631 | struct rusage r; | 1631 | struct rusage r; |
1632 | 1632 | ||
1633 | k_getrusage(p, who, &r); | ||
1634 | return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0; | ||
1635 | } | ||
1636 | |||
1637 | SYSCALL_DEFINE2(getrusage, int, who, struct rusage __user *, ru) | ||
1638 | { | ||
1639 | if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN && | 1633 | if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN && |
1640 | who != RUSAGE_THREAD) | 1634 | who != RUSAGE_THREAD) |
1641 | return -EINVAL; | 1635 | return -EINVAL; |
1642 | return getrusage(current, who, ru); | 1636 | |
1637 | getrusage(current, who, &r); | ||
1638 | return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0; | ||
1643 | } | 1639 | } |
1644 | 1640 | ||
1645 | #ifdef CONFIG_COMPAT | 1641 | #ifdef CONFIG_COMPAT |
@@ -1651,7 +1647,7 @@ COMPAT_SYSCALL_DEFINE2(getrusage, int, who, struct compat_rusage __user *, ru) | |||
1651 | who != RUSAGE_THREAD) | 1647 | who != RUSAGE_THREAD) |
1652 | return -EINVAL; | 1648 | return -EINVAL; |
1653 | 1649 | ||
1654 | k_getrusage(current, who, &r); | 1650 | getrusage(current, who, &r); |
1655 | return put_compat_rusage(&r, ru); | 1651 | return put_compat_rusage(&r, ru); |
1656 | } | 1652 | } |
1657 | #endif | 1653 | #endif |