aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/s390/lib/uaccess_pt.c59
1 files changed, 41 insertions, 18 deletions
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 5efdfe9f5e76..d66215b0fde9 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -302,6 +302,10 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
302 pte_t *pte_from, *pte_to; 302 pte_t *pte_from, *pte_to;
303 int write_user; 303 int write_user;
304 304
305 if (segment_eq(get_fs(), KERNEL_DS)) {
306 memcpy((void __force *) to, (void __force *) from, n);
307 return 0;
308 }
305 done = 0; 309 done = 0;
306retry: 310retry:
307 spin_lock(&mm->page_table_lock); 311 spin_lock(&mm->page_table_lock);
@@ -361,18 +365,10 @@ fault:
361 : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \ 365 : "0" (-EFAULT), "d" (oparg), "a" (uaddr), \
362 "m" (*uaddr) : "cc" ); 366 "m" (*uaddr) : "cc" );
363 367
364int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old) 368static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
365{ 369{
366 int oldval = 0, newval, ret; 370 int oldval = 0, newval, ret;
367 371
368 spin_lock(&current->mm->page_table_lock);
369 uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
370 if (!uaddr) {
371 spin_unlock(&current->mm->page_table_lock);
372 return -EFAULT;
373 }
374 get_page(virt_to_page(uaddr));
375 spin_unlock(&current->mm->page_table_lock);
376 switch (op) { 372 switch (op) {
377 case FUTEX_OP_SET: 373 case FUTEX_OP_SET:
378 __futex_atomic_op("lr %2,%5\n", 374 __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)
397 default: 393 default:
398 ret = -ENOSYS; 394 ret = -ENOSYS;
399 } 395 }
400 put_page(virt_to_page(uaddr)); 396 if (ret == 0)
401 *old = oldval; 397 *old = oldval;
402 return ret; 398 return ret;
403} 399}
404 400
405int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval) 401int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
406{ 402{
407 int ret; 403 int ret;
408 404
409 if (!current->mm) 405 if (segment_eq(get_fs(), KERNEL_DS))
410 return -EFAULT; 406 return __futex_atomic_op_pt(op, uaddr, oparg, old);
411 spin_lock(&current->mm->page_table_lock); 407 spin_lock(&current->mm->page_table_lock);
412 uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr); 408 uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
413 if (!uaddr) { 409 if (!uaddr) {
@@ -416,13 +412,40 @@ int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
416 } 412 }
417 get_page(virt_to_page(uaddr)); 413 get_page(virt_to_page(uaddr));
418 spin_unlock(&current->mm->page_table_lock); 414 spin_unlock(&current->mm->page_table_lock);
419 asm volatile(" cs %1,%4,0(%5)\n" 415 ret = __futex_atomic_op_pt(op, uaddr, oparg, old);
420 "0: lr %0,%1\n" 416 put_page(virt_to_page(uaddr));
421 "1:\n" 417 return ret;
422 EX_TABLE(0b,1b) 418}
419
420static int __futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
421{
422 int ret;
423
424 asm volatile("0: cs %1,%4,0(%5)\n"
425 "1: lr %0,%1\n"
426 "2:\n"
427 EX_TABLE(0b,2b) EX_TABLE(1b,2b)
423 : "=d" (ret), "+d" (oldval), "=m" (*uaddr) 428 : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
424 : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr) 429 : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
425 : "cc", "memory" ); 430 : "cc", "memory" );
431 return ret;
432}
433
434int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
435{
436 int ret;
437
438 if (segment_eq(get_fs(), KERNEL_DS))
439 return __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
440 spin_lock(&current->mm->page_table_lock);
441 uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
442 if (!uaddr) {
443 spin_unlock(&current->mm->page_table_lock);
444 return -EFAULT;
445 }
446 get_page(virt_to_page(uaddr));
447 spin_unlock(&current->mm->page_table_lock);
448 ret = __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
426 put_page(virt_to_page(uaddr)); 449 put_page(virt_to_page(uaddr));
427 return ret; 450 return ret;
428} 451}