s390: switch to generic fork/vfork/clone
authorAl Viro <viro@zeniv.linux.org.uk>
Sun, 21 Oct 2012 20:44:27 +0000 (16:44 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 29 Nov 2012 03:44:37 +0000 (22:44 -0500)
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
arch/s390/Kconfig
arch/s390/include/asm/unistd.h
arch/s390/kernel/process.c

index a163784e72c8df809690f0a446bc56749ee6b246..3cbb8757704ef6d2617328db099164406dfc1af3 100644 (file)
@@ -141,6 +141,7 @@ config S390
        select GENERIC_KERNEL_EXECVE
        select HAVE_MOD_ARCH_SPECIFIC
        select MODULES_USE_ELF_RELA
+       select CLONE_BACKWARDS2
 
 config SCHED_OMIT_FRAME_POINTER
        def_bool y
index ccbcab7742cdfb15502d0de1337a3d752be0b21f..086bb8eaf6abf3a75e6df3992519f69f1513851c 100644 (file)
@@ -54,6 +54,9 @@
 #   define __ARCH_WANT_COMPAT_SYS_RT_SIGSUSPEND
 # endif
 #define __ARCH_WANT_SYS_EXECVE
+#define __ARCH_WANT_SYS_FORK
+#define __ARCH_WANT_SYS_VFORK
+#define __ARCH_WANT_SYS_CLONE
 
 /*
  * "Conditional" syscalls
index cd31ad457a9bdb7890a0ff7eae840a63f5f0f48f..e37677796a09242d08e490d296c500ff9ef84489 100644 (file)
@@ -118,7 +118,7 @@ void release_thread(struct task_struct *dead_task)
 
 int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
                unsigned long arg,
-               struct task_struct *p, struct pt_regs *regs)
+               struct task_struct *p, struct pt_regs *unused)
 {
        struct thread_info *ti;
        struct fake_frame
@@ -150,7 +150,7 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
        frame->sf.gprs[9] = (unsigned long) frame;
 
        /* Store access registers to kernel stack of new process. */
-       if (unlikely(!regs)) {
+       if (unlikely(p->flags & PF_KTHREAD)) {
                /* kernel thread */
                memset(&frame->childregs, 0, sizeof(struct pt_regs));
                frame->childregs.psw.mask = psw_kernel_bits | PSW_MASK_DAT |
@@ -164,9 +164,10 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
 
                return 0;
        }
-       frame->childregs = *regs;
+       frame->childregs = *current_pt_regs();
        frame->childregs.gprs[2] = 0;   /* child returns 0 on fork. */
-       frame->childregs.gprs[15] = new_stackp;
+       if (new_stackp)
+               frame->childregs.gprs[15] = new_stackp;
 
        /* Don't copy runtime instrumentation info */
        p->thread.ri_cb = NULL;
@@ -183,57 +184,24 @@ int copy_thread(unsigned long clone_flags, unsigned long new_stackp,
               sizeof(s390_fp_regs));
        /* Set a new TLS ?  */
        if (clone_flags & CLONE_SETTLS)
-               p->thread.acrs[0] = regs->gprs[6];
+               p->thread.acrs[0] = frame->childregs.gprs[6];
 #else /* CONFIG_64BIT */
        /* Save the fpu registers to new thread structure. */
        save_fp_regs(&p->thread.fp_regs);
        /* Set a new TLS ?  */
        if (clone_flags & CLONE_SETTLS) {
+               unsigned long tls = frame->childregs.gprs[6];
                if (is_compat_task()) {
-                       p->thread.acrs[0] = (unsigned int) regs->gprs[6];
+                       p->thread.acrs[0] = (unsigned int)tls;
                } else {
-                       p->thread.acrs[0] = (unsigned int)(regs->gprs[6] >> 32);
-                       p->thread.acrs[1] = (unsigned int) regs->gprs[6];
+                       p->thread.acrs[0] = (unsigned int)(tls >> 32);
+                       p->thread.acrs[1] = (unsigned int)tls;
                }
        }
 #endif /* CONFIG_64BIT */
        return 0;
 }
 
-SYSCALL_DEFINE0(fork)
-{
-       struct pt_regs *regs = task_pt_regs(current);
-       return do_fork(SIGCHLD, regs->gprs[15], regs, 0, NULL, NULL);
-}
-
-SYSCALL_DEFINE4(clone, unsigned long, newsp, unsigned long, clone_flags,
-               int __user *, parent_tidptr, int __user *, child_tidptr)
-{
-       struct pt_regs *regs = task_pt_regs(current);
-
-       if (!newsp)
-               newsp = regs->gprs[15];
-       return do_fork(clone_flags, newsp, regs, 0,
-                      parent_tidptr, child_tidptr);
-}
-
-/*
- * This is trivial, and on the face of it looks like it
- * could equally well be done in user mode.
- *
- * Not so, for quite unobvious reasons - register pressure.
- * In user mode vfork() cannot have a stack frame, and if
- * done by calling the "clone()" system call directly, you
- * do not have enough call-clobbered registers to hold all
- * the information you need.
- */
-SYSCALL_DEFINE0(vfork)
-{
-       struct pt_regs *regs = task_pt_regs(current);
-       return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
-                      regs->gprs[15], regs, 0, NULL, NULL);
-}
-
 asmlinkage void execve_tail(void)
 {
        current->thread.fp_regs.fpc = 0;