Commit 567b3515 authored by John David Anglin's avatar John David Anglin Committed by Helge Deller

parisc: Cleanup mmap implementation regarding color alignment

This change simplifies the randomization of file mapping regions. It
reworks the code to remove duplication. The flow is now similar to
that for mips. Finally, we consistently use the do_color_align variable
to determine when color alignment is needed.

Tested on rp3440.
Signed-off-by: default avatarJohn David Anglin <dave.anglin@bell.net>
Signed-off-by: default avatarHelge Deller <deller@gmx.de>
parent 653f3ea7
...@@ -25,31 +25,26 @@ ...@@ -25,31 +25,26 @@
#include <linux/random.h> #include <linux/random.h>
#include <linux/compat.h> #include <linux/compat.h>
/* we construct an artificial offset for the mapping based on the physical /*
* address of the kernel mapping variable */ * Construct an artificial page offset for the mapping based on the physical
#define GET_LAST_MMAP(filp) \ * address of the kernel file mapping variable.
(filp ? ((unsigned long) filp->f_mapping) >> 8 : 0UL) */
#define SET_LAST_MMAP(filp, val) \ #define GET_FILP_PGOFF(filp) \
{ /* nothing */ } (filp ? (((unsigned long) filp->f_mapping) >> 8) \
& ((SHM_COLOUR-1) >> PAGE_SHIFT) : 0UL)
static int get_offset(unsigned int last_mmap)
{
return (last_mmap & (SHM_COLOUR-1)) >> PAGE_SHIFT;
}
static unsigned long shared_align_offset(unsigned int last_mmap, static unsigned long shared_align_offset(unsigned long filp_pgoff,
unsigned long pgoff) unsigned long pgoff)
{ {
return (get_offset(last_mmap) + pgoff) << PAGE_SHIFT; return (filp_pgoff + pgoff) << PAGE_SHIFT;
} }
static inline unsigned long COLOR_ALIGN(unsigned long addr, static inline unsigned long COLOR_ALIGN(unsigned long addr,
unsigned int last_mmap, unsigned long pgoff) unsigned long filp_pgoff, unsigned long pgoff)
{ {
unsigned long base = (addr+SHM_COLOUR-1) & ~(SHM_COLOUR-1); unsigned long base = (addr+SHM_COLOUR-1) & ~(SHM_COLOUR-1);
unsigned long off = (SHM_COLOUR-1) & unsigned long off = (SHM_COLOUR-1) &
(shared_align_offset(last_mmap, pgoff) << PAGE_SHIFT); shared_align_offset(filp_pgoff, pgoff);
return base + off; return base + off;
} }
...@@ -98,126 +93,91 @@ static unsigned long mmap_upper_limit(struct rlimit *rlim_stack) ...@@ -98,126 +93,91 @@ static unsigned long mmap_upper_limit(struct rlimit *rlim_stack)
return PAGE_ALIGN(STACK_TOP - stack_base); return PAGE_ALIGN(STACK_TOP - stack_base);
} }
enum mmap_allocation_direction {UP, DOWN};
unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, static unsigned long arch_get_unmapped_area_common(struct file *filp,
unsigned long len, unsigned long pgoff, unsigned long flags) unsigned long addr, unsigned long len, unsigned long pgoff,
unsigned long flags, enum mmap_allocation_direction dir)
{ {
struct mm_struct *mm = current->mm; struct mm_struct *mm = current->mm;
struct vm_area_struct *vma, *prev; struct vm_area_struct *vma, *prev;
unsigned long task_size = TASK_SIZE; unsigned long filp_pgoff;
int do_color_align, last_mmap; int do_color_align;
struct vm_unmapped_area_info info; struct vm_unmapped_area_info info;
if (len > task_size) if (unlikely(len > TASK_SIZE))
return -ENOMEM; return -ENOMEM;
do_color_align = 0; do_color_align = 0;
if (filp || (flags & MAP_SHARED)) if (filp || (flags & MAP_SHARED))
do_color_align = 1; do_color_align = 1;
last_mmap = GET_LAST_MMAP(filp); filp_pgoff = GET_FILP_PGOFF(filp);
if (flags & MAP_FIXED) { if (flags & MAP_FIXED) {
if ((flags & MAP_SHARED) && last_mmap && /* Even MAP_FIXED mappings must reside within TASK_SIZE */
(addr - shared_align_offset(last_mmap, pgoff)) if (TASK_SIZE - len < addr)
return -EINVAL;
if ((flags & MAP_SHARED) && filp &&
(addr - shared_align_offset(filp_pgoff, pgoff))
& (SHM_COLOUR - 1)) & (SHM_COLOUR - 1))
return -EINVAL; return -EINVAL;
goto found_addr; return addr;
} }
if (addr) { if (addr) {
if (do_color_align && last_mmap) if (do_color_align)
addr = COLOR_ALIGN(addr, last_mmap, pgoff); addr = COLOR_ALIGN(addr, filp_pgoff, pgoff);
else else
addr = PAGE_ALIGN(addr); addr = PAGE_ALIGN(addr);
vma = find_vma_prev(mm, addr, &prev); vma = find_vma_prev(mm, addr, &prev);
if (task_size - len >= addr && if (TASK_SIZE - len >= addr &&
(!vma || addr + len <= vm_start_gap(vma)) && (!vma || addr + len <= vm_start_gap(vma)) &&
(!prev || addr >= vm_end_gap(prev))) (!prev || addr >= vm_end_gap(prev)))
goto found_addr; return addr;
} }
info.flags = 0;
info.length = len; info.length = len;
info.align_mask = do_color_align ? (PAGE_MASK & (SHM_COLOUR - 1)) : 0;
info.align_offset = shared_align_offset(filp_pgoff, pgoff);
if (dir == DOWN) {
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
info.low_limit = PAGE_SIZE;
info.high_limit = mm->mmap_base;
addr = vm_unmapped_area(&info);
if (!(addr & ~PAGE_MASK))
return addr;
VM_BUG_ON(addr != -ENOMEM);
/*
* 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.
*/
}
info.flags = 0;
info.low_limit = mm->mmap_legacy_base; info.low_limit = mm->mmap_legacy_base;
info.high_limit = mmap_upper_limit(NULL); info.high_limit = mmap_upper_limit(NULL);
info.align_mask = last_mmap ? (PAGE_MASK & (SHM_COLOUR - 1)) : 0; return vm_unmapped_area(&info);
info.align_offset = shared_align_offset(last_mmap, pgoff);
addr = vm_unmapped_area(&info);
found_addr:
if (do_color_align && !last_mmap && !(addr & ~PAGE_MASK))
SET_LAST_MMAP(filp, addr - (pgoff << PAGE_SHIFT));
return addr;
} }
unsigned long unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, unsigned long len, unsigned long pgoff, unsigned long flags)
const unsigned long len, const unsigned long pgoff,
const unsigned long flags)
{ {
struct vm_area_struct *vma, *prev; return arch_get_unmapped_area_common(filp,
struct mm_struct *mm = current->mm; addr, len, pgoff, flags, UP);
unsigned long addr = addr0; }
int do_color_align, last_mmap;
struct vm_unmapped_area_info info;
/* requested length too big for entire address space */
if (len > TASK_SIZE)
return -ENOMEM;
do_color_align = 0;
if (filp || (flags & MAP_SHARED))
do_color_align = 1;
last_mmap = GET_LAST_MMAP(filp);
if (flags & MAP_FIXED) {
if ((flags & MAP_SHARED) && last_mmap &&
(addr - shared_align_offset(last_mmap, pgoff))
& (SHM_COLOUR - 1))
return -EINVAL;
goto found_addr;
}
/* requesting a specific address */
if (addr) {
if (do_color_align && last_mmap)
addr = COLOR_ALIGN(addr, last_mmap, pgoff);
else
addr = PAGE_ALIGN(addr);
vma = find_vma_prev(mm, addr, &prev);
if (TASK_SIZE - len >= addr &&
(!vma || addr + len <= vm_start_gap(vma)) &&
(!prev || addr >= vm_end_gap(prev)))
goto found_addr;
}
info.flags = VM_UNMAPPED_AREA_TOPDOWN;
info.length = len;
info.low_limit = PAGE_SIZE;
info.high_limit = mm->mmap_base;
info.align_mask = last_mmap ? (PAGE_MASK & (SHM_COLOUR - 1)) : 0;
info.align_offset = shared_align_offset(last_mmap, pgoff);
addr = vm_unmapped_area(&info);
if (!(addr & ~PAGE_MASK))
goto found_addr;
VM_BUG_ON(addr != -ENOMEM);
/*
* 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.
*/
return arch_get_unmapped_area(filp, addr0, len, pgoff, flags);
found_addr:
if (do_color_align && !last_mmap && !(addr & ~PAGE_MASK))
SET_LAST_MMAP(filp, addr - (pgoff << PAGE_SHIFT));
return addr; unsigned long arch_get_unmapped_area_topdown(struct file *filp,
unsigned long addr, unsigned long len, unsigned long pgoff,
unsigned long flags)
{
return arch_get_unmapped_area_common(filp,
addr, len, pgoff, flags, DOWN);
} }
static int mmap_is_legacy(void) static int mmap_is_legacy(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment