diff options
Diffstat (limited to 'arch/arm/kernel/traps.c')
-rw-r--r-- | arch/arm/kernel/traps.c | 66 |
1 files changed, 51 insertions, 15 deletions
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index ab517fcce21b..8fcda140358d 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -497,28 +497,64 @@ static int bad_syscall(int n, struct pt_regs *regs) | |||
497 | return regs->ARM_r0; | 497 | return regs->ARM_r0; |
498 | } | 498 | } |
499 | 499 | ||
500 | static long do_cache_op_restart(struct restart_block *); | ||
501 | |||
500 | static inline int | 502 | static inline int |
501 | do_cache_op(unsigned long start, unsigned long end, int flags) | 503 | __do_cache_op(unsigned long start, unsigned long end) |
502 | { | 504 | { |
503 | struct mm_struct *mm = current->active_mm; | 505 | int ret; |
504 | struct vm_area_struct *vma; | 506 | unsigned long chunk = PAGE_SIZE; |
507 | |||
508 | do { | ||
509 | if (signal_pending(current)) { | ||
510 | struct thread_info *ti = current_thread_info(); | ||
511 | |||
512 | ti->restart_block = (struct restart_block) { | ||
513 | .fn = do_cache_op_restart, | ||
514 | }; | ||
515 | |||
516 | ti->arm_restart_block = (struct arm_restart_block) { | ||
517 | { | ||
518 | .cache = { | ||
519 | .start = start, | ||
520 | .end = end, | ||
521 | }, | ||
522 | }, | ||
523 | }; | ||
524 | |||
525 | return -ERESTART_RESTARTBLOCK; | ||
526 | } | ||
527 | |||
528 | ret = flush_cache_user_range(start, start + chunk); | ||
529 | if (ret) | ||
530 | return ret; | ||
505 | 531 | ||
532 | cond_resched(); | ||
533 | start += chunk; | ||
534 | } while (start < end); | ||
535 | |||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | static long do_cache_op_restart(struct restart_block *unused) | ||
540 | { | ||
541 | struct arm_restart_block *restart_block; | ||
542 | |||
543 | restart_block = ¤t_thread_info()->arm_restart_block; | ||
544 | return __do_cache_op(restart_block->cache.start, | ||
545 | restart_block->cache.end); | ||
546 | } | ||
547 | |||
548 | static inline int | ||
549 | do_cache_op(unsigned long start, unsigned long end, int flags) | ||
550 | { | ||
506 | if (end < start || flags) | 551 | if (end < start || flags) |
507 | return -EINVAL; | 552 | return -EINVAL; |
508 | 553 | ||
509 | down_read(&mm->mmap_sem); | 554 | if (!access_ok(VERIFY_READ, start, end - start)) |
510 | vma = find_vma(mm, start); | 555 | return -EFAULT; |
511 | if (vma && vma->vm_start < end) { | ||
512 | if (start < vma->vm_start) | ||
513 | start = vma->vm_start; | ||
514 | if (end > vma->vm_end) | ||
515 | end = vma->vm_end; | ||
516 | 556 | ||
517 | up_read(&mm->mmap_sem); | 557 | return __do_cache_op(start, end); |
518 | return flush_cache_user_range(start, end); | ||
519 | } | ||
520 | up_read(&mm->mmap_sem); | ||
521 | return -EINVAL; | ||
522 | } | 558 | } |
523 | 559 | ||
524 | /* | 560 | /* |