By very popular demand. While we are here, let's refactor the condition for old_mmap_pgoff into an arch-specific one, as it is used more than in one place. * NEWS: Mention this. * configure.ac (case "$host_cpu" in) <s390x>: Set arch_m32 to s390, set cc_flags_m32 to -m31. (st_MPERS([m32])): Add s390x. * defs.h [S390X]: Define NEED_UID16_PARSERS. * linux/s390/arch_sigreturn.c [!S390_FRAME_PTR] (S390_FRAME_PTR): New macro, define to s390_frame_ptr. [!SIGNAL_FRAMESIZE] (SIGNAL_FRAMESIZE): New macro, define to __SIGNAL_FRAMESIZE. [!PTR_TYPE] (PTR_TYPE): New macro, define to unsigned long. (arch_sigreturn): Use S390_FRAME_PTR, SIGNAL_FRAMESIZE, and PTR_TYPE instead of s390_frame_ptr, __SIGNAL_FRAMESIZE, and pointer-sized type, respectively. * linux/s390/get_error.c [!ARCH_REGSET] (ARCH_REGSET): New macro, define * to s390_regset. (get_error): Use it instead of s390_regset. * linux/s390/get_scno.c (arch_get_scno): Likewise. * linux/s390/get_syscall_args.c (get_syscall_args): Likewise. * linux/s390/set_error.c (arch_set_error, arch_set_success): Likewise. * linux/s390/set_scno.c (arch_set_scno): Likewise. * linux/s390x/arch_regs.c (psw_compat_t, s390_compat_regs, s390x_regs_union, s390_frame_ptr, s390x_frame_ptr, s390x_io): New variable. (s390_regset, s390x_regset, ARCH_REGS_FOR_GETREGSET, ARCH_IOVEC_FOR_GETREGSET, ARCH_PC_REG, ARCH_PERSONALITY_0_IOV_SIZE, ARCH_PERSONALITY_1_IOV_SIZE): New macro. * linux/s390x/arch_regs.h (s390_frame_ptr, s390x_frame_ptr): New external definitions. * linux/s390x/arch_rt_sigframe.c: Behave based on tcp->currpers. * linux/s390x/arch_sigreturn.c: Likewise. * linux/s390x/get_error.c: Likewise. * linux/s390x/get_scno.c: Likewise. * linux/s390x/get_syscall_args.c: Likewise. * linux/s390x/set_error.c: Likewise. * linux/s390x/set_scno.c: Likewise. * linux/s390x/errnoent1.h: New file. * linux/s390x/ioctls_arch1.h: Likewise. * linux/s390x/ioctls_inc1.h: Likewise. * linux/s390x/signalent1.h: Likewise. * linux/s390x/syscallent1.h: Likewise. * supported_personalities.h [S390X]: Define SUPPORTED_PERSONALITIES to 2. * tests/strace-V.test: Add s390 to the list of architectures that have m32 personality. * linux/s390/arch_defs.h (HAVE_ARCH_OLD_MMAP_PGOFF): New definition. * linux/s390x/arch_defs.h: Likewise. * mem.c: Replace #ifdef S390 with #ifdef HAVE_ARCH_OLD_MMAP_PGOFF. * pathtrace.c: Likewise. --- NEWS | 1 + configure.ac | 4 +++- defs.h | 2 +- linux/s390/arch_defs.h | 1 + linux/s390/arch_sigreturn.c | 16 +++++++++++++--- linux/s390/get_error.c | 10 +++++++--- linux/s390/get_scno.c | 8 ++++++-- linux/s390/get_syscall_args.c | 16 ++++++++++------ linux/s390/set_error.c | 8 ++++++-- linux/s390/set_scno.c | 6 +++++- linux/s390x/arch_defs.h | 1 + linux/s390x/arch_regs.c | 37 ++++++++++++++++++++++++++++++++++++- linux/s390x/arch_regs.h | 3 ++- linux/s390x/arch_rt_sigframe.c | 5 ++++- linux/s390x/arch_sigreturn.c | 26 ++++++++++++++++++++++++++ linux/s390x/errnoent1.h | 1 + linux/s390x/get_error.c | 23 ++++++++++++++++++++++- linux/s390x/get_scno.c | 21 ++++++++++++++++++++- linux/s390x/get_syscall_args.c | 22 +++++++++++++++++++++- linux/s390x/ioctls_arch1.h | 1 + linux/s390x/ioctls_inc1.h | 1 + linux/s390x/set_error.c | 34 +++++++++++++++++++++++++++++++++- linux/s390x/set_scno.c | 21 ++++++++++++++++++++- linux/s390x/signalent1.h | 1 + linux/s390x/syscallent1.h | 1 + mem.c | 4 ++-- pathtrace.c | 2 +- supported_personalities.h | 1 + tests/strace-V.test | 2 +- 29 files changed, 248 insertions(+), 31 deletions(-) create mode 100644 linux/s390x/errnoent1.h create mode 100644 linux/s390x/ioctls_arch1.h create mode 100644 linux/s390x/ioctls_inc1.h create mode 100644 linux/s390x/signalent1.h create mode 100644 linux/s390x/syscallent1.h diff --git a/NEWS b/NEWS index 0dc23d6..550fc38 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,7 @@ Noteworthy changes in release ?.?? (????-??-??) * Updated lists of MSG_*, NT_*, and SHM_* constants. * Added manual page for the strace-log-merge command. * Updated lists of ioctl commands from Linux 4.15. + * Implemented biarch support for s390x. * Implemented an optional support for symbol demangling in strace -k output (activated by --with-libiberty configure option). * Information about availability of demangling and reliable personality diff --git a/configure.ac b/configure.ac index 5af1111..a1391c7 100644 --- a/configure.ac +++ b/configure.ac @@ -145,6 +145,8 @@ s390) ;; s390x) arch=s390x + arch_m32=s390 + cc_flags_m32=-m31 AC_DEFINE([S390X], 1, [Define for the S390x architecture.]) ;; hppa*|parisc*) @@ -980,7 +982,7 @@ AC_ARG_ENABLE([mpers], esac], [enable_mpers=yes]) -st_MPERS([m32], [aarch64|powerpc64|riscv|sparc64|tile|x32|x86_64]) +st_MPERS([m32], [aarch64|powerpc64|riscv|s390x|sparc64|tile|x32|x86_64]) st_MPERS([mx32], [x86_64]) AX_VALGRIND_DFLT([sgcheck], [off]) diff --git a/defs.h b/defs.h index 3e42908..2311d86 100644 --- a/defs.h +++ b/defs.h @@ -335,7 +335,7 @@ extern const struct xlat whence_codes[]; || defined(M68K) \ || defined(MICROBLAZE) \ || defined(RISCV) \ - || defined(S390) \ + || defined(S390) || defined(S390X) \ || defined(SH) || defined(SH64) \ || defined(SPARC) || defined(SPARC64) \ /**/ diff --git a/linux/s390/arch_defs.h b/linux/s390/arch_defs.h index 285947f..f49582b 100644 --- a/linux/s390/arch_defs.h +++ b/linux/s390/arch_defs.h @@ -1 +1,2 @@ #define HAVE_ARCH_OLD_MMAP 1 +#define HAVE_ARCH_OLD_MMAP_PGOFF 1 diff --git a/linux/s390/arch_sigreturn.c b/linux/s390/arch_sigreturn.c index d1b8598..9c9e0dd 100644 --- a/linux/s390/arch_sigreturn.c +++ b/linux/s390/arch_sigreturn.c @@ -1,11 +1,21 @@ +#ifndef S390_FRAME_PTR +# define S390_FRAME_PTR s390_frame_ptr +#endif +#ifndef SIGNAL_FRAMESIZE +# define SIGNAL_FRAMESIZE __SIGNAL_FRAMESIZE +#endif +#ifndef PTR_TYPE +# define PTR_TYPE unsigned long +#endif + static void arch_sigreturn(struct tcb *tcp) { - unsigned long mask[NSIG_BYTES / sizeof(long)]; - const unsigned long addr = *s390_frame_ptr + __SIGNAL_FRAMESIZE; + PTR_TYPE mask[NSIG_BYTES / sizeof(PTR_TYPE)]; + const PTR_TYPE addr = *S390_FRAME_PTR + SIGNAL_FRAMESIZE; if (umove(tcp, addr, &mask) < 0) { - tprintf("{mask=%#lx}", addr); + tprintf("{mask=%#llx}", zero_extend_signed_to_ull(addr)); } else { tprintsigmask_addr("{mask=", mask); tprints("}"); diff --git a/linux/s390/get_error.c b/linux/s390/get_error.c index 6d4d0a5..6f3925b 100644 --- a/linux/s390/get_error.c +++ b/linux/s390/get_error.c @@ -1,12 +1,16 @@ #include "negated_errno.h" +#ifndef ARCH_REGSET +# define ARCH_REGSET s390_regset +#endif + static void get_error(struct tcb *tcp, const bool check_errno) { - if (check_errno && is_negated_errno(s390_regset.gprs[2])) { + if (check_errno && is_negated_errno(ARCH_REGSET.gprs[2])) { tcp->u_rval = -1; - tcp->u_error = -s390_regset.gprs[2]; + tcp->u_error = -ARCH_REGSET.gprs[2]; } else { - tcp->u_rval = s390_regset.gprs[2]; + tcp->u_rval = ARCH_REGSET.gprs[2]; } } diff --git a/linux/s390/get_scno.c b/linux/s390/get_scno.c index d323860..2661795 100644 --- a/linux/s390/get_scno.c +++ b/linux/s390/get_scno.c @@ -1,8 +1,12 @@ +#ifndef ARCH_REGSET +# define ARCH_REGSET s390_regset +#endif + /* Return codes: 1 - ok, 0 - ignore, other - error. */ static int arch_get_scno(struct tcb *tcp) { - tcp->scno = s390_regset.gprs[2] ? - s390_regset.gprs[2] : s390_regset.gprs[1]; + tcp->scno = ARCH_REGSET.gprs[2] ? + ARCH_REGSET.gprs[2] : ARCH_REGSET.gprs[1]; return 1; } diff --git a/linux/s390/get_syscall_args.c b/linux/s390/get_syscall_args.c index ebf6c6c..2c35380 100644 --- a/linux/s390/get_syscall_args.c +++ b/linux/s390/get_syscall_args.c @@ -1,12 +1,16 @@ +#ifndef ARCH_REGSET +# define ARCH_REGSET s390_regset +#endif + /* Return -1 on error or 1 on success (never 0!). */ static int get_syscall_args(struct tcb *tcp) { - tcp->u_arg[0] = s390_regset.orig_gpr2; - tcp->u_arg[1] = s390_regset.gprs[3]; - tcp->u_arg[2] = s390_regset.gprs[4]; - tcp->u_arg[3] = s390_regset.gprs[5]; - tcp->u_arg[4] = s390_regset.gprs[6]; - tcp->u_arg[5] = s390_regset.gprs[7]; + tcp->u_arg[0] = ARCH_REGSET.orig_gpr2; + tcp->u_arg[1] = ARCH_REGSET.gprs[3]; + tcp->u_arg[2] = ARCH_REGSET.gprs[4]; + tcp->u_arg[3] = ARCH_REGSET.gprs[5]; + tcp->u_arg[4] = ARCH_REGSET.gprs[6]; + tcp->u_arg[5] = ARCH_REGSET.gprs[7]; return 1; } diff --git a/linux/s390/set_error.c b/linux/s390/set_error.c index 7262e5c..f73e578 100644 --- a/linux/s390/set_error.c +++ b/linux/s390/set_error.c @@ -1,13 +1,17 @@ +#ifndef ARCH_REGSET +# define ARCH_REGSET s390_regset +#endif + static int arch_set_error(struct tcb *tcp) { - s390_regset.gprs[2] = -tcp->u_error; + ARCH_REGSET.gprs[2] = -tcp->u_error; return set_regs(tcp->pid); } static int arch_set_success(struct tcb *tcp) { - s390_regset.gprs[2] = tcp->u_rval; + ARCH_REGSET.gprs[2] = tcp->u_rval; return set_regs(tcp->pid); } diff --git a/linux/s390/set_scno.c b/linux/s390/set_scno.c index c7a3110..6bb9999 100644 --- a/linux/s390/set_scno.c +++ b/linux/s390/set_scno.c @@ -1,6 +1,10 @@ +#ifndef ARCH_REGSET +# define ARCH_REGSET s390_regset +#endif + static int arch_set_scno(struct tcb *tcp, kernel_ulong_t scno) { - s390_regset.gprs[2] = scno; + ARCH_REGSET.gprs[2] = scno; return set_regs(tcp->pid); } diff --git a/linux/s390x/arch_defs.h b/linux/s390x/arch_defs.h index 285947f..f49582b 100644 --- a/linux/s390x/arch_defs.h +++ b/linux/s390x/arch_defs.h @@ -1 +1,2 @@ #define HAVE_ARCH_OLD_MMAP 1 +#define HAVE_ARCH_OLD_MMAP_PGOFF 1 diff --git a/linux/s390x/arch_regs.c b/linux/s390x/arch_regs.c index 62aece7..b5efde7 100644 --- a/linux/s390x/arch_regs.c +++ b/linux/s390x/arch_regs.c @@ -1 +1,36 @@ -#include "s390/arch_regs.c" +typedef struct { + uint32_t mask; + uint32_t addr; +} ATTRIBUTE_ALIGNED(8) psw_compat_t; + +typedef struct { + psw_compat_t psw; + uint32_t gprs[NUM_GPRS]; + uint32_t acrs[NUM_ACRS]; + uint32_t orig_gpr2; +} s390_compat_regs; + +static union { + s390_compat_regs s390_regs; + s390_regs s390x_regs; +} s390x_regs_union; + +#define s390_regset s390x_regs_union.s390_regs +#define s390x_regset s390x_regs_union.s390x_regs + +uint32_t *const s390_frame_ptr = &s390_regset.gprs[15]; +unsigned long *const s390x_frame_ptr = &s390x_regset.gprs[15]; + +static struct iovec s390x_io = { + .iov_base = &s390x_regs_union, +}; + + +#define ARCH_REGS_FOR_GETREGSET s390x_regs_union +#define ARCH_IOVEC_FOR_GETREGSET s390x_io +#define ARCH_PC_REG \ + (s390x_io.iov_len == sizeof(s390_regset) ? \ + s390_regset.psw.addr : s390x_regset.psw.addr) + +#define ARCH_PERSONALITY_0_IOV_SIZE sizeof(s390x_regset) +#define ARCH_PERSONALITY_1_IOV_SIZE sizeof(s390_regset) diff --git a/linux/s390x/arch_regs.h b/linux/s390x/arch_regs.h index 14fced4..1f8b57a 100644 --- a/linux/s390x/arch_regs.h +++ b/linux/s390x/arch_regs.h @@ -1 +1,2 @@ -#include "s390/arch_regs.h" +extern uint32_t *const s390_frame_ptr; +extern unsigned long *const s390x_frame_ptr; diff --git a/linux/s390x/arch_rt_sigframe.c b/linux/s390x/arch_rt_sigframe.c index 9731c0e..9c0255f 100644 --- a/linux/s390x/arch_rt_sigframe.c +++ b/linux/s390x/arch_rt_sigframe.c @@ -1 +1,4 @@ -#include "s390/arch_rt_sigframe.c" +FUNC_GET_RT_SIGFRAME_ADDR +{ + return tcp->currpers == 1 ? *s390_frame_ptr : *s390x_frame_ptr; +} diff --git a/linux/s390x/arch_sigreturn.c b/linux/s390x/arch_sigreturn.c index 679a395..edc9edd 100644 --- a/linux/s390x/arch_sigreturn.c +++ b/linux/s390x/arch_sigreturn.c @@ -1 +1,27 @@ +#include <stdint.h> + +#define S390_SIGNAL_FRAMESIZE 96 + +#define SIGNAL_FRAMESIZE S390_SIGNAL_FRAMESIZE +#define PTR_TYPE uint32_t +#define S390_FRAME_PTR s390_frame_ptr +#define arch_sigreturn s390_arch_sigreturn #include "s390/arch_sigreturn.c" +#undef arch_sigreturn +#undef S390_FRAME_PTR +#undef PTR_TYPE +#undef SIGNAL_FRAMESIZE + +#define S390_FRAME_PTR s390x_frame_ptr +#define arch_sigreturn s390x_arch_sigreturn +#include "s390/arch_sigreturn.c" +#undef arch_sigreturn + +static void +arch_sigreturn(struct tcb *tcp) +{ + if (tcp->currpers == 1) + s390_arch_sigreturn(tcp); + else + s390x_arch_sigreturn(tcp); +} diff --git a/linux/s390x/errnoent1.h b/linux/s390x/errnoent1.h new file mode 100644 index 0000000..c0f7787 --- /dev/null +++ b/linux/s390x/errnoent1.h @@ -0,0 +1 @@ +#include "errnoent.h" diff --git a/linux/s390x/get_error.c b/linux/s390x/get_error.c index 8e3944c..f35030b 100644 --- a/linux/s390x/get_error.c +++ b/linux/s390x/get_error.c @@ -1 +1,22 @@ -#include "s390/get_error.c" +#include "negated_errno.h" + +#define get_error s390x_get_error +#define ARCH_REGSET s390x_regset +#include "../s390/get_error.c" +#undef ARCH_REGSET +#undef get_error + +#define get_error s390_get_error +#define ARCH_REGSET s390_regset +#include "../s390/get_error.c" +#undef ARCH_REGSET +#undef get_error + +static void +get_error(struct tcb *tcp, const bool check_errno) +{ + if (tcp->currpers == 0) + s390x_get_error(tcp, check_errno); + else + s390_get_error(tcp, check_errno); +} diff --git a/linux/s390x/get_scno.c b/linux/s390x/get_scno.c index 71816fb..620d6bc 100644 --- a/linux/s390x/get_scno.c +++ b/linux/s390x/get_scno.c @@ -1 +1,20 @@ -#include "s390/get_scno.c" +#define arch_get_scno s390x_get_scno +#define ARCH_REGSET s390x_regset +#include "../s390/get_scno.c" +#undef ARCH_REGSET +#undef arch_get_scno + +#define arch_get_scno s390_get_scno +#define ARCH_REGSET s390_regset +#include "../s390/get_scno.c" +#undef ARCH_REGSET +#undef arch_get_scno + +static int +arch_get_scno(struct tcb *tcp) +{ + if (s390x_io.iov_len == sizeof(s390_regset)) + return s390_get_scno(tcp); + + return s390x_get_scno(tcp); +} diff --git a/linux/s390x/get_syscall_args.c b/linux/s390x/get_syscall_args.c index 4ded41d..91c5786 100644 --- a/linux/s390x/get_syscall_args.c +++ b/linux/s390x/get_syscall_args.c @@ -1 +1,21 @@ -#include "s390/get_syscall_args.c" +#define get_syscall_args s390x_get_syscall_args +#define ARCH_REGSET s390x_regset +#include "../s390/get_syscall_args.c" +#undef ARCH_REGSET +#undef get_syscall_args + +#define get_syscall_args s390_get_syscall_args +#define ARCH_REGSET s390_regset +#include "../s390/get_syscall_args.c" +#undef ARCH_REGSET +#undef get_syscall_args + +/* Return -1 on error or 1 on success (never 0!). */ +static int +get_syscall_args(struct tcb *tcp) +{ + if (tcp->currpers == 1) + return s390_get_syscall_args(tcp); + + return s390x_get_syscall_args(tcp); +} diff --git a/linux/s390x/ioctls_arch1.h b/linux/s390x/ioctls_arch1.h new file mode 100644 index 0000000..4a16cb5 --- /dev/null +++ b/linux/s390x/ioctls_arch1.h @@ -0,0 +1 @@ +#include "s390/ioctls_arch0.h" diff --git a/linux/s390x/ioctls_inc1.h b/linux/s390x/ioctls_inc1.h new file mode 100644 index 0000000..e09b6c6 --- /dev/null +++ b/linux/s390x/ioctls_inc1.h @@ -0,0 +1 @@ +#include "s390/ioctls_inc0.h" diff --git a/linux/s390x/set_error.c b/linux/s390x/set_error.c index 737ddef..187734f 100644 --- a/linux/s390x/set_error.c +++ b/linux/s390x/set_error.c @@ -1 +1,33 @@ -#include "s390/set_error.c" +#define arch_set_error s390x_set_error +#define arch_set_success s390x_set_success +#define ARCH_REGSET s390x_regset +#include "../s390/set_error.c" +#undef ARCH_REGSET +#undef arch_set_success +#undef arch_set_error + +#define arch_set_error s390_set_error +#define arch_set_success s390_set_success +#define ARCH_REGSET s390_regset +#include "../s390/set_error.c" +#undef ARCH_REGSET +#undef arch_set_success +#undef arch_set_error + +static int +arch_set_error(struct tcb *tcp) +{ + if (tcp->currpers == 1) + return s390_set_error(tcp); + + return s390x_set_error(tcp); +} + +static int +arch_set_success(struct tcb *tcp) +{ + if (tcp->currpers == 1) + return s390_set_success(tcp); + + return s390x_set_success(tcp); +} diff --git a/linux/s390x/set_scno.c b/linux/s390x/set_scno.c index 9cea4d1..97c9e2b 100644 --- a/linux/s390x/set_scno.c +++ b/linux/s390x/set_scno.c @@ -1 +1,20 @@ -#include "s390/set_scno.c" +#define arch_set_scno s390x_set_scno +#define ARCH_REGSET s390x_regset +#include "../s390/set_scno.c" +#undef ARCH_REGSET +#undef arch_set_scno + +#define arch_set_scno s390_set_scno +#define ARCH_REGSET s390_regset +#include "../s390/set_scno.c" +#undef ARCH_REGSET +#undef arch_set_scno + +static int +arch_set_scno(struct tcb *tcp, kernel_ulong_t scno) +{ + if (tcp->currpers == 1) + return s390_set_scno(tcp, scno); + + return s390x_set_scno(tcp, scno); +} diff --git a/linux/s390x/signalent1.h b/linux/s390x/signalent1.h new file mode 100644 index 0000000..093cba7 --- /dev/null +++ b/linux/s390x/signalent1.h @@ -0,0 +1 @@ +#include "signalent.h" diff --git a/linux/s390x/syscallent1.h b/linux/s390x/syscallent1.h new file mode 100644 index 0000000..b6bdaa5 --- /dev/null +++ b/linux/s390x/syscallent1.h @@ -0,0 +1 @@ +#include "../s390/syscallent.h" diff --git a/mem.c b/mem.c index 6eb974d..1da607d 100644 --- a/mem.c +++ b/mem.c @@ -144,7 +144,7 @@ SYS_FUNC(old_mmap) return RVAL_DECODED | RVAL_HEX; } -# ifdef S390 +#if defined HAVE_ARCH_OLD_MMAP_PGOFF /* Params are pointed to by u_arg[0], offset is in pages */ SYS_FUNC(old_mmap_pgoff) { @@ -163,7 +163,7 @@ SYS_FUNC(old_mmap_pgoff) return RVAL_DECODED | RVAL_HEX; } -# endif /* S390 */ +# endif /* HAVE_ARCH_OLD_MMAP_PGOFF */ #endif /* HAVE_ARCH_OLD_MMAP */ /* Params are passed directly, offset is in bytes */ diff --git a/pathtrace.c b/pathtrace.c index 9b39fc0..99b8711 100644 --- a/pathtrace.c +++ b/pathtrace.c @@ -216,7 +216,7 @@ pathtrace_match_set(struct tcb *tcp, struct path_set *set) #ifdef HAVE_ARCH_OLD_MMAP case SEN_old_mmap: -# if defined(S390) +# ifdef HAVE_ARCH_OLD_MMAP_PGOFF case SEN_old_mmap_pgoff: # endif { diff --git a/supported_personalities.h b/supported_personalities.h index 6f18ed3..58ee027 100644 --- a/supported_personalities.h +++ b/supported_personalities.h @@ -33,6 +33,7 @@ #elif defined AARCH64 \ || defined POWERPC64 \ || defined RISCV \ + || defined S390X \ || defined SPARC64 \ || defined TILE \ || defined X32 diff --git a/tests/strace-V.test b/tests/strace-V.test index 677818f..eb05e86 100755 --- a/tests/strace-V.test +++ b/tests/strace-V.test @@ -48,7 +48,7 @@ x86_64) option_m32=$(getoption HAVE_M32_MPERS ' m32-mpers' ' no-m32-mpers') option_mx32=$(getoption HAVE_MX32_MPERS ' mx32-mpers' ' no-mx32-mpers') ;; -aarch64|powerpc64|riscv|sparc64|tile|x32) +aarch64|powerpc64|riscv|s390x|sparc64|tile|x32) option_m32=$(getoption HAVE_M32_MPERS ' m32-mpers' ' no-m32-mpers') ;; esac -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-s390" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html