[Devel] [PATCH 1/1] implement s390 clone_with_pids syscall
Serge E. Hallyn
serue at us.ibm.com
Tue Nov 10 08:37:08 PST 2009
This does the s390 hook for v11 of clone-with-pids. This
patch is on top of the linux-cr tree. A pair of patches
against user-cr is coming next to (a) make restart work
with the new clone-with-pids, and (b) demonstrate clone-with-pids
more generally using the ns_exec (namespace manipulation)
program.
The full kernel tree/changelog can be seen as branch cwp.2 at
http://git.kernel.org/gitweb.cgi?p=linux/kernel/git/sergeh/linux-cr.git
The user-space clone-with-pids glue for s390 (clone_s390x.c
from the user-cr package) is now:
struct pid_set {
int num_pids;
pid_t *pids;
};
typedef unsigned long long u64;
typedef unsigned int u32;
typedef int pid_t;
struct clone_args {
u64 clone_flags_high;
u64 child_stack_base;
u64 child_stack_size;
u64 parent_tid_ptr;
u64 child_tid_ptr;
u32 nr_pids;
u32 reserved0;
u64 reserved1;
};
#define do_cwp(flags, pids, args, sz) \
( { \
register unsigned long int __r1 asm ("1") = (unsigned long int)(__NR_clone_with_pids); \
register unsigned long int __r2 asm ("2") = (unsigned long int)(flags); \
register unsigned long int __r3 asm ("3") = (unsigned long int)(args); \
register unsigned long int __r4 asm ("4") = (unsigned long int)(sz); \
register unsigned long int __r5 asm ("5") = (unsigned long int)(pids); \
register long int __result asm ("2"); \
__asm__ __volatile__( \
" svc 0\n" /* do __NR_cwp syscall */ \
" ltgr %%r2,%%r2\n" /* returned 0? */ \
" jnz 1f\n" /* if not goto label 1 */ \
" lg %%r3,0(%%r15)\n" /* get fnarg off stack into arg 1 */ \
" lg %%r2,8(%%r15)\n" /* get fn off stack int r3 basr*/ \
" lgr %%r1,%%r15\n" /* tmp store old stack pointer */ \
" aghi %%r15,-160\n" /* move the stack */ \
" stg %%r1,0(%%r15)\n" /* and save old stack pointer */ \
" basr %%r14,%%r3\n" /* call fn(arg) */ \
" svc 1\n" /* call exit */ \
" 1:\n" \
: "=d" (__result) \
: "d" (__r1), "0" (__r2), "d" (__r3), "d" (__r4), "d" (__r5) \
: "memory"); \
__result; \
} )
int clone_with_pids(int (*fn)(void *), void *child_stack,
unsigned long stack_size, unsigned long flags,
struct pid_set *target_pids, void *arg)
{
struct clone_args clone_args, *ca = &clone_args;
u64 *s;
memset(ca, 0, sizeof(struct clone_args));
ca->nr_pids = target_pids->num_pids;
ca->child_stack_size = stack_size - 16;
ca->child_stack_base = (u64) child_stack;
if (child_stack) {
s = (u64 *) (ca->child_stack_base + ca->child_stack_size);
*--s = (u64) arg;
*--s = (u64) fn;
ca->child_stack_size -= 16;
}
return do_cwp(flags, target_pids->pids, ca,
sizeof(struct clone_args));
}
Changelog:
Nov 09: fix compat code (thanks, Suka)
Nov 10: use orig_gpr2, not gprs[2] for input arg 1
---
arch/s390/kernel/compat_linux.c | 63 ++++++++++++++++++++++++++++++--------
arch/s390/kernel/process.c | 58 +++++++++++++++++++++++++++--------
2 files changed, 94 insertions(+), 27 deletions(-)
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index c6dc681..e26ad2c 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -821,20 +821,55 @@ asmlinkage long sys32_clone(void)
asmlinkage long sys32_clone_with_pids(void)
{
struct pt_regs *regs = task_pt_regs(current);
- unsigned long clone_flags;
- unsigned long newsp;
- int __user *parent_tidptr, *child_tidptr;
- void __user *upid_setp;
-
- clone_flags = regs->gprs[3] & 0xffffffffUL;
- newsp = regs->orig_gpr2 & 0x7fffffffUL;
- parent_tidptr = compat_ptr(regs->gprs[4]);
- child_tidptr = compat_ptr(regs->gprs[5]);
- upid_setp = compat_ptr(regs->gprs[7]);
- if (!newsp)
- newsp = regs->gprs[15];
- return do_fork_with_pids(clone_flags, newsp, regs, 0,
- parent_tidptr, child_tidptr, upid_setp);
+ int rc;
+ int args_size;
+ struct clone_args kca;
+ unsigned long flags;
+ int __user *parent_tid_ptr;
+ int __user *child_tid_ptr;
+ unsigned long __user child_stack;
+ unsigned long stack_size;
+ unsigned int flags_low;
+ struct clone_args __user *uca;
+ pid_t __user *pids;
+
+ flags_low = regs->orig_gpr2 & 0xffffffffUL;
+ uca = compat_ptr(regs->gprs[3]);
+ args_size = regs->gprs[4] & 0xffffffffUL;
+ pids = compat_ptr(regs->gprs[5]);
+
+ rc = fetch_clone_args_from_user(uca, args_size, &kca);
+ if (rc)
+ return rc;
+
+ /*
+ * TODO: Convert 'clone-flags' to 64-bits on all architectures.
+ * TODO: When ->clone_flags_high is non-zero, copy it in to the
+ * higher word(s) of 'flags':
+ *
+ * flags = (kca.clone_flags_high << 32) | flags_low;
+ */
+ flags = flags_low;
+ parent_tid_ptr = (int *)kca.parent_tid_ptr;
+ child_tid_ptr = (int *)kca.child_tid_ptr;
+
+ stack_size = (unsigned long)kca.child_stack_size;
+ child_stack = (unsigned long)kca.child_stack_base;
+ if (child_stack)
+ child_stack += stack_size;
+ else
+ child_stack = regs->gprs[15];
+
+ if (!child_stack)
+ child_stack = regs->gprs[15];
+
+ /*
+ * TODO: On 32-bit systems, clone_flags is passed in as 32-bit value
+ * to several functions. Need to convert clone_flags to 64-bit.
+ */
+ return do_fork_with_pids(flags, child_stack, regs, stack_size,
+ parent_tid_ptr, child_tid_ptr, kca.nr_pids,
+ pids);
}
/*
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 263d3ab..865e791 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -250,20 +250,52 @@ SYSCALL_DEFINE0(clone)
SYSCALL_DEFINE0(clone_with_pids)
{
struct pt_regs *regs = task_pt_regs(current);
- unsigned long clone_flags;
- unsigned long newsp;
- int __user *parent_tidptr, *child_tidptr;
- void __user *upid_setp;
+ int rc;
+ int args_size;
+ struct clone_args kca;
+ unsigned long flags;
+ int __user *parent_tid_ptr;
+ int __user *child_tid_ptr;
+ unsigned long __user child_stack;
+ unsigned long stack_size;
+ unsigned long flags_low;
+ struct clone_args __user *uca;
+ pid_t __user *pids;
+
+ flags_low = regs->orig_gpr2;
+ uca = (struct clone_args __user *)regs->gprs[3];
+ args_size = regs->gprs[4];
+ pids = (pid_t __user *)regs->gprs[5];
+
+ rc = fetch_clone_args_from_user(uca, args_size, &kca);
+ if (rc)
+ return rc;
- clone_flags = regs->gprs[3];
- newsp = regs->orig_gpr2;
- parent_tidptr = (int __user *) regs->gprs[4];
- child_tidptr = (int __user *) regs->gprs[5];
- upid_setp = (void __user *) regs->gprs[7];
- if (!newsp)
- newsp = regs->gprs[15];
- return do_fork_with_pids(clone_flags, newsp, regs, 0, parent_tidptr,
- child_tidptr, upid_setp);
+ /*
+ * TODO: Convert 'clone-flags' to 64-bits on all architectures.
+ * TODO: When ->clone_flags_high is non-zero, copy it in to the
+ * higher word(s) of 'flags':
+ *
+ * flags = (kca.clone_flags_high << 32) | flags_low;
+ */
+ flags = flags_low;
+ parent_tid_ptr = (int *)kca.parent_tid_ptr;
+ child_tid_ptr = (int *)kca.child_tid_ptr;
+
+ stack_size = (unsigned long)kca.child_stack_size;
+ child_stack = (unsigned long)kca.child_stack_base;
+ if (child_stack)
+ child_stack += stack_size;
+ else
+ child_stack = regs->gprs[15];
+
+ /*
+ * TODO: On 32-bit systems, clone_flags is passed in as 32-bit value
+ * to several functions. Need to convert clone_flags to 64-bit.
+ */
+ return do_fork_with_pids(flags, child_stack, regs, stack_size,
+ parent_tid_ptr, child_tid_ptr, kca.nr_pids,
+ pids);
}
/*
--
1.6.1
_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers
More information about the Devel
mailing list