|
@@ -302,6 +302,10 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
|
|
pte_t *pte_from, *pte_to;
|
|
pte_t *pte_from, *pte_to;
|
|
int write_user;
|
|
int write_user;
|
|
|
|
|
|
|
|
+ if (segment_eq(get_fs(), KERNEL_DS)) {
|
|
|
|
+ memcpy((void __force *) to, (void __force *) from, n);
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
done = 0;
|
|
done = 0;
|
|
retry:
|
|
retry:
|
|
spin_lock(&mm->page_table_lock);
|
|
spin_lock(&mm->page_table_lock);
|
|
@@ -361,18 +365,10 @@ fault:
|
|
: "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
|
|
: "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
|
|
"m" (*uaddr) : "cc" );
|
|
"m" (*uaddr) : "cc" );
|
|
|
|
|
|
-int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
|
|
|
|
|
|
+static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
|
|
{
|
|
{
|
|
int oldval = 0, newval, ret;
|
|
int oldval = 0, newval, ret;
|
|
|
|
|
|
- spin_lock(¤t->mm->page_table_lock);
|
|
|
|
- uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
|
|
|
|
- if (!uaddr) {
|
|
|
|
- spin_unlock(¤t->mm->page_table_lock);
|
|
|
|
- return -EFAULT;
|
|
|
|
- }
|
|
|
|
- get_page(virt_to_page(uaddr));
|
|
|
|
- spin_unlock(¤t->mm->page_table_lock);
|
|
|
|
switch (op) {
|
|
switch (op) {
|
|
case FUTEX_OP_SET:
|
|
case FUTEX_OP_SET:
|
|
__futex_atomic_op("lr %2,%5\n",
|
|
__futex_atomic_op("lr %2,%5\n",
|
|
@@ -397,17 +393,17 @@ int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
|
|
default:
|
|
default:
|
|
ret = -ENOSYS;
|
|
ret = -ENOSYS;
|
|
}
|
|
}
|
|
- put_page(virt_to_page(uaddr));
|
|
|
|
- *old = oldval;
|
|
|
|
|
|
+ if (ret == 0)
|
|
|
|
+ *old = oldval;
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
-int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
|
|
|
|
|
|
+int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
|
|
{
|
|
{
|
|
int ret;
|
|
int ret;
|
|
|
|
|
|
- if (!current->mm)
|
|
|
|
- return -EFAULT;
|
|
|
|
|
|
+ if (segment_eq(get_fs(), KERNEL_DS))
|
|
|
|
+ return __futex_atomic_op_pt(op, uaddr, oparg, old);
|
|
spin_lock(¤t->mm->page_table_lock);
|
|
spin_lock(¤t->mm->page_table_lock);
|
|
uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
|
|
uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
|
|
if (!uaddr) {
|
|
if (!uaddr) {
|
|
@@ -416,13 +412,40 @@ int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
|
|
}
|
|
}
|
|
get_page(virt_to_page(uaddr));
|
|
get_page(virt_to_page(uaddr));
|
|
spin_unlock(¤t->mm->page_table_lock);
|
|
spin_unlock(¤t->mm->page_table_lock);
|
|
- asm volatile(" cs %1,%4,0(%5)\n"
|
|
|
|
- "0: lr %0,%1\n"
|
|
|
|
- "1:\n"
|
|
|
|
- EX_TABLE(0b,1b)
|
|
|
|
|
|
+ ret = __futex_atomic_op_pt(op, uaddr, oparg, old);
|
|
|
|
+ put_page(virt_to_page(uaddr));
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int __futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ asm volatile("0: cs %1,%4,0(%5)\n"
|
|
|
|
+ "1: lr %0,%1\n"
|
|
|
|
+ "2:\n"
|
|
|
|
+ EX_TABLE(0b,2b) EX_TABLE(1b,2b)
|
|
: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
|
|
: "=d" (ret), "+d" (oldval), "=m" (*uaddr)
|
|
: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
|
|
: "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
|
|
: "cc", "memory" );
|
|
: "cc", "memory" );
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+
|
|
|
|
+ if (segment_eq(get_fs(), KERNEL_DS))
|
|
|
|
+ return __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
|
|
|
|
+ spin_lock(¤t->mm->page_table_lock);
|
|
|
|
+ uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
|
|
|
|
+ if (!uaddr) {
|
|
|
|
+ spin_unlock(¤t->mm->page_table_lock);
|
|
|
|
+ return -EFAULT;
|
|
|
|
+ }
|
|
|
|
+ get_page(virt_to_page(uaddr));
|
|
|
|
+ spin_unlock(¤t->mm->page_table_lock);
|
|
|
|
+ ret = __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
|
|
put_page(virt_to_page(uaddr));
|
|
put_page(virt_to_page(uaddr));
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|