From: Greg Kroah-Hartman Date: Thu, 14 Jan 2010 19:44:29 +0000 (-0800) Subject: mremap patch X-Git-Tag: v2.6.32.4~13 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=0518c197cfc08dc322fb30f4d39acffdf9c34477;p=thirdparty%2Fkernel%2Fstable-queue.git mremap patch --- diff --git a/queue-2.6.32/series b/queue-2.6.32/series index 764d3832e36..e2b71c3cd2a 100644 --- a/queue-2.6.32/series +++ b/queue-2.6.32/series @@ -1,3 +1,4 @@ +untangle-the-do_mremap-mess.patch fasync-split-fasync_helper-into-separate-add-remove-functions.patch asoc-fix-params_rate-macro-use-in-several-codecs.patch modules-skip-empty-sections-when-exporting-section-notes.patch diff --git a/queue-2.6.32/untangle-the-do_mremap-mess.patch b/queue-2.6.32/untangle-the-do_mremap-mess.patch new file mode 100644 index 00000000000..da1f11df1f1 --- /dev/null +++ b/queue-2.6.32/untangle-the-do_mremap-mess.patch @@ -0,0 +1,2547 @@ +From foo@baz Thu Jan 14 11:39:39 PST 2010 +Date: Thu, 14 Jan 2010 11:39:39 -0800 +To: Greg KH +From: Al Viro +Subject: untangle the do_mremap() mess + +This backports the following upstream commits all as one patch: + 54f5de709984bae0d31d823ff03de755f9dcac54 + ecc1a8993751de4e82eb18640d631dae1f626bd6 + 1a0ef85f84feb13f07b604fcf5b90ef7c2b5c82f + f106af4e90eadd76cfc0b5325f659619e08fb762 + 097eed103862f9c6a97f2e415e21d1134017b135 + 935874141df839c706cd6cdc438e85eb69d1525e + 0ec62d290912bb4b989be7563851bc364ec73b56 + c4caa778157dbbf04116f0ac2111e389b5cd7a29 + 2ea1d13f64efdf49319e86c87d9ba38c30902782 + 570dcf2c15463842e384eb597a87c1e39bead99b + 564b3bffc619dcbdd160de597b0547a7017ea010 + 0067bd8a55862ac9dd212bd1c4f6f5bff1ca1301 + f8b7256096a20436f6d0926747e3ac3d64c81d24 + 8c7b49b3ecd48923eb64ff57e07a1cdb74782970 + 9206de95b1ea68357996ec02be5db0638a0de2c1 + 2c6a10161d0b5fc047b5bd81b03693b9af99fab5 + 05d72faa6d13c9d857478a5d35c85db9adada685 + bb52d6694002b9d632bb355f64daa045c6293a4e + e77414e0aad6a1b063ba5e5750c582c75327ea6a + aa65607373a4daf2010e8c3867b6317619f3c1a3 + +Backport done by Greg Kroah-Hartman. Only minor tweaks were needed. + +Cc: David S. Miller +Cc: Hugh Dickins +Cc: Paul Mundt +Cc: Russell King +Cc: Linus Torvalds +Signed-off-by: Al Viro +Signed-off-by: Greg Kroah-Hartman + +--- + arch/alpha/kernel/osf_sys.c | 19 -- + arch/arm/include/asm/mman.h | 3 + arch/arm/kernel/calls.S | 2 + arch/arm/kernel/entry-common.S | 4 + arch/arm/kernel/sys_arm.c | 55 ------ + arch/arm/mm/mmap.c | 3 + arch/avr32/include/asm/syscalls.h | 4 + arch/avr32/kernel/sys_avr32.c | 31 --- + arch/avr32/kernel/syscall-stubs.S | 2 + arch/blackfin/kernel/sys_bfin.c | 33 ---- + arch/blackfin/mach-common/entry.S | 2 + arch/cris/kernel/sys_cris.c | 30 --- + arch/frv/kernel/sys_frv.c | 66 -------- + arch/h8300/kernel/sys_h8300.c | 83 ---------- + arch/h8300/kernel/syscalls.S | 2 + arch/ia64/ia32/sys_ia32.c | 3 + arch/ia64/kernel/sys_ia64.c | 83 ---------- + arch/m32r/kernel/sys_m32r.c | 24 -- + arch/m32r/kernel/syscall_table.S | 2 + arch/m68k/kernel/sys_m68k.c | 83 ---------- + arch/m68knommu/kernel/sys_m68k.c | 38 ---- + arch/m68knommu/kernel/syscalltable.S | 2 + arch/microblaze/kernel/sys_microblaze.c | 38 ---- + arch/microblaze/kernel/syscall_table.S | 2 + arch/mips/kernel/linux32.c | 19 -- + arch/mips/kernel/syscall.c | 32 --- + arch/mn10300/include/asm/mman.h | 5 + arch/mn10300/kernel/entry.S | 2 + arch/mn10300/kernel/sys_mn10300.c | 36 ---- + arch/parisc/kernel/sys_parisc.c | 30 --- + arch/powerpc/kernel/syscalls.c | 15 - + arch/s390/kernel/compat_linux.c | 37 ---- + arch/s390/kernel/sys_s390.c | 30 --- + arch/score/kernel/sys_score.c | 28 --- + arch/sh/kernel/sys_sh.c | 28 --- + arch/sh/mm/mmap.c | 3 + arch/sparc/kernel/sys_sparc_32.c | 64 ------- + arch/sparc/kernel/sys_sparc_64.c | 50 +----- + arch/sparc/kernel/systbls.h | 1 + arch/sparc/kernel/systbls_32.S | 4 + arch/sparc/kernel/systbls_64.S | 4 + arch/um/kernel/syscall.c | 28 --- + arch/um/sys-i386/shared/sysdep/syscalls.h | 4 + arch/x86/ia32/ia32entry.S | 2 + arch/x86/ia32/sys_ia32.c | 43 ----- + arch/x86/include/asm/sys_ia32.h | 3 + arch/x86/include/asm/syscalls.h | 2 + arch/x86/kernel/sys_i386_32.c | 27 --- + arch/x86/kernel/sys_x86_64.c | 17 -- + arch/x86/kernel/syscall_table_32.S | 2 + arch/xtensa/include/asm/syscall.h | 2 + arch/xtensa/include/asm/unistd.h | 2 + arch/xtensa/kernel/syscall.c | 25 --- + include/linux/syscalls.h | 4 + ipc/shm.c | 31 ++- + mm/mmap.c | 42 +---- + mm/mremap.c | 241 +++++++++++++++++++----------- + mm/util.c | 44 +++++ + 58 files changed, 342 insertions(+), 1179 deletions(-) + +--- a/arch/alpha/kernel/osf_sys.c ++++ b/arch/alpha/kernel/osf_sys.c +@@ -178,25 +178,18 @@ SYSCALL_DEFINE6(osf_mmap, unsigned long, + unsigned long, prot, unsigned long, flags, unsigned long, fd, + unsigned long, off) + { +- struct file *file = NULL; +- unsigned long ret = -EBADF; ++ unsigned long ret = -EINVAL; + + #if 0 + if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED)) + printk("%s: unimplemented OSF mmap flags %04lx\n", + current->comm, flags); + #endif +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- down_write(¤t->mm->mmap_sem); +- ret = do_mmap(file, addr, len, prot, flags, off); +- up_write(¤t->mm->mmap_sem); +- if (file) +- fput(file); ++ if ((off + PAGE_ALIGN(len)) < off) ++ goto out; ++ if (off & ~PAGE_MASK) ++ goto out; ++ ret = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); + out: + return ret; + } +--- a/arch/arm/include/asm/mman.h ++++ b/arch/arm/include/asm/mman.h +@@ -1 +1,4 @@ + #include ++ ++#define arch_mmap_check(addr, len, flags) \ ++ (((flags) & MAP_FIXED && (addr) < FIRST_USER_ADDRESS) ? -EINVAL : 0) +--- a/arch/arm/kernel/calls.S ++++ b/arch/arm/kernel/calls.S +@@ -172,7 +172,7 @@ + /* 160 */ CALL(sys_sched_get_priority_min) + CALL(sys_sched_rr_get_interval) + CALL(sys_nanosleep) +- CALL(sys_arm_mremap) ++ CALL(sys_mremap) + CALL(sys_setresuid16) + /* 165 */ CALL(sys_getresuid16) + CALL(sys_ni_syscall) /* vm86 */ +--- a/arch/arm/kernel/entry-common.S ++++ b/arch/arm/kernel/entry-common.S +@@ -416,12 +416,12 @@ sys_mmap2: + tst r5, #PGOFF_MASK + moveq r5, r5, lsr #PAGE_SHIFT - 12 + streq r5, [sp, #4] +- beq do_mmap2 ++ beq sys_mmap_pgoff + mov r0, #-EINVAL + mov pc, lr + #else + str r5, [sp, #4] +- b do_mmap2 ++ b sys_mmap_pgoff + #endif + ENDPROC(sys_mmap2) + +--- a/arch/arm/kernel/sys_arm.c ++++ b/arch/arm/kernel/sys_arm.c +@@ -28,41 +28,6 @@ + #include + #include + +-extern unsigned long do_mremap(unsigned long addr, unsigned long old_len, +- unsigned long new_len, unsigned long flags, +- unsigned long new_addr); +- +-/* common code for old and new mmaps */ +-inline long do_mmap2( +- unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- int error = -EINVAL; +- struct file * file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- +- if (flags & MAP_FIXED && addr < FIRST_USER_ADDRESS) +- goto out; +- +- error = -EBADF; +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- + struct mmap_arg_struct { + unsigned long addr; + unsigned long len; +@@ -84,29 +49,11 @@ asmlinkage int old_mmap(struct mmap_arg_ + if (a.offset & ~PAGE_MASK) + goto out; + +- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); ++ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); + out: + return error; + } + +-asmlinkage unsigned long +-sys_arm_mremap(unsigned long addr, unsigned long old_len, +- unsigned long new_len, unsigned long flags, +- unsigned long new_addr) +-{ +- unsigned long ret = -EINVAL; +- +- if (flags & MREMAP_FIXED && new_addr < FIRST_USER_ADDRESS) +- goto out; +- +- down_write(¤t->mm->mmap_sem); +- ret = do_mremap(addr, old_len, new_len, flags, new_addr); +- up_write(¤t->mm->mmap_sem); +- +-out: +- return ret; +-} +- + /* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. +--- a/arch/arm/mm/mmap.c ++++ b/arch/arm/mm/mmap.c +@@ -54,7 +54,8 @@ arch_get_unmapped_area(struct file *filp + * We enforce the MAP_FIXED case. + */ + if (flags & MAP_FIXED) { +- if (aliasing && flags & MAP_SHARED && addr & (SHMLBA - 1)) ++ if (aliasing && flags & MAP_SHARED && ++ (addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)) + return -EINVAL; + return addr; + } +--- a/arch/avr32/include/asm/syscalls.h ++++ b/arch/avr32/include/asm/syscalls.h +@@ -29,10 +29,6 @@ asmlinkage int sys_sigaltstack(const sta + struct pt_regs *); + asmlinkage int sys_rt_sigreturn(struct pt_regs *); + +-/* kernel/sys_avr32.c */ +-asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long, +- unsigned long, unsigned long, off_t); +- + /* mm/cache.c */ + asmlinkage int sys_cacheflush(int, void __user *, size_t); + +--- a/arch/avr32/kernel/sys_avr32.c ++++ b/arch/avr32/kernel/sys_avr32.c +@@ -5,39 +5,8 @@ + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +-#include +-#include +-#include +-#include + #include + +-#include +-#include +-#include +- +-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, off_t offset) +-{ +- int error = -EBADF; +- struct file *file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- return error; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, offset); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +- return error; +-} +- + int kernel_execve(const char *file, char **argv, char **envp) + { + register long scno asm("r8") = __NR_execve; +--- a/arch/avr32/kernel/syscall-stubs.S ++++ b/arch/avr32/kernel/syscall-stubs.S +@@ -61,7 +61,7 @@ __sys_execve: + __sys_mmap2: + pushm lr + st.w --sp, ARG6 +- call sys_mmap2 ++ call sys_mmap_pgoff + sub sp, -4 + popm pc + +--- a/arch/blackfin/kernel/sys_bfin.c ++++ b/arch/blackfin/kernel/sys_bfin.c +@@ -22,39 +22,6 @@ + #include + #include + +-/* common code for old and new mmaps */ +-static inline long +-do_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- int error = -EBADF; +- struct file *file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +- out: +- return error; +-} +- +-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- return do_mmap2(addr, len, prot, flags, fd, pgoff); +-} +- + asmlinkage void *sys_sram_alloc(size_t size, unsigned long flags) + { + return sram_alloc_with_lsl(size, flags); +--- a/arch/blackfin/mach-common/entry.S ++++ b/arch/blackfin/mach-common/entry.S +@@ -1422,7 +1422,7 @@ ENTRY(_sys_call_table) + .long _sys_ni_syscall /* streams2 */ + .long _sys_vfork /* 190 */ + .long _sys_getrlimit +- .long _sys_mmap2 ++ .long _sys_mmap_pgoff + .long _sys_truncate64 + .long _sys_ftruncate64 + .long _sys_stat64 /* 195 */ +--- a/arch/cris/kernel/sys_cris.c ++++ b/arch/cris/kernel/sys_cris.c +@@ -26,31 +26,6 @@ + #include + #include + +-/* common code for old and new mmaps */ +-static inline long +-do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, +- unsigned long flags, unsigned long fd, unsigned long pgoff) +-{ +- int error = -EBADF; +- struct file * file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- + asmlinkage unsigned long old_mmap(unsigned long __user *args) + { + unsigned long buffer[6]; +@@ -63,7 +38,7 @@ asmlinkage unsigned long old_mmap(unsign + if (buffer[5] & ~PAGE_MASK) /* verify that offset is on page boundary */ + goto out; + +- err = do_mmap2(buffer[0], buffer[1], buffer[2], buffer[3], ++ err = sys_mmap_pgoff(buffer[0], buffer[1], buffer[2], buffer[3], + buffer[4], buffer[5] >> PAGE_SHIFT); + out: + return err; +@@ -73,7 +48,8 @@ asmlinkage long + sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, unsigned long pgoff) + { +- return do_mmap2(addr, len, prot, flags, fd, pgoff); ++ /* bug(?): 8Kb pages here */ ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); + } + + /* +--- a/arch/frv/kernel/sys_frv.c ++++ b/arch/frv/kernel/sys_frv.c +@@ -31,9 +31,6 @@ asmlinkage long sys_mmap2(unsigned long + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) + { +- int error = -EBADF; +- struct file * file = NULL; +- + /* As with sparc32, make sure the shift for mmap2 is constant + (12), no matter what PAGE_SIZE we have.... */ + +@@ -41,69 +38,10 @@ asmlinkage long sys_mmap2(unsigned long + trying to map something we can't */ + if (pgoff & ((1 << (PAGE_SHIFT - 12)) - 1)) + return -EINVAL; +- pgoff >>= PAGE_SHIFT - 12; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- +-#if 0 /* DAVIDM - do we want this */ +-struct mmap_arg_struct64 { +- __u32 addr; +- __u32 len; +- __u32 prot; +- __u32 flags; +- __u64 offset; /* 64 bits */ +- __u32 fd; +-}; +- +-asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg) +-{ +- int error = -EFAULT; +- struct file * file = NULL; +- struct mmap_arg_struct64 a; +- unsigned long pgoff; +- +- if (copy_from_user(&a, arg, sizeof(a))) +- return -EFAULT; +- +- if ((long)a.offset & ~PAGE_MASK) +- return -EINVAL; +- +- pgoff = a.offset >> PAGE_SHIFT; +- if ((a.offset >> PAGE_SHIFT) != pgoff) +- return -EINVAL; +- +- if (!(a.flags & MAP_ANONYMOUS)) { +- error = -EBADF; +- file = fget(a.fd); +- if (!file) +- goto out; +- } +- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- if (file) +- fput(file); +-out: +- return error; ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, ++ pgoff >> (PAGE_SHIFT - 12)); + } +-#endif + + /* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. +--- a/arch/h8300/kernel/syscalls.S ++++ b/arch/h8300/kernel/syscalls.S +@@ -206,7 +206,7 @@ SYMBOL_NAME_LABEL(sys_call_table) + .long SYMBOL_NAME(sys_ni_syscall) /* streams2 */ + .long SYMBOL_NAME(sys_vfork) /* 190 */ + .long SYMBOL_NAME(sys_getrlimit) +- .long SYMBOL_NAME(sys_mmap2) ++ .long SYMBOL_NAME(sys_mmap_pgoff) + .long SYMBOL_NAME(sys_truncate64) + .long SYMBOL_NAME(sys_ftruncate64) + .long SYMBOL_NAME(sys_stat64) /* 195 */ +--- a/arch/h8300/kernel/sys_h8300.c ++++ b/arch/h8300/kernel/sys_h8300.c +@@ -26,39 +26,6 @@ + #include + #include + +-/* common code for old and new mmaps */ +-static inline long do_mmap2( +- unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- int error = -EBADF; +- struct file * file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- +-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- return do_mmap2(addr, len, prot, flags, fd, pgoff); +-} +- + /* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to +@@ -87,58 +54,12 @@ asmlinkage int old_mmap(struct mmap_arg_ + if (a.offset & ~PAGE_MASK) + goto out; + +- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- +- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); ++ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, ++ a.offset >> PAGE_SHIFT); + out: + return error; + } + +-#if 0 /* DAVIDM - do we want this */ +-struct mmap_arg_struct64 { +- __u32 addr; +- __u32 len; +- __u32 prot; +- __u32 flags; +- __u64 offset; /* 64 bits */ +- __u32 fd; +-}; +- +-asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg) +-{ +- int error = -EFAULT; +- struct file * file = NULL; +- struct mmap_arg_struct64 a; +- unsigned long pgoff; +- +- if (copy_from_user(&a, arg, sizeof(a))) +- return -EFAULT; +- +- if ((long)a.offset & ~PAGE_MASK) +- return -EINVAL; +- +- pgoff = a.offset >> PAGE_SHIFT; +- if ((a.offset >> PAGE_SHIFT) != pgoff) +- return -EINVAL; +- +- if (!(a.flags & MAP_ANONYMOUS)) { +- error = -EBADF; +- file = fget(a.fd); +- if (!file) +- goto out; +- } +- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- if (file) +- fput(file); +-out: +- return error; +-} +-#endif +- + struct sel_arg_struct { + unsigned long n; + fd_set *inp, *outp, *exp; +--- a/arch/ia64/ia32/sys_ia32.c ++++ b/arch/ia64/ia32/sys_ia32.c +@@ -858,6 +858,9 @@ ia32_do_mmap (struct file *file, unsigne + + prot = get_prot32(prot); + ++ if (flags & MAP_HUGETLB) ++ return -ENOMEM; ++ + #if PAGE_SHIFT > IA32_PAGE_SHIFT + mutex_lock(&ia32_mmap_mutex); + { +--- a/arch/ia64/kernel/sys_ia64.c ++++ b/arch/ia64/kernel/sys_ia64.c +@@ -100,51 +100,7 @@ sys_getpagesize (void) + asmlinkage unsigned long + ia64_brk (unsigned long brk) + { +- unsigned long rlim, retval, newbrk, oldbrk; +- struct mm_struct *mm = current->mm; +- +- /* +- * Most of this replicates the code in sys_brk() except for an additional safety +- * check and the clearing of r8. However, we can't call sys_brk() because we need +- * to acquire the mmap_sem before we can do the test... +- */ +- down_write(&mm->mmap_sem); +- +- if (brk < mm->end_code) +- goto out; +- newbrk = PAGE_ALIGN(brk); +- oldbrk = PAGE_ALIGN(mm->brk); +- if (oldbrk == newbrk) +- goto set_brk; +- +- /* Always allow shrinking brk. */ +- if (brk <= mm->brk) { +- if (!do_munmap(mm, newbrk, oldbrk-newbrk)) +- goto set_brk; +- goto out; +- } +- +- /* Check against unimplemented/unmapped addresses: */ +- if ((newbrk - oldbrk) > RGN_MAP_LIMIT || REGION_OFFSET(newbrk) > RGN_MAP_LIMIT) +- goto out; +- +- /* Check against rlimit.. */ +- rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur; +- if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim) +- goto out; +- +- /* Check against existing mmap mappings. */ +- if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE)) +- goto out; +- +- /* Ok, looks good - let it rip. */ +- if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk) +- goto out; +-set_brk: +- mm->brk = brk; +-out: +- retval = mm->brk; +- up_write(&mm->mmap_sem); ++ unsigned long retval = sys_brk(brk); + force_successful_syscall_return(); + return retval; + } +@@ -185,39 +141,6 @@ int ia64_mmap_check(unsigned long addr, + return 0; + } + +-static inline unsigned long +-do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, unsigned long pgoff) +-{ +- struct file *file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- return -EBADF; +- +- if (!file->f_op || !file->f_op->mmap) { +- addr = -ENODEV; +- goto out; +- } +- } +- +- /* Careful about overflows.. */ +- len = PAGE_ALIGN(len); +- if (!len || len > TASK_SIZE) { +- addr = -EINVAL; +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +-out: if (file) +- fput(file); +- return addr; +-} +- + /* + * mmap2() is like mmap() except that the offset is expressed in units + * of PAGE_SIZE (instead of bytes). This allows to mmap2() (pieces +@@ -226,7 +149,7 @@ out: if (file) + asmlinkage unsigned long + sys_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, long pgoff) + { +- addr = do_mmap2(addr, len, prot, flags, fd, pgoff); ++ addr = sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); + if (!IS_ERR((void *) addr)) + force_successful_syscall_return(); + return addr; +@@ -238,7 +161,7 @@ sys_mmap (unsigned long addr, unsigned l + if (offset_in_page(off) != 0) + return -EINVAL; + +- addr = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); ++ addr = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); + if (!IS_ERR((void *) addr)) + force_successful_syscall_return(); + return addr; +--- a/arch/m32r/kernel/syscall_table.S ++++ b/arch/m32r/kernel/syscall_table.S +@@ -191,7 +191,7 @@ ENTRY(sys_call_table) + .long sys_ni_syscall /* streams2 */ + .long sys_vfork /* 190 */ + .long sys_getrlimit +- .long sys_mmap2 ++ .long sys_mmap_pgoff + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ +--- a/arch/m32r/kernel/sys_m32r.c ++++ b/arch/m32r/kernel/sys_m32r.c +@@ -76,30 +76,6 @@ asmlinkage int sys_tas(int __user *addr) + return oldval; + } + +-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- int error = -EBADF; +- struct file *file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- + /* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * +--- a/arch/m68k/kernel/sys_m68k.c ++++ b/arch/m68k/kernel/sys_m68k.c +@@ -29,37 +29,16 @@ + #include + #include + +-/* common code for old and new mmaps */ +-static inline long do_mmap2( +- unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- int error = -EBADF; +- struct file * file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- + asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) + { +- return do_mmap2(addr, len, prot, flags, fd, pgoff); ++ /* ++ * This is wrong for sun3 - there PAGE_SIZE is 8Kb, ++ * so we need to shift the argument down by 1; m68k mmap64(3) ++ * (in libc) expects the last argument of mmap2 in 4Kb units. ++ */ ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); + } + + /* +@@ -90,57 +69,11 @@ asmlinkage int old_mmap(struct mmap_arg_ + if (a.offset & ~PAGE_MASK) + goto out; + +- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- +- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); +-out: +- return error; +-} +- +-#if 0 +-struct mmap_arg_struct64 { +- __u32 addr; +- __u32 len; +- __u32 prot; +- __u32 flags; +- __u64 offset; /* 64 bits */ +- __u32 fd; +-}; +- +-asmlinkage long sys_mmap64(struct mmap_arg_struct64 *arg) +-{ +- int error = -EFAULT; +- struct file * file = NULL; +- struct mmap_arg_struct64 a; +- unsigned long pgoff; +- +- if (copy_from_user(&a, arg, sizeof(a))) +- return -EFAULT; +- +- if ((long)a.offset & ~PAGE_MASK) +- return -EINVAL; +- +- pgoff = a.offset >> PAGE_SHIFT; +- if ((a.offset >> PAGE_SHIFT) != pgoff) +- return -EINVAL; +- +- if (!(a.flags & MAP_ANONYMOUS)) { +- error = -EBADF; +- file = fget(a.fd); +- if (!file) +- goto out; +- } +- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- if (file) +- fput(file); ++ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, ++ a.offset >> PAGE_SHIFT); + out: + return error; + } +-#endif + + struct sel_arg_struct { + unsigned long n; +--- a/arch/m68knommu/kernel/syscalltable.S ++++ b/arch/m68knommu/kernel/syscalltable.S +@@ -210,7 +210,7 @@ ENTRY(sys_call_table) + .long sys_ni_syscall /* streams2 */ + .long sys_vfork /* 190 */ + .long sys_getrlimit +- .long sys_mmap2 ++ .long sys_mmap_pgoff + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ +--- a/arch/m68knommu/kernel/sys_m68k.c ++++ b/arch/m68knommu/kernel/sys_m68k.c +@@ -27,39 +27,6 @@ + #include + #include + +-/* common code for old and new mmaps */ +-static inline long do_mmap2( +- unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- int error = -EBADF; +- struct file * file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- +-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- return do_mmap2(addr, len, prot, flags, fd, pgoff); +-} +- + /* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to +@@ -88,9 +55,8 @@ asmlinkage int old_mmap(struct mmap_arg_ + if (a.offset & ~PAGE_MASK) + goto out; + +- a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- +- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); ++ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, ++ a.offset >> PAGE_SHIFT); + out: + return error; + } +--- a/arch/microblaze/kernel/syscall_table.S ++++ b/arch/microblaze/kernel/syscall_table.S +@@ -196,7 +196,7 @@ ENTRY(sys_call_table) + .long sys_ni_syscall /* reserved for streams2 */ + .long sys_vfork /* 190 */ + .long sys_getrlimit +- .long sys_mmap2 /* mmap2 */ ++ .long sys_mmap_pgoff /* mmap2 */ + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ +--- a/arch/microblaze/kernel/sys_microblaze.c ++++ b/arch/microblaze/kernel/sys_microblaze.c +@@ -62,46 +62,14 @@ out: + return error; + } + +-asmlinkage long +-sys_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- struct file *file = NULL; +- int ret = -EBADF; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) { +- printk(KERN_INFO "no fd in mmap\r\n"); +- goto out; +- } +- } +- +- down_write(¤t->mm->mmap_sem); +- ret = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- if (file) +- fput(file); +-out: +- return ret; +-} +- + asmlinkage long sys_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, off_t pgoff) + { +- int err = -EINVAL; +- +- if (pgoff & ~PAGE_MASK) { +- printk(KERN_INFO "no pagemask in mmap\r\n"); +- goto out; +- } ++ if (pgoff & ~PAGE_MASK) ++ return -EINVAL; + +- err = sys_mmap2(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT); +-out: +- return err; ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT); + } + + /* +--- a/arch/mips/kernel/linux32.c ++++ b/arch/mips/kernel/linux32.c +@@ -67,28 +67,13 @@ SYSCALL_DEFINE6(32_mmap2, unsigned long, + unsigned long, prot, unsigned long, flags, unsigned long, fd, + unsigned long, pgoff) + { +- struct file * file = NULL; + unsigned long error; + + error = -EINVAL; + if (pgoff & (~PAGE_MASK >> 12)) + goto out; +- pgoff >>= PAGE_SHIFT-12; +- +- if (!(flags & MAP_ANONYMOUS)) { +- error = -EBADF; +- file = fget(fd); +- if (!file) +- goto out; +- } +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- if (file) +- fput(file); +- ++ error = sys_mmap_pgoff(addr, len, prot, flags, fd, ++ pgoff >> (PAGE_SHIFT-12)); + out: + return error; + } +--- a/arch/mips/kernel/syscall.c ++++ b/arch/mips/kernel/syscall.c +@@ -93,7 +93,8 @@ unsigned long arch_get_unmapped_area(str + * We do not accept a shared mapping if it would violate + * cache aliasing constraints. + */ +- if ((flags & MAP_SHARED) && (addr & shm_align_mask)) ++ if ((flags & MAP_SHARED) && ++ ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) + return -EINVAL; + return addr; + } +@@ -129,31 +130,6 @@ unsigned long arch_get_unmapped_area(str + } + } + +-/* common code for old and new mmaps */ +-static inline unsigned long +-do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, +- unsigned long flags, unsigned long fd, unsigned long pgoff) +-{ +- unsigned long error = -EBADF; +- struct file * file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- + SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len, + unsigned long, prot, unsigned long, flags, unsigned long, + fd, off_t, offset) +@@ -164,7 +140,7 @@ SYSCALL_DEFINE6(mips_mmap, unsigned long + if (offset & ~PAGE_MASK) + goto out; + +- result = do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); ++ result = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + + out: + return result; +@@ -177,7 +153,7 @@ SYSCALL_DEFINE6(mips_mmap2, unsigned lon + if (pgoff & (~PAGE_MASK >> 12)) + return -EINVAL; + +- return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12)); ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT-12)); + } + + save_static_function(sys_fork); +--- a/arch/mn10300/include/asm/mman.h ++++ b/arch/mn10300/include/asm/mman.h +@@ -1 +1,6 @@ + #include ++ ++#define MIN_MAP_ADDR PAGE_SIZE /* minimum fixed mmap address */ ++ ++#define arch_mmap_check(addr, len, flags) \ ++ (((flags) & MAP_FIXED && (addr) < MIN_MAP_ADDR) ? -EINVAL : 0) +--- a/arch/mn10300/kernel/entry.S ++++ b/arch/mn10300/kernel/entry.S +@@ -578,7 +578,7 @@ ENTRY(sys_call_table) + .long sys_ni_syscall /* reserved for streams2 */ + .long sys_vfork /* 190 */ + .long sys_getrlimit +- .long sys_mmap2 ++ .long sys_mmap_pgoff + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ +--- a/arch/mn10300/kernel/sys_mn10300.c ++++ b/arch/mn10300/kernel/sys_mn10300.c +@@ -23,47 +23,13 @@ + + #include + +-#define MIN_MAP_ADDR PAGE_SIZE /* minimum fixed mmap address */ +- +-/* +- * memory mapping syscall +- */ +-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- struct file *file = NULL; +- long error = -EINVAL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- +- if (flags & MAP_FIXED && addr < MIN_MAP_ADDR) +- goto out; +- +- error = -EBADF; +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- + asmlinkage long old_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long offset) + { + if (offset & ~PAGE_MASK) + return -EINVAL; +- return sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + } + + struct sel_arg_struct { +--- a/arch/parisc/kernel/sys_parisc.c ++++ b/arch/parisc/kernel/sys_parisc.c +@@ -110,37 +110,14 @@ unsigned long arch_get_unmapped_area(str + return addr; + } + +-static unsigned long do_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, unsigned long fd, +- unsigned long pgoff) +-{ +- struct file * file = NULL; +- unsigned long error = -EBADF; +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file != NULL) +- fput(file); +-out: +- return error; +-} +- + asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, unsigned long fd, + unsigned long pgoff) + { + /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE + we have. */ +- return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12)); ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, ++ pgoff >> (PAGE_SHIFT - 12)); + } + + asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, +@@ -148,7 +125,8 @@ asmlinkage unsigned long sys_mmap(unsign + unsigned long offset) + { + if (!(offset & ~PAGE_MASK)) { +- return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, ++ offset >> PAGE_SHIFT); + } else { + return -EINVAL; + } +--- a/arch/powerpc/kernel/syscalls.c ++++ b/arch/powerpc/kernel/syscalls.c +@@ -140,7 +140,6 @@ static inline unsigned long do_mmap2(uns + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long off, int shift) + { +- struct file * file = NULL; + unsigned long ret = -EINVAL; + + if (!arch_validate_prot(prot)) +@@ -151,20 +150,8 @@ static inline unsigned long do_mmap2(uns + goto out; + off >>= shift; + } +- +- ret = -EBADF; +- if (!(flags & MAP_ANONYMOUS)) { +- if (!(file = fget(fd))) +- goto out; +- } +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + +- down_write(¤t->mm->mmap_sem); +- ret = do_mmap_pgoff(file, addr, len, prot, flags, off); +- up_write(¤t->mm->mmap_sem); +- if (file) +- fput(file); ++ ret = sys_mmap_pgoff(addr, len, prot, flags, fd, off); + out: + return ret; + } +--- a/arch/s390/kernel/compat_linux.c ++++ b/arch/s390/kernel/compat_linux.c +@@ -683,38 +683,6 @@ struct mmap_arg_struct_emu31 { + u32 offset; + }; + +-/* common code for old and new mmaps */ +-static inline long do_mmap2( +- unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- struct file * file = NULL; +- unsigned long error = -EBADF; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) { +- /* Result is out of bounds. */ +- do_munmap(current->mm, addr, len); +- error = -ENOMEM; +- } +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- +- + asmlinkage unsigned long + old32_mmap(struct mmap_arg_struct_emu31 __user *arg) + { +@@ -728,7 +696,8 @@ old32_mmap(struct mmap_arg_struct_emu31 + if (a.offset & ~PAGE_MASK) + goto out; + +- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); ++ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, ++ a.offset >> PAGE_SHIFT); + out: + return error; + } +@@ -741,7 +710,7 @@ sys32_mmap2(struct mmap_arg_struct_emu31 + + if (copy_from_user(&a, arg, sizeof(a))) + goto out; +- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); ++ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); + out: + return error; + } +--- a/arch/s390/kernel/sys_s390.c ++++ b/arch/s390/kernel/sys_s390.c +@@ -32,32 +32,6 @@ + #include + #include "entry.h" + +-/* common code for old and new mmaps */ +-static inline long do_mmap2( +- unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- long error = -EBADF; +- struct file * file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- + /* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. Linux for S/390 isn't able to handle more than 5 +@@ -81,7 +55,7 @@ SYSCALL_DEFINE1(mmap2, struct mmap_arg_s + + if (copy_from_user(&a, arg, sizeof(a))) + goto out; +- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); ++ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); + out: + return error; + } +@@ -98,7 +72,7 @@ SYSCALL_DEFINE1(s390_old_mmap, struct mm + if (a.offset & ~PAGE_MASK) + goto out; + +- error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); ++ error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); + out: + return error; + } +--- a/arch/score/kernel/sys_score.c ++++ b/arch/score/kernel/sys_score.c +@@ -36,34 +36,16 @@ asmlinkage long + sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, + unsigned long flags, unsigned long fd, unsigned long pgoff) + { +- int error = -EBADF; +- struct file *file = NULL; +- +- if (pgoff & (~PAGE_MASK >> 12)) +- return -EINVAL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- return error; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +- +- return error; ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); + } + + asmlinkage long + sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, +- unsigned long flags, unsigned long fd, off_t pgoff) ++ unsigned long flags, unsigned long fd, off_t offset) + { +- return sys_mmap2(addr, len, prot, flags, fd, pgoff >> PAGE_SHIFT); ++ if (unlikely(offset & ~PAGE_MASK)) ++ return -EINVAL; ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + } + + asmlinkage long +--- a/arch/sh/kernel/sys_sh.c ++++ b/arch/sh/kernel/sys_sh.c +@@ -28,37 +28,13 @@ + #include + #include + +-static inline long +-do_mmap2(unsigned long addr, unsigned long len, unsigned long prot, +- unsigned long flags, int fd, unsigned long pgoff) +-{ +- int error = -EBADF; +- struct file *file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- + asmlinkage int old_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + int fd, unsigned long off) + { + if (off & ~PAGE_MASK) + return -EINVAL; +- return do_mmap2(addr, len, prot, flags, fd, off>>PAGE_SHIFT); ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, off>>PAGE_SHIFT); + } + + asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, +@@ -74,7 +50,7 @@ asmlinkage long sys_mmap2(unsigned long + + pgoff >>= PAGE_SHIFT - 12; + +- return do_mmap2(addr, len, prot, flags, fd, pgoff); ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); + } + + /* +--- a/arch/sh/mm/mmap.c ++++ b/arch/sh/mm/mmap.c +@@ -54,7 +54,8 @@ unsigned long arch_get_unmapped_area(str + /* We do not accept a shared mapping if it would violate + * cache aliasing constraints. + */ +- if ((flags & MAP_SHARED) && (addr & shm_align_mask)) ++ if ((flags & MAP_SHARED) && ++ ((addr - (pgoff << PAGE_SHIFT)) & shm_align_mask)) + return -EINVAL; + return addr; + } +--- a/arch/sparc/kernel/sys_sparc_32.c ++++ b/arch/sparc/kernel/sys_sparc_32.c +@@ -45,7 +45,8 @@ unsigned long arch_get_unmapped_area(str + /* We do not accept a shared mapping if it would violate + * cache aliasing constraints. + */ +- if ((flags & MAP_SHARED) && (addr & (SHMLBA - 1))) ++ if ((flags & MAP_SHARED) && ++ ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) + return -EINVAL; + return addr; + } +@@ -79,15 +80,6 @@ unsigned long arch_get_unmapped_area(str + } + } + +-asmlinkage unsigned long sparc_brk(unsigned long brk) +-{ +- if(ARCH_SUN4C) { +- if ((brk & 0xe0000000) != (current->mm->brk & 0xe0000000)) +- return current->mm->brk; +- } +- return sys_brk(brk); +-} +- + /* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix traditionally does this, though. +@@ -234,31 +226,6 @@ int sparc_mmap_check(unsigned long addr, + } + + /* Linux version of mmap */ +-static unsigned long do_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, unsigned long fd, +- unsigned long pgoff) +-{ +- struct file * file = NULL; +- unsigned long retval = -EBADF; +- +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- len = PAGE_ALIGN(len); +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- +- down_write(¤t->mm->mmap_sem); +- retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return retval; +-} + + asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, unsigned long fd, +@@ -266,14 +233,16 @@ asmlinkage unsigned long sys_mmap2(unsig + { + /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE + we have. */ +- return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12)); ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, ++ pgoff >> (PAGE_SHIFT - 12)); + } + + asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, unsigned long fd, + unsigned long off) + { +- return do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT); ++ /* no alignment check? */ ++ return sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); + } + + long sparc_remap_file_pages(unsigned long start, unsigned long size, +@@ -287,27 +256,6 @@ long sparc_remap_file_pages(unsigned lon + (pgoff >> (PAGE_SHIFT - 12)), flags); + } + +-extern unsigned long do_mremap(unsigned long addr, +- unsigned long old_len, unsigned long new_len, +- unsigned long flags, unsigned long new_addr); +- +-asmlinkage unsigned long sparc_mremap(unsigned long addr, +- unsigned long old_len, unsigned long new_len, +- unsigned long flags, unsigned long new_addr) +-{ +- unsigned long ret = -EINVAL; +- +- if (unlikely(sparc_mmap_check(addr, old_len))) +- goto out; +- if (unlikely(sparc_mmap_check(new_addr, new_len))) +- goto out; +- down_write(¤t->mm->mmap_sem); +- ret = do_mremap(addr, old_len, new_len, flags, new_addr); +- up_write(¤t->mm->mmap_sem); +-out: +- return ret; +-} +- + /* we come to here via sys_nis_syscall so it can setup the regs argument */ + asmlinkage unsigned long + c_sys_nis_syscall (struct pt_regs *regs) +--- a/arch/sparc/kernel/sys_sparc_64.c ++++ b/arch/sparc/kernel/sys_sparc_64.c +@@ -317,10 +317,14 @@ bottomup: + unsigned long get_fb_unmapped_area(struct file *filp, unsigned long orig_addr, unsigned long len, unsigned long pgoff, unsigned long flags) + { + unsigned long align_goal, addr = -ENOMEM; ++ unsigned long (*get_area)(struct file *, unsigned long, ++ unsigned long, unsigned long, unsigned long); ++ ++ get_area = current->mm->get_unmapped_area; + + if (flags & MAP_FIXED) { + /* Ok, don't mess with it. */ +- return get_unmapped_area(NULL, orig_addr, len, pgoff, flags); ++ return get_area(NULL, orig_addr, len, pgoff, flags); + } + flags &= ~MAP_SHARED; + +@@ -333,7 +337,7 @@ unsigned long get_fb_unmapped_area(struc + align_goal = (64UL * 1024); + + do { +- addr = get_unmapped_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags); ++ addr = get_area(NULL, orig_addr, len + (align_goal - PAGE_SIZE), pgoff, flags); + if (!(addr & ~PAGE_MASK)) { + addr = (addr + (align_goal - 1UL)) & ~(align_goal - 1UL); + break; +@@ -351,7 +355,7 @@ unsigned long get_fb_unmapped_area(struc + * be obtained. + */ + if (addr & ~PAGE_MASK) +- addr = get_unmapped_area(NULL, orig_addr, len, pgoff, flags); ++ addr = get_area(NULL, orig_addr, len, pgoff, flags); + + return addr; + } +@@ -399,18 +403,6 @@ void arch_pick_mmap_layout(struct mm_str + } + } + +-SYSCALL_DEFINE1(sparc_brk, unsigned long, brk) +-{ +- /* People could try to be nasty and use ta 0x6d in 32bit programs */ +- if (test_thread_flag(TIF_32BIT) && brk >= STACK_TOP32) +- return current->mm->brk; +- +- if (unlikely(straddles_64bit_va_hole(current->mm->brk, brk))) +- return current->mm->brk; +- +- return sys_brk(brk); +-} +- + /* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix traditionally does this, though. +@@ -568,23 +560,13 @@ SYSCALL_DEFINE6(mmap, unsigned long, add + unsigned long, prot, unsigned long, flags, unsigned long, fd, + unsigned long, off) + { +- struct file * file = NULL; +- unsigned long retval = -EBADF; +- +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- len = PAGE_ALIGN(len); ++ unsigned long retval = -EINVAL; + +- down_write(¤t->mm->mmap_sem); +- retval = do_mmap(file, addr, len, prot, flags, off); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); ++ if ((off + PAGE_ALIGN(len)) < off) ++ goto out; ++ if (off & ~PAGE_MASK) ++ goto out; ++ retval = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); + out: + return retval; + } +@@ -614,12 +596,6 @@ SYSCALL_DEFINE5(64_mremap, unsigned long + + if (test_thread_flag(TIF_32BIT)) + goto out; +- if (unlikely(new_len >= VA_EXCLUDE_START)) +- goto out; +- if (unlikely(sparc_mmap_check(addr, old_len))) +- goto out; +- if (unlikely(sparc_mmap_check(new_addr, new_len))) +- goto out; + + down_write(¤t->mm->mmap_sem); + ret = do_mremap(addr, old_len, new_len, flags, new_addr); +--- a/arch/sparc/kernel/systbls_32.S ++++ b/arch/sparc/kernel/systbls_32.S +@@ -19,7 +19,7 @@ sys_call_table: + /*0*/ .long sys_restart_syscall, sys_exit, sys_fork, sys_read, sys_write + /*5*/ .long sys_open, sys_close, sys_wait4, sys_creat, sys_link + /*10*/ .long sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys_mknod +-/*15*/ .long sys_chmod, sys_lchown16, sparc_brk, sys_nis_syscall, sys_lseek ++/*15*/ .long sys_chmod, sys_lchown16, sys_brk, sys_nis_syscall, sys_lseek + /*20*/ .long sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16 + /*25*/ .long sys_vmsplice, sys_ptrace, sys_alarm, sys_sigaltstack, sys_pause + /*30*/ .long sys_utime, sys_lchown, sys_fchown, sys_access, sys_nice +@@ -67,7 +67,7 @@ sys_call_table: + /*235*/ .long sys_fstatfs64, sys_llseek, sys_mlock, sys_munlock, sys_mlockall + /*240*/ .long sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler + /*245*/ .long sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep +-/*250*/ .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl ++/*250*/ .long sys_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl + /*255*/ .long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep + /*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun + /*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy +--- a/arch/sparc/kernel/systbls_64.S ++++ b/arch/sparc/kernel/systbls_64.S +@@ -21,7 +21,7 @@ sys_call_table32: + /*0*/ .word sys_restart_syscall, sys32_exit, sys_fork, sys_read, sys_write + /*5*/ .word sys32_open, sys_close, sys32_wait4, sys32_creat, sys_link + /*10*/ .word sys_unlink, sunos_execv, sys_chdir, sys_chown16, sys32_mknod +-/*15*/ .word sys_chmod, sys_lchown16, sys_sparc_brk, sys32_perfctr, sys32_lseek ++/*15*/ .word sys_chmod, sys_lchown16, sys_brk, sys32_perfctr, sys32_lseek + /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid16, sys_getuid16 + /*25*/ .word sys32_vmsplice, compat_sys_ptrace, sys_alarm, sys32_sigaltstack, sys_pause + /*30*/ .word compat_sys_utime, sys_lchown, sys_fchown, sys32_access, sys32_nice +@@ -96,7 +96,7 @@ sys_call_table: + /*0*/ .word sys_restart_syscall, sparc_exit, sys_fork, sys_read, sys_write + /*5*/ .word sys_open, sys_close, sys_wait4, sys_creat, sys_link + /*10*/ .word sys_unlink, sys_nis_syscall, sys_chdir, sys_chown, sys_mknod +-/*15*/ .word sys_chmod, sys_lchown, sys_sparc_brk, sys_perfctr, sys_lseek ++/*15*/ .word sys_chmod, sys_lchown, sys_brk, sys_perfctr, sys_lseek + /*20*/ .word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid + /*25*/ .word sys_vmsplice, sys_ptrace, sys_alarm, sys_sigaltstack, sys_nis_syscall + /*30*/ .word sys_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice +--- a/arch/sparc/kernel/systbls.h ++++ b/arch/sparc/kernel/systbls.h +@@ -9,7 +9,6 @@ + struct new_utsname; + + extern asmlinkage unsigned long sys_getpagesize(void); +-extern asmlinkage unsigned long sparc_brk(unsigned long brk); + extern asmlinkage long sparc_pipe(struct pt_regs *regs); + extern asmlinkage long sys_ipc(unsigned int call, int first, + unsigned long second, +--- a/arch/um/kernel/syscall.c ++++ b/arch/um/kernel/syscall.c +@@ -8,6 +8,7 @@ + #include "linux/mm.h" + #include "linux/sched.h" + #include "linux/utsname.h" ++#include "linux/syscalls.h" + #include "asm/current.h" + #include "asm/mman.h" + #include "asm/uaccess.h" +@@ -37,31 +38,6 @@ long sys_vfork(void) + return ret; + } + +-/* common code for old and new mmaps */ +-long sys_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- long error = -EBADF; +- struct file * file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +- out: +- return error; +-} +- + long old_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long offset) +@@ -70,7 +46,7 @@ long old_mmap(unsigned long addr, unsign + if (offset & ~PAGE_MASK) + goto out; + +- err = sys_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); ++ err = sys_mmap_pgoff(addr, len, prot, flags, fd, offset >> PAGE_SHIFT); + out: + return err; + } +--- a/arch/um/sys-i386/shared/sysdep/syscalls.h ++++ b/arch/um/sys-i386/shared/sysdep/syscalls.h +@@ -20,7 +20,3 @@ extern syscall_handler_t *sys_call_table + #define EXECUTE_SYSCALL(syscall, regs) \ + ((long (*)(struct syscall_args)) \ + (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) +- +-extern long sys_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff); +--- a/arch/x86/ia32/ia32entry.S ++++ b/arch/x86/ia32/ia32entry.S +@@ -696,7 +696,7 @@ ia32_sys_call_table: + .quad quiet_ni_syscall /* streams2 */ + .quad stub32_vfork /* 190 */ + .quad compat_sys_getrlimit +- .quad sys32_mmap2 ++ .quad sys_mmap_pgoff + .quad sys32_truncate64 + .quad sys32_ftruncate64 + .quad sys32_stat64 /* 195 */ +--- a/arch/x86/ia32/sys_ia32.c ++++ b/arch/x86/ia32/sys_ia32.c +@@ -155,9 +155,6 @@ struct mmap_arg_struct { + asmlinkage long sys32_mmap(struct mmap_arg_struct __user *arg) + { + struct mmap_arg_struct a; +- struct file *file = NULL; +- unsigned long retval; +- struct mm_struct *mm ; + + if (copy_from_user(&a, arg, sizeof(a))) + return -EFAULT; +@@ -165,22 +162,8 @@ asmlinkage long sys32_mmap(struct mmap_a + if (a.offset & ~PAGE_MASK) + return -EINVAL; + +- if (!(a.flags & MAP_ANONYMOUS)) { +- file = fget(a.fd); +- if (!file) +- return -EBADF; +- } +- +- mm = current->mm; +- down_write(&mm->mmap_sem); +- retval = do_mmap_pgoff(file, a.addr, a.len, a.prot, a.flags, ++ return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, + a.offset>>PAGE_SHIFT); +- if (file) +- fput(file); +- +- up_write(&mm->mmap_sem); +- +- return retval; + } + + asmlinkage long sys32_mprotect(unsigned long start, size_t len, +@@ -539,30 +522,6 @@ asmlinkage long sys32_sendfile(int out_f + return ret; + } + +-asmlinkage long sys32_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- struct mm_struct *mm = current->mm; +- unsigned long error; +- struct file *file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- return -EBADF; +- } +- +- down_write(&mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(&mm->mmap_sem); +- +- if (file) +- fput(file); +- return error; +-} +- + asmlinkage long sys32_olduname(struct oldold_utsname __user *name) + { + char *arch = "x86_64"; +--- a/arch/x86/include/asm/syscalls.h ++++ b/arch/x86/include/asm/syscalls.h +@@ -55,8 +55,6 @@ struct sel_arg_struct; + struct oldold_utsname; + struct old_utsname; + +-asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long, +- unsigned long, unsigned long, unsigned long); + asmlinkage int old_mmap(struct mmap_arg_struct __user *); + asmlinkage int old_select(struct sel_arg_struct __user *); + asmlinkage int sys_ipc(uint, int, int, int, void __user *, long); +--- a/arch/x86/include/asm/sys_ia32.h ++++ b/arch/x86/include/asm/sys_ia32.h +@@ -62,9 +62,6 @@ asmlinkage long sys32_pwrite(unsigned in + asmlinkage long sys32_personality(unsigned long); + asmlinkage long sys32_sendfile(int, int, compat_off_t __user *, s32); + +-asmlinkage long sys32_mmap2(unsigned long, unsigned long, unsigned long, +- unsigned long, unsigned long, unsigned long); +- + struct oldold_utsname; + struct old_utsname; + asmlinkage long sys32_olduname(struct oldold_utsname __user *); +--- a/arch/x86/kernel/syscall_table_32.S ++++ b/arch/x86/kernel/syscall_table_32.S +@@ -191,7 +191,7 @@ ENTRY(sys_call_table) + .long sys_ni_syscall /* reserved for streams2 */ + .long ptregs_vfork /* 190 */ + .long sys_getrlimit +- .long sys_mmap2 ++ .long sys_mmap_pgoff + .long sys_truncate64 + .long sys_ftruncate64 + .long sys_stat64 /* 195 */ +--- a/arch/x86/kernel/sys_i386_32.c ++++ b/arch/x86/kernel/sys_i386_32.c +@@ -24,31 +24,6 @@ + + #include + +-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- int error = -EBADF; +- struct file *file = NULL; +- struct mm_struct *mm = current->mm; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(&mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(&mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- + /* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. Linux/i386 didn't use to be able to handle more than +@@ -77,7 +52,7 @@ asmlinkage int old_mmap(struct mmap_arg_ + if (a.offset & ~PAGE_MASK) + goto out; + +- err = sys_mmap2(a.addr, a.len, a.prot, a.flags, ++ err = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, + a.fd, a.offset >> PAGE_SHIFT); + out: + return err; +--- a/arch/x86/kernel/sys_x86_64.c ++++ b/arch/x86/kernel/sys_x86_64.c +@@ -23,26 +23,11 @@ SYSCALL_DEFINE6(mmap, unsigned long, add + unsigned long, fd, unsigned long, off) + { + long error; +- struct file *file; +- + error = -EINVAL; + if (off & ~PAGE_MASK) + goto out; + +- error = -EBADF; +- file = NULL; +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, off >> PAGE_SHIFT); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); ++ error = sys_mmap_pgoff(addr, len, prot, flags, fd, off >> PAGE_SHIFT); + out: + return error; + } +--- a/arch/xtensa/include/asm/syscall.h ++++ b/arch/xtensa/include/asm/syscall.h +@@ -13,8 +13,6 @@ struct sigaction; + asmlinkage long xtensa_execve(char*, char**, char**, struct pt_regs*); + asmlinkage long xtensa_clone(unsigned long, unsigned long, struct pt_regs*); + asmlinkage long xtensa_pipe(int __user *); +-asmlinkage long xtensa_mmap2(unsigned long, unsigned long, unsigned long, +- unsigned long, unsigned long, unsigned long); + asmlinkage long xtensa_ptrace(long, long, long, long); + asmlinkage long xtensa_sigreturn(struct pt_regs*); + asmlinkage long xtensa_rt_sigreturn(struct pt_regs*); +--- a/arch/xtensa/include/asm/unistd.h ++++ b/arch/xtensa/include/asm/unistd.h +@@ -189,7 +189,7 @@ __SYSCALL( 79, sys_fremovexattr, 2) + /* File Map / Shared Memory Operations */ + + #define __NR_mmap2 80 +-__SYSCALL( 80, xtensa_mmap2, 6) ++__SYSCALL( 80, sys_mmap_pgoff, 6) + #define __NR_munmap 81 + __SYSCALL( 81, sys_munmap, 2) + #define __NR_mprotect 82 +--- a/arch/xtensa/kernel/syscall.c ++++ b/arch/xtensa/kernel/syscall.c +@@ -57,31 +57,6 @@ asmlinkage long xtensa_pipe(int __user * + return error; + } + +- +-asmlinkage long xtensa_mmap2(unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, +- unsigned long fd, unsigned long pgoff) +-{ +- int error = -EBADF; +- struct file * file = NULL; +- +- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); +- if (!(flags & MAP_ANONYMOUS)) { +- file = fget(fd); +- if (!file) +- goto out; +- } +- +- down_write(¤t->mm->mmap_sem); +- error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); +- up_write(¤t->mm->mmap_sem); +- +- if (file) +- fput(file); +-out: +- return error; +-} +- + asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg) + { + unsigned long ret; +--- a/include/linux/syscalls.h ++++ b/include/linux/syscalls.h +@@ -879,4 +879,8 @@ int kernel_execve(const char *filename, + asmlinkage long sys_perf_event_open( + struct perf_event_attr __user *attr_uptr, + pid_t pid, int cpu, int group_fd, unsigned long flags); ++ ++asmlinkage long sys_mmap_pgoff(unsigned long addr, unsigned long len, ++ unsigned long prot, unsigned long flags, ++ unsigned long fd, unsigned long pgoff); + #endif +--- a/ipc/shm.c ++++ b/ipc/shm.c +@@ -290,28 +290,28 @@ static unsigned long shm_get_unmapped_ar + unsigned long flags) + { + struct shm_file_data *sfd = shm_file_data(file); +- return get_unmapped_area(sfd->file, addr, len, pgoff, flags); +-} +- +-int is_file_shm_hugepages(struct file *file) +-{ +- int ret = 0; +- +- if (file->f_op == &shm_file_operations) { +- struct shm_file_data *sfd; +- sfd = shm_file_data(file); +- ret = is_file_hugepages(sfd->file); +- } +- return ret; ++ return sfd->file->f_op->get_unmapped_area(sfd->file, addr, len, ++ pgoff, flags); + } + + static const struct file_operations shm_file_operations = { + .mmap = shm_mmap, + .fsync = shm_fsync, + .release = shm_release, ++}; ++ ++static const struct file_operations shm_file_operations_huge = { ++ .mmap = shm_mmap, ++ .fsync = shm_fsync, ++ .release = shm_release, + .get_unmapped_area = shm_get_unmapped_area, + }; + ++int is_file_shm_hugepages(struct file *file) ++{ ++ return file->f_op == &shm_file_operations_huge; ++} ++ + static const struct vm_operations_struct shm_vm_ops = { + .open = shm_open, /* callback for a new vm-area open */ + .close = shm_close, /* callback for when the vm-area is released */ +@@ -889,7 +889,10 @@ long do_shmat(int shmid, char __user *sh + if (!sfd) + goto out_put_dentry; + +- file = alloc_file(path.mnt, path.dentry, f_mode, &shm_file_operations); ++ file = alloc_file(path.mnt, path.dentry, f_mode, ++ is_file_hugepages(shp->shm_file) ? ++ &shm_file_operations_huge : ++ &shm_file_operations); + if (!file) + goto out_free; + ima_counts_get(file); +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -932,13 +932,9 @@ unsigned long do_mmap_pgoff(struct file + if (!(flags & MAP_FIXED)) + addr = round_hint_to_min(addr); + +- error = arch_mmap_check(addr, len, flags); +- if (error) +- return error; +- + /* Careful about overflows.. */ + len = PAGE_ALIGN(len); +- if (!len || len > TASK_SIZE) ++ if (!len) + return -ENOMEM; + + /* offset overflow? */ +@@ -949,24 +945,6 @@ unsigned long do_mmap_pgoff(struct file + if (mm->map_count > sysctl_max_map_count) + return -ENOMEM; + +- if (flags & MAP_HUGETLB) { +- struct user_struct *user = NULL; +- if (file) +- return -EINVAL; +- +- /* +- * VM_NORESERVE is used because the reservations will be +- * taken when vm_ops->mmap() is called +- * A dummy user value is used because we are not locking +- * memory so no accounting is necessary +- */ +- len = ALIGN(len, huge_page_size(&default_hstate)); +- file = hugetlb_file_setup(HUGETLB_ANON_FILE, len, VM_NORESERVE, +- &user, HUGETLB_ANONHUGE_INODE); +- if (IS_ERR(file)) +- return PTR_ERR(file); +- } +- + /* Obtain the address to map to. we verify (or select) it and ensure + * that it represents a valid section of the address space. + */ +@@ -1459,6 +1437,14 @@ get_unmapped_area(struct file *file, uns + unsigned long (*get_area)(struct file *, unsigned long, + unsigned long, unsigned long, unsigned long); + ++ unsigned long error = arch_mmap_check(addr, len, flags); ++ if (error) ++ return error; ++ ++ /* Careful about overflows.. */ ++ if (len > TASK_SIZE) ++ return -ENOMEM; ++ + get_area = current->mm->get_unmapped_area; + if (file && file->f_op && file->f_op->get_unmapped_area) + get_area = file->f_op->get_unmapped_area; +@@ -2003,20 +1989,14 @@ unsigned long do_brk(unsigned long addr, + if (!len) + return addr; + +- if ((addr + len) > TASK_SIZE || (addr + len) < addr) +- return -EINVAL; +- +- if (is_hugepage_only_range(mm, addr, len)) +- return -EINVAL; +- + error = security_file_mmap(NULL, 0, 0, 0, addr, 1); + if (error) + return error; + + flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags; + +- error = arch_mmap_check(addr, len, flags); +- if (error) ++ error = get_unmapped_area(NULL, addr, len, 0, MAP_FIXED); ++ if (error & ~PAGE_MASK) + return error; + + /* +--- a/mm/mremap.c ++++ b/mm/mremap.c +@@ -261,6 +261,137 @@ static unsigned long move_vma(struct vm_ + return new_addr; + } + ++static struct vm_area_struct *vma_to_resize(unsigned long addr, ++ unsigned long old_len, unsigned long new_len, unsigned long *p) ++{ ++ struct mm_struct *mm = current->mm; ++ struct vm_area_struct *vma = find_vma(mm, addr); ++ ++ if (!vma || vma->vm_start > addr) ++ goto Efault; ++ ++ if (is_vm_hugetlb_page(vma)) ++ goto Einval; ++ ++ /* We can't remap across vm area boundaries */ ++ if (old_len > vma->vm_end - addr) ++ goto Efault; ++ ++ if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) { ++ if (new_len > old_len) ++ goto Efault; ++ } ++ ++ if (vma->vm_flags & VM_LOCKED) { ++ unsigned long locked, lock_limit; ++ locked = mm->locked_vm << PAGE_SHIFT; ++ lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; ++ locked += new_len - old_len; ++ if (locked > lock_limit && !capable(CAP_IPC_LOCK)) ++ goto Eagain; ++ } ++ ++ if (!may_expand_vm(mm, (new_len - old_len) >> PAGE_SHIFT)) ++ goto Enomem; ++ ++ if (vma->vm_flags & VM_ACCOUNT) { ++ unsigned long charged = (new_len - old_len) >> PAGE_SHIFT; ++ if (security_vm_enough_memory(charged)) ++ goto Efault; ++ *p = charged; ++ } ++ ++ return vma; ++ ++Efault: /* very odd choice for most of the cases, but... */ ++ return ERR_PTR(-EFAULT); ++Einval: ++ return ERR_PTR(-EINVAL); ++Enomem: ++ return ERR_PTR(-ENOMEM); ++Eagain: ++ return ERR_PTR(-EAGAIN); ++} ++ ++static unsigned long mremap_to(unsigned long addr, ++ unsigned long old_len, unsigned long new_addr, ++ unsigned long new_len) ++{ ++ struct mm_struct *mm = current->mm; ++ struct vm_area_struct *vma; ++ unsigned long ret = -EINVAL; ++ unsigned long charged = 0; ++ unsigned long map_flags; ++ ++ if (new_addr & ~PAGE_MASK) ++ goto out; ++ ++ if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len) ++ goto out; ++ ++ /* Check if the location we're moving into overlaps the ++ * old location at all, and fail if it does. ++ */ ++ if ((new_addr <= addr) && (new_addr+new_len) > addr) ++ goto out; ++ ++ if ((addr <= new_addr) && (addr+old_len) > new_addr) ++ goto out; ++ ++ ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1); ++ if (ret) ++ goto out; ++ ++ ret = do_munmap(mm, new_addr, new_len); ++ if (ret) ++ goto out; ++ ++ if (old_len >= new_len) { ++ ret = do_munmap(mm, addr+new_len, old_len - new_len); ++ if (ret && old_len != new_len) ++ goto out; ++ old_len = new_len; ++ } ++ ++ vma = vma_to_resize(addr, old_len, new_len, &charged); ++ if (IS_ERR(vma)) { ++ ret = PTR_ERR(vma); ++ goto out; ++ } ++ ++ map_flags = MAP_FIXED; ++ if (vma->vm_flags & VM_MAYSHARE) ++ map_flags |= MAP_SHARED; ++ ++ ret = get_unmapped_area(vma->vm_file, new_addr, new_len, vma->vm_pgoff + ++ ((addr - vma->vm_start) >> PAGE_SHIFT), ++ map_flags); ++ if (ret & ~PAGE_MASK) ++ goto out1; ++ ++ ret = move_vma(vma, addr, old_len, new_len, new_addr); ++ if (!(ret & ~PAGE_MASK)) ++ goto out; ++out1: ++ vm_unacct_memory(charged); ++ ++out: ++ return ret; ++} ++ ++static int vma_expandable(struct vm_area_struct *vma, unsigned long delta) ++{ ++ unsigned long end = vma->vm_end + delta; ++ if (end < vma->vm_end) /* overflow */ ++ return 0; ++ if (vma->vm_next && vma->vm_next->vm_start < end) /* intersection */ ++ return 0; ++ if (get_unmapped_area(NULL, vma->vm_start, end - vma->vm_start, ++ 0, MAP_FIXED) & ~PAGE_MASK) ++ return 0; ++ return 1; ++} ++ + /* + * Expand (or shrink) an existing mapping, potentially moving it at the + * same time (controlled by the MREMAP_MAYMOVE flag and available VM space) +@@ -294,32 +425,10 @@ unsigned long do_mremap(unsigned long ad + if (!new_len) + goto out; + +- /* new_addr is only valid if MREMAP_FIXED is specified */ + if (flags & MREMAP_FIXED) { +- if (new_addr & ~PAGE_MASK) +- goto out; +- if (!(flags & MREMAP_MAYMOVE)) +- goto out; +- +- if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len) +- goto out; +- +- /* Check if the location we're moving into overlaps the +- * old location at all, and fail if it does. +- */ +- if ((new_addr <= addr) && (new_addr+new_len) > addr) +- goto out; +- +- if ((addr <= new_addr) && (addr+old_len) > new_addr) +- goto out; +- +- ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1); +- if (ret) +- goto out; +- +- ret = do_munmap(mm, new_addr, new_len); +- if (ret) +- goto out; ++ if (flags & MREMAP_MAYMOVE) ++ ret = mremap_to(addr, old_len, new_addr, new_len); ++ goto out; + } + + /* +@@ -332,60 +441,23 @@ unsigned long do_mremap(unsigned long ad + if (ret && old_len != new_len) + goto out; + ret = addr; +- if (!(flags & MREMAP_FIXED) || (new_addr == addr)) +- goto out; +- old_len = new_len; ++ goto out; + } + + /* +- * Ok, we need to grow.. or relocate. ++ * Ok, we need to grow.. + */ +- ret = -EFAULT; +- vma = find_vma(mm, addr); +- if (!vma || vma->vm_start > addr) ++ vma = vma_to_resize(addr, old_len, new_len, &charged); ++ if (IS_ERR(vma)) { ++ ret = PTR_ERR(vma); + goto out; +- if (is_vm_hugetlb_page(vma)) { +- ret = -EINVAL; +- goto out; +- } +- /* We can't remap across vm area boundaries */ +- if (old_len > vma->vm_end - addr) +- goto out; +- if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) { +- if (new_len > old_len) +- goto out; +- } +- if (vma->vm_flags & VM_LOCKED) { +- unsigned long locked, lock_limit; +- locked = mm->locked_vm << PAGE_SHIFT; +- lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; +- locked += new_len - old_len; +- ret = -EAGAIN; +- if (locked > lock_limit && !capable(CAP_IPC_LOCK)) +- goto out; +- } +- if (!may_expand_vm(mm, (new_len - old_len) >> PAGE_SHIFT)) { +- ret = -ENOMEM; +- goto out; +- } +- +- if (vma->vm_flags & VM_ACCOUNT) { +- charged = (new_len - old_len) >> PAGE_SHIFT; +- if (security_vm_enough_memory(charged)) +- goto out_nc; + } + + /* old_len exactly to the end of the area.. +- * And we're not relocating the area. + */ +- if (old_len == vma->vm_end - addr && +- !((flags & MREMAP_FIXED) && (addr != new_addr)) && +- (old_len != new_len || !(flags & MREMAP_MAYMOVE))) { +- unsigned long max_addr = TASK_SIZE; +- if (vma->vm_next) +- max_addr = vma->vm_next->vm_start; ++ if (old_len == vma->vm_end - addr) { + /* can we just expand the current mapping? */ +- if (max_addr - addr >= new_len) { ++ if (vma_expandable(vma, new_len - old_len)) { + int pages = (new_len - old_len) >> PAGE_SHIFT; + + vma_adjust(vma, vma->vm_start, +@@ -409,28 +481,27 @@ unsigned long do_mremap(unsigned long ad + */ + ret = -ENOMEM; + if (flags & MREMAP_MAYMOVE) { +- if (!(flags & MREMAP_FIXED)) { +- unsigned long map_flags = 0; +- if (vma->vm_flags & VM_MAYSHARE) +- map_flags |= MAP_SHARED; +- +- new_addr = get_unmapped_area(vma->vm_file, 0, new_len, +- vma->vm_pgoff, map_flags); +- if (new_addr & ~PAGE_MASK) { +- ret = new_addr; +- goto out; +- } +- +- ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1); +- if (ret) +- goto out; ++ unsigned long map_flags = 0; ++ if (vma->vm_flags & VM_MAYSHARE) ++ map_flags |= MAP_SHARED; ++ ++ new_addr = get_unmapped_area(vma->vm_file, 0, new_len, ++ vma->vm_pgoff + ++ ((addr - vma->vm_start) >> PAGE_SHIFT), ++ map_flags); ++ if (new_addr & ~PAGE_MASK) { ++ ret = new_addr; ++ goto out; + } ++ ++ ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1); ++ if (ret) ++ goto out; + ret = move_vma(vma, addr, old_len, new_len, new_addr); + } + out: + if (ret & ~PAGE_MASK) + vm_unacct_memory(charged); +-out_nc: + return ret; + } + +--- a/mm/util.c ++++ b/mm/util.c +@@ -4,6 +4,10 @@ + #include + #include + #include ++#include ++#include ++#include ++#include + #include + + #define CREATE_TRACE_POINTS +@@ -268,6 +272,46 @@ int __attribute__((weak)) get_user_pages + } + EXPORT_SYMBOL_GPL(get_user_pages_fast); + ++SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, ++ unsigned long, prot, unsigned long, flags, ++ unsigned long, fd, unsigned long, pgoff) ++{ ++ struct file * file = NULL; ++ unsigned long retval = -EBADF; ++ ++ if (!(flags & MAP_ANONYMOUS)) { ++ if (unlikely(flags & MAP_HUGETLB)) ++ return -EINVAL; ++ file = fget(fd); ++ if (!file) ++ goto out; ++ } else if (flags & MAP_HUGETLB) { ++ struct user_struct *user = NULL; ++ /* ++ * VM_NORESERVE is used because the reservations will be ++ * taken when vm_ops->mmap() is called ++ * A dummy user value is used because we are not locking ++ * memory so no accounting is necessary ++ */ ++ len = ALIGN(len, huge_page_size(&default_hstate)); ++ file = hugetlb_file_setup(HUGETLB_ANON_FILE, len, VM_NORESERVE, ++ &user, HUGETLB_ANONHUGE_INODE); ++ if (IS_ERR(file)) ++ return PTR_ERR(file); ++ } ++ ++ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); ++ ++ down_write(¤t->mm->mmap_sem); ++ retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); ++ up_write(¤t->mm->mmap_sem); ++ ++ if (file) ++ fput(file); ++out: ++ return retval; ++} ++ + /* Tracepoints definitions. */ + EXPORT_TRACEPOINT_SYMBOL(kmalloc); + EXPORT_TRACEPOINT_SYMBOL(kmem_cache_alloc);