fallocate() on s390 This patch implements support of fallocate system call on s390(x) platform. A wrapper is added to address the issue which s390 ABI has with the arguments of this system call. This is the suggested wrapper in glibc to handle this system call on s390. .globl __fallocate ENTRY(__fallocate) stm %r6,%r7,28(%r15) /* save %r6/%r7 on stack */ cfi_offset (%r7, -68) cfi_offset (%r6, -72) lm %r6,%r7,96(%r15) /* load loff_t len from stack */ svc SYS_ify(fallocate) lm %r6,%r7,28(%r15) /* restore %r6/%r7 from stack */ br %r14 PSEUDO_END(__fallocate) Signed-off-by: Martin Schwidefsky diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S index acc4154..8e0071c 100644 --- a/arch/s390/kernel/compat_wrapper.S +++ b/arch/s390/kernel/compat_wrapper.S @@ -1683,6 +1683,16 @@ compat_sys_utimes_wrapper: llgtr %r3,%r3 # struct compat_timeval * jg compat_sys_utimes + .globl sys_fallocate_wrapper +sys_fallocate_wrapper: + lgfr %r2,%r2 # int + lgfr %r3,%r3 # int + sllg %r4,%r4,32 # get high word of 64bit loff_t + lr %r4,%r5 # get low word of 64bit loff_t + sllg %r5,%r6,32 # get high word of 64bit loff_t + l %r5,164(%r15) # get low word of 64bit loff_t + jg sys_fallocate + .globl compat_sys_utimensat_wrapper compat_sys_utimensat_wrapper: llgfr %r2,%r2 # unsigned int diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c index 1c90c7e..632fd0f 100644 --- a/arch/s390/kernel/sys_s390.c +++ b/arch/s390/kernel/sys_s390.c @@ -265,3 +265,32 @@ s390_fadvise64_64(struct fadvise64_64_args __user *args) return -EFAULT; return sys_fadvise64_64(a.fd, a.offset, a.len, a.advice); } + +#ifndef CONFIG_64BIT +/* + * This is a wrapper to call sys_fallocate(). For 31 bit s390 the last + * 64 bit argument "len" is split into the upper and lower 32 bits. The + * system call wrapper in the user space loads the value to %r6/%r7. + * The code in entry.S keeps the values in %r2 - %r6 where they are and + * stores %r7 to 96(%r15). But the standard C linkage requires that + * the whole 64 bit value for len is stored on the stack and doesn't + * use %r6 at all. So s390_fallocate has to convert the arguments from + * %r2: fd, %r3: mode, %r4/%r5: offset, %r6/96(%r15)-99(%r15): len + * to + * %r2: fd, %r3: mode, %r4/%r5: offset, 96(%r15)-103(%r15): len + */ +asmlinkage long s390_fallocate(int fd, int mode, loff_t offset, + u32 len_high, u32 len_low) +{ + union { + u64 len; + struct { + u32 high; + u32 low; + }; + } cv; + cv.high = len_high; + cv.low = len_low; + return sys_fallocate(fd, mode, offset, cv.len); +} +#endif diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S index 738feb4..9c6a843 100644 --- a/arch/s390/kernel/syscalls.S +++ b/arch/s390/kernel/syscalls.S @@ -322,6 +322,7 @@ NI_SYSCALL /* 310 sys_move_pages */ SYSCALL(sys_getcpu,sys_getcpu,sys_getcpu_wrapper) SYSCALL(sys_epoll_pwait,sys_epoll_pwait,compat_sys_epoll_pwait_wrapper) SYSCALL(sys_utimes,sys_utimes,compat_sys_utimes_wrapper) +SYSCALL(s390_fallocate,sys_fallocate,sys_fallocate_wrapper) NI_SYSCALL /* 314 sys_fallocate */ SYSCALL(sys_utimensat,sys_utimensat,compat_sys_utimensat_wrapper) /* 315 */ SYSCALL(sys_signalfd,sys_signalfd,compat_sys_signalfd_wrapper) diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index 790c1c5..1dede71 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h @@ -256,7 +256,8 @@ #define __NR_signalfd 316 #define __NR_timerfd 317 #define __NR_eventfd 318 -#define NR_syscalls 319 +#define __NR_fallocate 319 +#define NR_syscalls 320 /* * There are some system calls that are not present on 64 bit, some