diff mbox

[v2,4/4] ARM: cacheflush: don't bother rounding to nearest vma

Message ID 1369395087-30972-5-git-send-email-will.deacon@arm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Will Deacon May 24, 2013, 11:31 a.m. UTC
do_cache_op finds the lowest VMA contained in the specified address
range and rounds the range to cover only the mapped addresses.

Since commit 4542b6a0fa6b ("ARM: 7365/1: drop unused parameter from
flush_cache_user_range") the VMA is not used for anything else in this
code and seeing as the low-level cache flushing routines return -EFAULT
if the address is not valid, there is no need for this range truncation.

This patch removes the VMA handling code from the cacheflushing syscall.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 arch/arm/kernel/traps.c | 17 ++---------------
 1 file changed, 2 insertions(+), 15 deletions(-)

Comments

Russell King - ARM Linux May 24, 2013, 11:59 a.m. UTC | #1
On Fri, May 24, 2013 at 12:31:27PM +0100, Will Deacon wrote:
> do_cache_op finds the lowest VMA contained in the specified address
> range and rounds the range to cover only the mapped addresses.
> 
> Since commit 4542b6a0fa6b ("ARM: 7365/1: drop unused parameter from
> flush_cache_user_range") the VMA is not used for anything else in this
> code and seeing as the low-level cache flushing routines return -EFAULT
> if the address is not valid, there is no need for this range truncation.
> 
> This patch removes the VMA handling code from the cacheflushing syscall.

The only thing which access_ok() tells you is that the addresses are
_potentially_ valid user addresses.  That's not what the VMA check is
there for.

That check is there to make sure userspace doesn't do something idiotic,
and to keep the use of this API limited to specific actions such as self
modifying code, and not a general purpose cache flushing API covering
multiple VMAs.
Will Deacon May 24, 2013, 12:56 p.m. UTC | #2
On Fri, May 24, 2013 at 12:59:17PM +0100, Russell King - ARM Linux wrote:
> On Fri, May 24, 2013 at 12:31:27PM +0100, Will Deacon wrote:
> > do_cache_op finds the lowest VMA contained in the specified address
> > range and rounds the range to cover only the mapped addresses.
> > 
> > Since commit 4542b6a0fa6b ("ARM: 7365/1: drop unused parameter from
> > flush_cache_user_range") the VMA is not used for anything else in this
> > code and seeing as the low-level cache flushing routines return -EFAULT
> > if the address is not valid, there is no need for this range truncation.
> > 
> > This patch removes the VMA handling code from the cacheflushing syscall.
> 
> The only thing which access_ok() tells you is that the addresses are
> _potentially_ valid user addresses.  That's not what the VMA check is
> there for.

Agreed, but it becomes necessary if we remove the vma check, since then
kernel addresses could be passed in unnoticed. The moment we get a fault,
we'll stop and return -EFAULT.

> That check is there to make sure userspace doesn't do something idiotic,
> and to keep the use of this API limited to specific actions such as self
> modifying code, and not a general purpose cache flushing API covering
> multiple VMAs.

Why make the distinction? You can already create single VMAs up to around
2GB and use the syscall in mainline today to flush that area by line. With
these patches we avoid touching mmap_sem, simplify the semantics of the
call, remove the possibility of DoS with non-preemptible kernels (which also
exists in mainline today) and measurably improve performance (~2%
improvement on a browser benchmark test).

If userspace does something idiotic, that should be fine as long as the
idiocy is confined to the task issuing the system call.

Will
diff mbox

Patch

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 47092f2..9af88fd 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -548,24 +548,11 @@  static long do_cache_op_restart(struct restart_block *unused)
 static inline int
 do_cache_op(unsigned long start, unsigned long end, int flags)
 {
-	struct mm_struct *mm = current->active_mm;
-	struct vm_area_struct *vma;
-
 	if (end < start || flags)
 		return -EINVAL;
 
-	down_read(&mm->mmap_sem);
-	vma = find_vma(mm, start);
-	if (!vma || vma->vm_start >= end) {
-		up_read(&mm->mmap_sem);
-		return -EINVAL;
-	}
-
-	if (start < vma->vm_start)
-		start = vma->vm_start;
-	if (end > vma->vm_end)
-		end = vma->vm_end;
-	up_read(&mm->mmap_sem);
+	if (!access_ok(VERIFY_READ, start, end - start))
+		return -EFAULT;
 
 	return __do_cache_op(start, end);
 }