2009-11-28 15:40:46

by Mike Frysinger

[permalink] [raw]
Subject: avoiding duplicate icache flushing of shared maps on nommu

when working with FDPIC, there are many shared maps of read only text
regions (the C library, applet packages like busybox, ...) between
applications. but the current mm/nommu.c:do_mmap_pgoff() function
will issue an icache flush whenever a vma is added to a mm instead of
only doing it when the map is initially created. am i missing
something obvious here, or would a change like below be OK ? this
easily cuts the number of icache flushes during boot by 50% if not
more.

(yes, this now does the icache flush while holding the
nommu_region_sem, but i'm interested if the _idea_ is OK)

--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1409,14 +1409,14 @@ unsigned long do_mmap_pgoff(struct file *file,

current->mm->total_vm += len >> PAGE_SHIFT;

+ if (prot & PROT_EXEC)
+ flush_icache_range(result, result + len);
+
share:
add_vma_to_mm(current->mm, vma);

up_write(&nommu_region_sem);

- if (prot & PROT_EXEC)
- flush_icache_range(result, result + len);
-
kleave(" = %lx", result);
return result;

-mike


2009-11-28 18:53:49

by Mike Frysinger

[permalink] [raw]
Subject: Re: avoiding duplicate icache flushing of shared maps on nommu

On Sat, Nov 28, 2009 at 10:40, Mike Frysinger wrote:
> when working with FDPIC, there are many shared maps of read only text
> regions (the C library, applet packages like busybox, ...) between
> applications.  but the current mm/nommu.c:do_mmap_pgoff() function
> will issue an icache flush whenever a vma is added to a mm instead of
> only doing it when the map is initially created.  am i missing
> something obvious here, or would a change like below be OK ?  this
> easily cuts the number of icache flushes during boot by 50% if not
> more.

for some actual numbers, my default boot iflushes 18,562,124 bytes.
with this fix, it's down to 4,528,580 bytes (a 75% shrink). with the
stack fix, it's down to 989,636 bytes (a 95% shrink).
-mike

2009-11-30 03:18:09

by Jie Zhang

[permalink] [raw]
Subject: Re: avoiding duplicate icache flushing of shared maps on nommu

On 11/28/2009 11:40 PM, Mike Frysinger wrote:
> when working with FDPIC, there are many shared maps of read only text
> regions (the C library, applet packages like busybox, ...) between
> applications. but the current mm/nommu.c:do_mmap_pgoff() function
> will issue an icache flush whenever a vma is added to a mm instead of
> only doing it when the map is initially created. am i missing
> something obvious here, or would a change like below be OK ? this
> easily cuts the number of icache flushes during boot by 50% if not
> more.
>
> (yes, this now does the icache flush while holding the
> nommu_region_sem, but i'm interested if the _idea_ is OK)
>
I don't see any problem. But I'm not a kernel expert. I tried to take a
look at the source code history. But I cannot find code older than
2.6.12. In the CVS repository of uClinux, there is no similar code in
kernel sub-directory. :-(


Jie


> --- a/mm/nommu.c
> +++ b/mm/nommu.c
> @@ -1409,14 +1409,14 @@ unsigned long do_mmap_pgoff(struct file *file,
>
> current->mm->total_vm += len>> PAGE_SHIFT;
>
> + if (prot& PROT_EXEC)
> + flush_icache_range(result, result + len);
> +
> share:
> add_vma_to_mm(current->mm, vma);
>
> up_write(&nommu_region_sem);
>
> - if (prot& PROT_EXEC)
> - flush_icache_range(result, result + len);
> -
> kleave(" = %lx", result);
> return result;
>
> -mike

2009-12-02 14:16:26

by David Howells

[permalink] [raw]
Subject: Re: avoiding duplicate icache flushing of shared maps on nommu

Mike Frysinger <[email protected]> wrote:

> (yes, this now does the icache flush while holding the
> nommu_region_sem, but i'm interested if the _idea_ is OK)

Yes... But it's not quite as simple as you think. The first mapping made of
a file could be PROT_READ only, in which case a second, executable mapping
made that shares it would not get flushed from the icache.

How about the attached patch?

David
---
From: Mike Frysinger <[email protected]>
Subject: [PATCH] NOMMU: Avoiding duplicate icache flushes of shared maps

When working with FDPIC, there are many shared mappings of read-only code
regions between applications (the C library, applet packages like busybox,
etc.), but the current do_mmap_pgoff() function will issue an icache flush
whenever a VMA is added to an MM instead of only doing it when the map is
initially created.

The flush can instead be done when a region is first mmapped PROT_EXEC. Note
that we may not rely on the first mapping of a region being executable - it's
possible for it to be PROT_READ only, so we have to remember whether we've
flushed the region or not, and then flush the entire region when a bit of it is
made executable.

Signed-off-by: David Howells <[email protected]>
---

include/linux/mm_types.h | 2 ++
mm/nommu.c | 11 ++++++++---
2 files changed, 10 insertions(+), 3 deletions(-)


diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 84a524a..84d020b 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -123,6 +123,8 @@ struct vm_region {
struct file *vm_file; /* the backing file or NULL */

atomic_t vm_usage; /* region usage count */
+ bool vm_icache_flushed : 1; /* true if the icache has been flushed for
+ * this region */
};

/*
diff --git a/mm/nommu.c b/mm/nommu.c
index 969392c..95159a1 100644
--- a/mm/nommu.c
+++ b/mm/nommu.c
@@ -1353,10 +1353,15 @@ unsigned long do_mmap_pgoff(struct file *file,
share:
add_vma_to_mm(current->mm, vma);

- up_write(&nommu_region_sem);
+ /* we flush the region from the icache only when the first executable
+ * mapping of it is made */
+ if (vma->vm_flags & VM_EXEC && !region->vm_icache_flushed) {
+ flush_icache_range(region->vm_start,
+ region->vm_end - region->vm_start);
+ region->vm_icache_flushed = true;
+ }

- if (prot & PROT_EXEC)
- flush_icache_range(result, result + len);
+ up_write(&nommu_region_sem);

kleave(" = %lx", result);
return result;

2009-12-02 21:40:29

by Mike Frysinger

[permalink] [raw]
Subject: Re: avoiding duplicate icache flushing of shared maps on nommu

On Wed, Dec 2, 2009 at 09:15, David Howells wrote:
> Mike Frysinger wrote:
>> (yes, this now does the icache flush while holding the
>> nommu_region_sem, but i'm interested if the _idea_ is OK)
>
> Yes...  But it's not quite as simple as you think.  The first mapping made of
> a file could be PROT_READ only, in which case a second, executable mapping
> made that shares it would not get flushed from the icache.

that is a tricky edge case ;)

> How about the attached patch?

it works, but i think we want to put the vm_icache_flushed in
linux/mm_types.h behind NOMMU so we dont bloat the MMU guys ?
-mike

2009-12-02 22:41:46

by Mike Frysinger

[permalink] [raw]
Subject: Re: avoiding duplicate icache flushing of shared maps on nommu

On Wed, Dec 2, 2009 at 09:15, David Howells wrote:
> Mike Frysinger wrote:
> +               flush_icache_range(region->vm_start,
> +                                  region->vm_end - region->vm_start);
> -               flush_icache_range(result, result + len);

actually, there's one typo here. you want:
flush_icache_range(region->vm_start, region->vm_end);

it doesnt crash on blackfin systems as addresses not in icache get
nopped, but it was causing large delays on exec mappings. i thought
this was due to the nic on the board i was using as it's hitting some
weird pauses by itself.
-mike

2009-12-02 23:52:41

by David Howells

[permalink] [raw]
Subject: Re: avoiding duplicate icache flushing of shared maps on nommu

Mike Frysinger <[email protected]> wrote:

> it works, but i think we want to put the vm_icache_flushed in
> linux/mm_types.h behind NOMMU so we dont bloat the MMU guys ?

No. The vm_region struct just isn't used in MMU-mode.

David

2009-12-03 16:15:49

by David Howells

[permalink] [raw]
Subject: Re: avoiding duplicate icache flushing of shared maps on nommu

Mike Frysinger <[email protected]> wrote:

> actually, there's one typo here. you want:
> flush_icache_range(region->vm_start, region->vm_end);

Good catch, thanks.

David