|
@@ -1238,7 +1238,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
|
|
unsigned long stack_size,
|
|
|
int __user *child_tidptr,
|
|
|
struct pid *pid,
|
|
|
- int trace)
|
|
|
+ int trace,
|
|
|
+ unsigned long tls)
|
|
|
{
|
|
|
int retval;
|
|
|
struct task_struct *p;
|
|
@@ -1447,7 +1448,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
|
|
retval = copy_io(clone_flags, p);
|
|
|
if (retval)
|
|
|
goto bad_fork_cleanup_namespaces;
|
|
|
- retval = copy_thread(clone_flags, stack_start, stack_size, p);
|
|
|
+ retval = copy_thread_tls(clone_flags, stack_start, stack_size, p, tls);
|
|
|
if (retval)
|
|
|
goto bad_fork_cleanup_io;
|
|
|
|
|
@@ -1659,7 +1660,7 @@ static inline void init_idle_pids(struct pid_link *links)
|
|
|
struct task_struct *fork_idle(int cpu)
|
|
|
{
|
|
|
struct task_struct *task;
|
|
|
- task = copy_process(CLONE_VM, 0, 0, NULL, &init_struct_pid, 0);
|
|
|
+ task = copy_process(CLONE_VM, 0, 0, NULL, &init_struct_pid, 0, 0);
|
|
|
if (!IS_ERR(task)) {
|
|
|
init_idle_pids(task->pids);
|
|
|
init_idle(task, cpu);
|
|
@@ -1674,11 +1675,12 @@ struct task_struct *fork_idle(int cpu)
|
|
|
* It copies the process, and if successful kick-starts
|
|
|
* it and waits for it to finish using the VM if required.
|
|
|
*/
|
|
|
-long do_fork(unsigned long clone_flags,
|
|
|
+long _do_fork(unsigned long clone_flags,
|
|
|
unsigned long stack_start,
|
|
|
unsigned long stack_size,
|
|
|
int __user *parent_tidptr,
|
|
|
- int __user *child_tidptr)
|
|
|
+ int __user *child_tidptr,
|
|
|
+ unsigned long tls)
|
|
|
{
|
|
|
struct task_struct *p;
|
|
|
int trace = 0;
|
|
@@ -1703,7 +1705,7 @@ long do_fork(unsigned long clone_flags,
|
|
|
}
|
|
|
|
|
|
p = copy_process(clone_flags, stack_start, stack_size,
|
|
|
- child_tidptr, NULL, trace);
|
|
|
+ child_tidptr, NULL, trace, tls);
|
|
|
/*
|
|
|
* Do this prior waking up the new thread - the thread pointer
|
|
|
* might get invalid after that point, if the thread exits quickly.
|
|
@@ -1744,20 +1746,34 @@ long do_fork(unsigned long clone_flags,
|
|
|
return nr;
|
|
|
}
|
|
|
|
|
|
+#ifndef CONFIG_HAVE_COPY_THREAD_TLS
|
|
|
+/* For compatibility with architectures that call do_fork directly rather than
|
|
|
+ * using the syscall entry points below. */
|
|
|
+long do_fork(unsigned long clone_flags,
|
|
|
+ unsigned long stack_start,
|
|
|
+ unsigned long stack_size,
|
|
|
+ int __user *parent_tidptr,
|
|
|
+ int __user *child_tidptr)
|
|
|
+{
|
|
|
+ return _do_fork(clone_flags, stack_start, stack_size,
|
|
|
+ parent_tidptr, child_tidptr, 0);
|
|
|
+}
|
|
|
+#endif
|
|
|
+
|
|
|
/*
|
|
|
* Create a kernel thread.
|
|
|
*/
|
|
|
pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
|
|
|
{
|
|
|
- return do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
|
|
|
- (unsigned long)arg, NULL, NULL);
|
|
|
+ return _do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn,
|
|
|
+ (unsigned long)arg, NULL, NULL, 0);
|
|
|
}
|
|
|
|
|
|
#ifdef __ARCH_WANT_SYS_FORK
|
|
|
SYSCALL_DEFINE0(fork)
|
|
|
{
|
|
|
#ifdef CONFIG_MMU
|
|
|
- return do_fork(SIGCHLD, 0, 0, NULL, NULL);
|
|
|
+ return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0);
|
|
|
#else
|
|
|
/* can not support in nommu mode */
|
|
|
return -EINVAL;
|
|
@@ -1768,8 +1784,8 @@ SYSCALL_DEFINE0(fork)
|
|
|
#ifdef __ARCH_WANT_SYS_VFORK
|
|
|
SYSCALL_DEFINE0(vfork)
|
|
|
{
|
|
|
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,
|
|
|
- 0, NULL, NULL);
|
|
|
+ return _do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0,
|
|
|
+ 0, NULL, NULL, 0);
|
|
|
}
|
|
|
#endif
|
|
|
|
|
@@ -1777,27 +1793,27 @@ SYSCALL_DEFINE0(vfork)
|
|
|
#ifdef CONFIG_CLONE_BACKWARDS
|
|
|
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
|
|
|
int __user *, parent_tidptr,
|
|
|
- int, tls_val,
|
|
|
+ unsigned long, tls,
|
|
|
int __user *, child_tidptr)
|
|
|
#elif defined(CONFIG_CLONE_BACKWARDS2)
|
|
|
SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags,
|
|
|
int __user *, parent_tidptr,
|
|
|
int __user *, child_tidptr,
|
|
|
- int, tls_val)
|
|
|
+ unsigned long, tls)
|
|
|
#elif defined(CONFIG_CLONE_BACKWARDS3)
|
|
|
SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp,
|
|
|
int, stack_size,
|
|
|
int __user *, parent_tidptr,
|
|
|
int __user *, child_tidptr,
|
|
|
- int, tls_val)
|
|
|
+ unsigned long, tls)
|
|
|
#else
|
|
|
SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
|
|
|
int __user *, parent_tidptr,
|
|
|
int __user *, child_tidptr,
|
|
|
- int, tls_val)
|
|
|
+ unsigned long, tls)
|
|
|
#endif
|
|
|
{
|
|
|
- return do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr);
|
|
|
+ return _do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr, tls);
|
|
|
}
|
|
|
#endif
|
|
|
|