[PATCH 2/2] topdown mmap support

Stefan Bader stefan.bader at canonical.com
Fri Jan 13 09:38:11 UTC 2012


On 13.01.2012 10:24, Paolo Pisati wrote:
> From: Rob Herring <rob.herring at calxeda.com>
> 
> Similar to other architectures, this adds topdown mmap support in user
> process address space allocation policy. This allows mmap sizes greater
> than 2GB. This support is largely copied from MIPS and the generic
> implementations.
> 
> The address space randomization is moved into arch_pick_mmap_layout.
> 
> Tested on V-Express with ubuntu and a mmap test from here:
> https://bugs.launchpad.net/bugs/861296
> 
> BugLink: http://bugs.launchpad.net/bugs/861296
> 
> Signed-off-by: Rob Herring <rob.herring at calxeda.com>
> Acked-by: Nicolas Pitre <nico at linaro.org>
> Signed-off-by: Paolo Pisati <paolo.pisati at canonical.com>
> Acked-by: Seth Forshee <seth.forshee at canonical.com>
> Signed-off-by: Tim Gardner <tim.gardner at canonical.com>
> ---
>  arch/arm/include/asm/pgtable.h   |    1 +
>  arch/arm/include/asm/processor.h |    2 +
>  arch/arm/mm/mmap.c               |  173 +++++++++++++++++++++++++++++++++++++-
>  3 files changed, 172 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
> index ea19775..4e85b3e 100644
> --- a/arch/arm/include/asm/pgtable.h
> +++ b/arch/arm/include/asm/pgtable.h
> @@ -469,6 +469,7 @@ extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
>   * We provide our own arch_get_unmapped_area to cope with VIPT caches.
>   */
>  #define HAVE_ARCH_UNMAPPED_AREA
> +#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN
>  
>  /*
>   * remap a physical page `pfn' of size `size' with page protection `prot'
> diff --git a/arch/arm/include/asm/processor.h b/arch/arm/include/asm/processor.h
> index 7bed3da..68fdb7f 100644
> --- a/arch/arm/include/asm/processor.h
> +++ b/arch/arm/include/asm/processor.h
> @@ -131,6 +131,8 @@ static inline void prefetch(const void *ptr)
>  
>  #endif
>  
> +#define HAVE_ARCH_PICK_MMAP_LAYOUT
> +
>  #endif
>  
>  #endif /* __ASM_ARM_PROCESSOR_H */
> diff --git a/arch/arm/mm/mmap.c b/arch/arm/mm/mmap.c
> index 0cbf50b..ce3038b 100644
> --- a/arch/arm/mm/mmap.c
> +++ b/arch/arm/mm/mmap.c
> @@ -7,13 +7,53 @@
>  #include <linux/shm.h>
>  #include <linux/sched.h>
>  #include <linux/io.h>
> +#include <linux/personality.h>
>  #include <linux/random.h>
>  #include <asm/cachetype.h>
>  
> +static inline unsigned long COLOUR_ALIGN_DOWN(unsigned long addr,
> +					      unsigned long pgoff)
> +{
> +	unsigned long base = addr & ~(SHMLBA-1);
> +	unsigned long off = (pgoff << PAGE_SHIFT) & (SHMLBA-1);
> +
> +	if (base + off <= addr)
> +		return base + off;
> +
> +	return base - off;
> +}
> +
>  #define COLOUR_ALIGN(addr,pgoff)		\
>  	((((addr)+SHMLBA-1)&~(SHMLBA-1)) +	\
>  	 (((pgoff)<<PAGE_SHIFT) & (SHMLBA-1)))
>  
> +/* gap between mmap and stack */
> +#define MIN_GAP (128*1024*1024UL)
> +#define MAX_GAP ((TASK_SIZE)/6*5)
> +
> +static int mmap_is_legacy(void)
> +{
> +	if (current->personality & ADDR_COMPAT_LAYOUT)
> +		return 1;
> +
> +	if (rlimit(RLIMIT_STACK) == RLIM_INFINITY)
> +		return 1;
> +
> +	return sysctl_legacy_va_layout;
> +}
> +
> +static unsigned long mmap_base(unsigned long rnd)
> +{
> +	unsigned long gap = rlimit(RLIMIT_STACK);
> +
> +	if (gap < MIN_GAP)
> +		gap = MIN_GAP;
> +	else if (gap > MAX_GAP)
> +		gap = MAX_GAP;
> +
> +	return PAGE_ALIGN(TASK_SIZE - gap - rnd);
> +}
> +
>  /*
>   * We need to ensure that shared mappings are correctly aligned to
>   * avoid aliasing issues with VIPT caches.  We need to ensure that
> @@ -67,12 +107,9 @@ arch_get_unmapped_area(struct file *filp, unsigned long addr,
>  	if (len > mm->cached_hole_size) {
>  	        start_addr = addr = mm->free_area_cache;
>  	} else {
> -	        start_addr = addr = TASK_UNMAPPED_BASE;
> +	        start_addr = addr = mm->mmap_base;
>  	        mm->cached_hole_size = 0;
>  	}
> -	/* 8 bits of randomness in 20 address space bits */
> -	if (current->flags & PF_RANDOMIZE)
> -		addr += (get_random_int() % (1 << 8)) << PAGE_SHIFT;
>  
>  full_search:
>  	if (do_align)
> @@ -109,6 +146,134 @@ full_search:
>  	}
>  }
>  
> +unsigned long
> +arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
> +			const unsigned long len, const unsigned long pgoff,
> +			const unsigned long flags)
> +{
> +	struct vm_area_struct *vma;
> +	struct mm_struct *mm = current->mm;
> +	unsigned long addr = addr0;
> +	int do_align = 0;
> +	int aliasing = cache_is_vipt_aliasing();
> +
> +	/*
> +	 * We only need to do colour alignment if either the I or D
> +	 * caches alias.
> +	 */
> +	if (aliasing)
> +		do_align = filp || (flags & MAP_SHARED);
> +
> +	/* requested length too big for entire address space */
> +	if (len > TASK_SIZE)
> +		return -ENOMEM;
> +
> +	if (flags & MAP_FIXED) {
> +		if (aliasing && flags & MAP_SHARED &&
> +		    (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))
> +			return -EINVAL;
> +		return addr;
> +	}
> +
> +	/* requesting a specific address */
> +	if (addr) {
> +		if (do_align)
> +			addr = COLOUR_ALIGN(addr, pgoff);
> +		else
> +			addr = PAGE_ALIGN(addr);
> +		vma = find_vma(mm, addr);
> +		if (TASK_SIZE - len >= addr &&
> +				(!vma || addr + len <= vma->vm_start))
> +			return addr;
> +	}
> +
> +	/* check if free_area_cache is useful for us */
> +	if (len <= mm->cached_hole_size) {
> +		mm->cached_hole_size = 0;
> +		mm->free_area_cache = mm->mmap_base;
> +	}
> +
> +	/* either no address requested or can't fit in requested address hole */
> +	addr = mm->free_area_cache;
> +	if (do_align) {
> +		unsigned long base = COLOUR_ALIGN_DOWN(addr - len, pgoff);
> +		addr = base + len;
> +	}
> +
> +	/* make sure it can fit in the remaining address space */
> +	if (addr > len) {
> +		vma = find_vma(mm, addr-len);
> +		if (!vma || addr <= vma->vm_start)
> +			/* remember the address as a hint for next time */
> +			return (mm->free_area_cache = addr-len);
> +	}
> +
> +	if (mm->mmap_base < len)
> +		goto bottomup;
> +
> +	addr = mm->mmap_base - len;
> +	if (do_align)
> +		addr = COLOUR_ALIGN_DOWN(addr, pgoff);
> +
> +	do {
> +		/*
> +		 * Lookup failure means no vma is above this address,
> +		 * else if new region fits below vma->vm_start,
> +		 * return with success:
> +		 */
> +		vma = find_vma(mm, addr);
> +		if (!vma || addr+len <= vma->vm_start)
> +			/* remember the address as a hint for next time */
> +			return (mm->free_area_cache = addr);
> +
> +		/* remember the largest hole we saw so far */
> +		if (addr + mm->cached_hole_size < vma->vm_start)
> +			mm->cached_hole_size = vma->vm_start - addr;
> +
> +		/* try just below the current vma->vm_start */
> +		addr = vma->vm_start - len;
> +		if (do_align)
> +			addr = COLOUR_ALIGN_DOWN(addr, pgoff);
> +	} while (len < vma->vm_start);
> +
> +bottomup:
> +	/*
> +	 * A failed mmap() very likely causes application failure,
> +	 * so fall back to the bottom-up function here. This scenario
> +	 * can happen with large stack limits and large mmap()
> +	 * allocations.
> +	 */
> +	mm->cached_hole_size = ~0UL;
> +	mm->free_area_cache = TASK_UNMAPPED_BASE;
> +	addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
> +	/*
> +	 * Restore the topdown base:
> +	 */
> +	mm->free_area_cache = mm->mmap_base;
> +	mm->cached_hole_size = ~0UL;
> +
> +	return addr;
> +}
> +
> +void arch_pick_mmap_layout(struct mm_struct *mm)
> +{
> +	unsigned long random_factor = 0UL;
> +
> +	/* 8 bits of randomness in 20 address space bits */
> +	if ((current->flags & PF_RANDOMIZE) &&
> +	    !(current->personality & ADDR_NO_RANDOMIZE))
> +		random_factor = (get_random_int() % (1 << 8)) << PAGE_SHIFT;
> +
> +	if (mmap_is_legacy()) {
> +		mm->mmap_base = TASK_UNMAPPED_BASE + random_factor;
> +		mm->get_unmapped_area = arch_get_unmapped_area;
> +		mm->unmap_area = arch_unmap_area;
> +	} else {
> +		mm->mmap_base = mmap_base(random_factor);
> +		mm->get_unmapped_area = arch_get_unmapped_area_topdown;
> +		mm->unmap_area = arch_unmap_area_topdown;
> +	}
> +}
>  
>  /*
>   * You really shouldn't be using read() or write() on /dev/mem.  This

same here...

commit 7dbaa466780a754154531b44c2086f6618cee3a8
Author: Rob Herring <rob.herring at calxeda.com>
Date:   Tue Nov 22 04:01:07 2011 +0100

    ARM: 7169/1: topdown mmap support





More information about the kernel-team mailing list