diff options
Diffstat (limited to 'arch/s390/lib/uaccess_pt.c')
-rw-r--r-- | arch/s390/lib/uaccess_pt.c | 59 |
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; |
306 | retry: | 310 | retry: |
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 | ||
364 | int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old) | 368 | static 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(¤t->mm->page_table_lock); | ||
369 | uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr); | ||
370 | if (!uaddr) { | ||
371 | spin_unlock(¤t->mm->page_table_lock); | ||
372 | return -EFAULT; | ||
373 | } | ||
374 | get_page(virt_to_page(uaddr)); | ||
375 | spin_unlock(¤t->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 | ||
405 | int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval) | 401 | int 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(¤t->mm->page_table_lock); | 407 | spin_lock(¤t->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(¤t->mm->page_table_lock); | 414 | spin_unlock(¤t->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 | |||
420 | static 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 | |||
434 | int 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(¤t->mm->page_table_lock); | ||
441 | uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr); | ||
442 | if (!uaddr) { | ||
443 | spin_unlock(¤t->mm->page_table_lock); | ||
444 | return -EFAULT; | ||
445 | } | ||
446 | get_page(virt_to_page(uaddr)); | ||
447 | spin_unlock(¤t->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 | } |