diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 05f6e5caffc9d3c31aac2433671f4d082611e7aa..ea603c4820dad555c86bbd588dc10d82cdaae2a4 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -373,12 +373,45 @@ struct shmid64_ds32 { unsigned int __unused5; }; - -/* - * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation.. - * - * This is really horribly ugly. - */ +extern int sem_ctls[]; +#define sc_semopm (sem_ctls[2]) +#define SEMOPM_FAST 64 /* ~ 372 bytes on stack */ + +static long +do_sys32_semtimedop (int semid, struct sembuf *tsops, int nsops, + struct compat_timespec *timeout32) +{ + struct sembuf *sops, fast_sops[SEMOPM_FAST]; + struct timespec t; + mm_segment_t oldfs; + long ret; + + /* parameter checking precedence should mirror sys_semtimedop() */ + if (nsops < 1 || semid < 0) + return -EINVAL; + if (nsops > sc_semopm) + return -E2BIG; + if (nsops <= SEMOPM_FAST) + sops = fast_sops; + else { + sops = kmalloc(nsops * sizeof(*sops), GFP_KERNEL); + if (sops == NULL) + return -ENOMEM; + } + if (copy_from_user(sops, tsops, nsops * sizeof(*tsops)) || + get_compat_timespec(&t, timeout32)) + ret = -EFAULT; + else { + oldfs = get_fs(); + set_fs(KERNEL_DS); + ret = sys_semtimedop(semid, sops, nsops, &t); + set_fs(oldfs); + } + if (sops != fast_sops) + kfree(sops); + return ret; +} + #define IPCOP_MASK(__x) (1UL << (__x)) static int do_sys32_semctl(int first, int second, int third, void *uptr) { @@ -763,7 +796,12 @@ static int do_sys32_shmctl (int first, int second, void *uptr) return err; } -asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth) +/* + * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation. + * + * This is really horribly ugly. + */ +asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr) { int version, err; @@ -773,11 +811,22 @@ asmlinkage int sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u if(version) return -EINVAL; - if (call <= SEMCTL) + if (call <= SEMTIMEDOP) switch (call) { + case SEMTIMEDOP: + if (third) { + err = do_sys32_semtimedop(first, + (struct sembuf *)AA(ptr), + second, + (struct compat_timespec *) + AA((u32)third)); + goto out; + } + /* else fall through for normal semop() */ case SEMOP: /* struct sembuf is the same on 32 and 64bit :)) */ - err = sys_semop (first, (struct sembuf *)AA(ptr), second); + err = sys_semtimedop (first, (struct sembuf *)AA(ptr), + second, NULL); goto out; case SEMGET: err = sys_semget (first, second, third); diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c index b41f095c1a030d1bb16cfb96cc97c6a10d42715b..51038c69733f6d82cc47a29189ccbadf8737071b 100644 --- a/arch/s390/kernel/sys_s390.c +++ b/arch/s390/kernel/sys_s390.c @@ -184,8 +184,7 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr, * This is really horribly ugly. */ asmlinkage __SYS_RETTYPE sys_ipc (uint call, int first, int second, - unsigned long third, void *ptr, - unsigned long fifth) + unsigned long third, void *ptr) { struct ipc_kludge tmp; int ret; @@ -195,8 +194,8 @@ asmlinkage __SYS_RETTYPE sys_ipc (uint call, int first, int second, return sys_semtimedop (first, (struct sembuf *) ptr, second, NULL); case SEMTIMEDOP: - return sys_semtimedop(first, (struct sembuf *) ptr, second, - (const struct timespec *) fifth); + return sys_semtimedop (first, (struct sembuf *) ptr, second, + (const struct timespec *) third); case SEMGET: return sys_semget (first, second, third); case SEMCTL: {