Files
android_kernel_xiaomi_sm8450/arch/parisc/include/asm/futex.h
John David Anglin 0ffb9f83e4 parisc: Fix mask used to select futex spinlock
commit d3a5a68cff47f6eead84504c3c28376b85053242 upstream.

The address bits used to select the futex spinlock need to match those used in
the LWS code in syscall.S. The mask 0x3f8 only selects 7 bits.  It should
select 8 bits.

This change fixes the glibc nptl/tst-cond24 and nptl/tst-cond25 tests.

Signed-off-by: John David Anglin <dave.anglin@bell.net>
Fixes: 53a42b6324 ("parisc: Switch to more fine grained lws locks")
Cc: stable@vger.kernel.org # 5.10+
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-12-29 12:26:02 +01:00

124 lines
2.6 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _ASM_PARISC_FUTEX_H
#define _ASM_PARISC_FUTEX_H
#ifdef __KERNEL__
#include <linux/futex.h>
#include <linux/uaccess.h>
#include <asm/atomic.h>
#include <asm/errno.h>
/* The following has to match the LWS code in syscall.S. We have
sixteen four-word locks. */
static inline void
_futex_spin_lock_irqsave(u32 __user *uaddr, unsigned long int *flags)
{
extern u32 lws_lock_start[];
long index = ((long)uaddr & 0x7f8) >> 1;
arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
local_irq_save(*flags);
arch_spin_lock(s);
}
static inline void
_futex_spin_unlock_irqrestore(u32 __user *uaddr, unsigned long int *flags)
{
extern u32 lws_lock_start[];
long index = ((long)uaddr & 0x7f8) >> 1;
arch_spinlock_t *s = (arch_spinlock_t *)&lws_lock_start[index];
arch_spin_unlock(s);
local_irq_restore(*flags);
}
static inline int
arch_futex_atomic_op_inuser(int op, int oparg, int *oval, u32 __user *uaddr)
{
unsigned long int flags;
int oldval, ret;
u32 tmp;
_futex_spin_lock_irqsave(uaddr, &flags);
ret = -EFAULT;
if (unlikely(get_user(oldval, uaddr) != 0))
goto out_pagefault_enable;
ret = 0;
tmp = oldval;
switch (op) {
case FUTEX_OP_SET:
tmp = oparg;
break;
case FUTEX_OP_ADD:
tmp += oparg;
break;
case FUTEX_OP_OR:
tmp |= oparg;
break;
case FUTEX_OP_ANDN:
tmp &= ~oparg;
break;
case FUTEX_OP_XOR:
tmp ^= oparg;
break;
default:
ret = -ENOSYS;
}
if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
ret = -EFAULT;
out_pagefault_enable:
_futex_spin_unlock_irqrestore(uaddr, &flags);
if (!ret)
*oval = oldval;
return ret;
}
static inline int
futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
u32 oldval, u32 newval)
{
u32 val;
unsigned long flags;
/* futex.c wants to do a cmpxchg_inatomic on kernel NULL, which is
* our gateway page, and causes no end of trouble...
*/
if (uaccess_kernel() && !uaddr)
return -EFAULT;
if (!access_ok(uaddr, sizeof(u32)))
return -EFAULT;
/* HPPA has no cmpxchg in hardware and therefore the
* best we can do here is use an array of locks. The
* lock selected is based on a hash of the userspace
* address. This should scale to a couple of CPUs.
*/
_futex_spin_lock_irqsave(uaddr, &flags);
if (unlikely(get_user(val, uaddr) != 0)) {
_futex_spin_unlock_irqrestore(uaddr, &flags);
return -EFAULT;
}
if (val == oldval && unlikely(put_user(newval, uaddr) != 0)) {
_futex_spin_unlock_irqrestore(uaddr, &flags);
return -EFAULT;
}
*uval = val;
_futex_spin_unlock_irqrestore(uaddr, &flags);
return 0;
}
#endif /*__KERNEL__*/
#endif /*_ASM_PARISC_FUTEX_H*/