in kernel/skas/uaccess.c [249:310]
int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, u32 __user *uaddr)
{
int oldval, ret;
struct page *page;
unsigned long addr = (unsigned long) uaddr;
pte_t *pte;
ret = -EFAULT;
if (!access_ok(uaddr, sizeof(*uaddr)))
return -EFAULT;
preempt_disable();
pte = maybe_map(addr, 1);
if (pte == NULL)
goto out_inuser;
page = pte_page(*pte);
#ifdef CONFIG_64BIT
pagefault_disable();
addr = (unsigned long) page_address(page) +
(((unsigned long) addr) & ~PAGE_MASK);
#else
addr = (unsigned long) kmap_atomic(page) +
((unsigned long) addr & ~PAGE_MASK);
#endif
uaddr = (u32 *) addr;
oldval = *uaddr;
ret = 0;
switch (op) {
case FUTEX_OP_SET:
*uaddr = oparg;
break;
case FUTEX_OP_ADD:
*uaddr += oparg;
break;
case FUTEX_OP_OR:
*uaddr |= oparg;
break;
case FUTEX_OP_ANDN:
*uaddr &= ~oparg;
break;
case FUTEX_OP_XOR:
*uaddr ^= oparg;
break;
default:
ret = -ENOSYS;
}
#ifdef CONFIG_64BIT
pagefault_enable();
#else
kunmap_atomic((void *)addr);
#endif
out_inuser:
preempt_enable();
if (ret == 0)
*oval = oldval;
return ret;
}