diff options
Diffstat (limited to 'kernel/fork.c')
-rw-r--r-- | kernel/fork.c | 55 |
1 files changed, 29 insertions, 26 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index c7c112391d79..be8aa5b98666 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -1592,6 +1592,10 @@ static __latent_entropy struct task_struct *copy_process( | |||
1592 | int retval; | 1592 | int retval; |
1593 | struct task_struct *p; | 1593 | struct task_struct *p; |
1594 | 1594 | ||
1595 | /* | ||
1596 | * Don't allow sharing the root directory with processes in a different | ||
1597 | * namespace | ||
1598 | */ | ||
1595 | if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) | 1599 | if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) |
1596 | return ERR_PTR(-EINVAL); | 1600 | return ERR_PTR(-EINVAL); |
1597 | 1601 | ||
@@ -2067,6 +2071,8 @@ long _do_fork(unsigned long clone_flags, | |||
2067 | int __user *child_tidptr, | 2071 | int __user *child_tidptr, |
2068 | unsigned long tls) | 2072 | unsigned long tls) |
2069 | { | 2073 | { |
2074 | struct completion vfork; | ||
2075 | struct pid *pid; | ||
2070 | struct task_struct *p; | 2076 | struct task_struct *p; |
2071 | int trace = 0; | 2077 | int trace = 0; |
2072 | long nr; | 2078 | long nr; |
@@ -2092,43 +2098,40 @@ long _do_fork(unsigned long clone_flags, | |||
2092 | p = copy_process(clone_flags, stack_start, stack_size, | 2098 | p = copy_process(clone_flags, stack_start, stack_size, |
2093 | child_tidptr, NULL, trace, tls, NUMA_NO_NODE); | 2099 | child_tidptr, NULL, trace, tls, NUMA_NO_NODE); |
2094 | add_latent_entropy(); | 2100 | add_latent_entropy(); |
2101 | |||
2102 | if (IS_ERR(p)) | ||
2103 | return PTR_ERR(p); | ||
2104 | |||
2095 | /* | 2105 | /* |
2096 | * Do this prior waking up the new thread - the thread pointer | 2106 | * Do this prior waking up the new thread - the thread pointer |
2097 | * might get invalid after that point, if the thread exits quickly. | 2107 | * might get invalid after that point, if the thread exits quickly. |
2098 | */ | 2108 | */ |
2099 | if (!IS_ERR(p)) { | 2109 | trace_sched_process_fork(current, p); |
2100 | struct completion vfork; | ||
2101 | struct pid *pid; | ||
2102 | |||
2103 | trace_sched_process_fork(current, p); | ||
2104 | 2110 | ||
2105 | pid = get_task_pid(p, PIDTYPE_PID); | 2111 | pid = get_task_pid(p, PIDTYPE_PID); |
2106 | nr = pid_vnr(pid); | 2112 | nr = pid_vnr(pid); |
2107 | 2113 | ||
2108 | if (clone_flags & CLONE_PARENT_SETTID) | 2114 | if (clone_flags & CLONE_PARENT_SETTID) |
2109 | put_user(nr, parent_tidptr); | 2115 | put_user(nr, parent_tidptr); |
2110 | 2116 | ||
2111 | if (clone_flags & CLONE_VFORK) { | 2117 | if (clone_flags & CLONE_VFORK) { |
2112 | p->vfork_done = &vfork; | 2118 | p->vfork_done = &vfork; |
2113 | init_completion(&vfork); | 2119 | init_completion(&vfork); |
2114 | get_task_struct(p); | 2120 | get_task_struct(p); |
2115 | } | 2121 | } |
2116 | |||
2117 | wake_up_new_task(p); | ||
2118 | 2122 | ||
2119 | /* forking complete and child started to run, tell ptracer */ | 2123 | wake_up_new_task(p); |
2120 | if (unlikely(trace)) | ||
2121 | ptrace_event_pid(trace, pid); | ||
2122 | 2124 | ||
2123 | if (clone_flags & CLONE_VFORK) { | 2125 | /* forking complete and child started to run, tell ptracer */ |
2124 | if (!wait_for_vfork_done(p, &vfork)) | 2126 | if (unlikely(trace)) |
2125 | ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid); | 2127 | ptrace_event_pid(trace, pid); |
2126 | } | ||
2127 | 2128 | ||
2128 | put_pid(pid); | 2129 | if (clone_flags & CLONE_VFORK) { |
2129 | } else { | 2130 | if (!wait_for_vfork_done(p, &vfork)) |
2130 | nr = PTR_ERR(p); | 2131 | ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid); |
2131 | } | 2132 | } |
2133 | |||
2134 | put_pid(pid); | ||
2132 | return nr; | 2135 | return nr; |
2133 | } | 2136 | } |
2134 | 2137 | ||