|
@@ -28,29 +28,39 @@
|
|
|
#include <asm/cacheflush.h>
|
|
|
#include <asm/unistd.h>
|
|
|
|
|
|
-static inline void
|
|
|
-do_compat_cache_op(unsigned long start, unsigned long end, int flags)
|
|
|
+static long
|
|
|
+__do_compat_cache_op(unsigned long start, unsigned long end)
|
|
|
{
|
|
|
- struct mm_struct *mm = current->active_mm;
|
|
|
- struct vm_area_struct *vma;
|
|
|
+ long ret;
|
|
|
|
|
|
- if (end < start || flags)
|
|
|
- return;
|
|
|
+ do {
|
|
|
+ unsigned long chunk = min(PAGE_SIZE, end - start);
|
|
|
|
|
|
- down_read(&mm->mmap_sem);
|
|
|
- vma = find_vma(mm, start);
|
|
|
- if (vma && vma->vm_start < end) {
|
|
|
- if (start < vma->vm_start)
|
|
|
- start = vma->vm_start;
|
|
|
- if (end > vma->vm_end)
|
|
|
- end = vma->vm_end;
|
|
|
- up_read(&mm->mmap_sem);
|
|
|
- __flush_cache_user_range(start & PAGE_MASK, PAGE_ALIGN(end));
|
|
|
- return;
|
|
|
- }
|
|
|
- up_read(&mm->mmap_sem);
|
|
|
+ if (fatal_signal_pending(current))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ ret = __flush_cache_user_range(start, start + chunk);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ cond_resched();
|
|
|
+ start += chunk;
|
|
|
+ } while (start < end);
|
|
|
+
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
+static inline long
|
|
|
+do_compat_cache_op(unsigned long start, unsigned long end, int flags)
|
|
|
+{
|
|
|
+ if (end < start || flags)
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+ if (!access_ok(VERIFY_READ, start, end - start))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ return __do_compat_cache_op(start, end);
|
|
|
+}
|
|
|
/*
|
|
|
* Handle all unrecognised system calls.
|
|
|
*/
|
|
@@ -74,8 +84,7 @@ long compat_arm_syscall(struct pt_regs *regs)
|
|
|
* the specified region).
|
|
|
*/
|
|
|
case __ARM_NR_compat_cacheflush:
|
|
|
- do_compat_cache_op(regs->regs[0], regs->regs[1], regs->regs[2]);
|
|
|
- return 0;
|
|
|
+ return do_compat_cache_op(regs->regs[0], regs->regs[1], regs->regs[2]);
|
|
|
|
|
|
case __ARM_NR_compat_set_tls:
|
|
|
current->thread.tp_value = regs->regs[0];
|