--- /dev/null
+From foo@baz Thu Jan 14 11:39:39 PST 2010
+Date: Thu, 14 Jan 2010 11:39:39 -0800
+To: Greg KH <greg@kroah.com>
+From: Al Viro <viro@zeniv.linux.org.uk>
+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 <davem@davemloft.net>
+Cc: Hugh Dickins <hugh.dickins@tiscali.co.uk>
+Cc: Paul Mundt <lethal@linux-sh.org>
+Cc: Russell King <rmk+kernel@arm.linux.org.uk>
+Cc: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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 <asm-generic/mman.h>
++
++#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 <linux/ipc.h>
+ #include <linux/uaccess.h>
+
+-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 <linux/errno.h>
+-#include <linux/fs.h>
+-#include <linux/file.h>
+-#include <linux/mm.h>
+ #include <linux/unistd.h>
+
+-#include <asm/mman.h>
+-#include <asm/uaccess.h>
+-#include <asm/syscalls.h>
+-
+-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 <asm/cacheflush.h>
+ #include <asm/dma.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)
+-{
+- 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 <asm/uaccess.h>
+ #include <asm/segment.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)
+-{
+- 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 <asm/traps.h>
+ #include <asm/unistd.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)
+-{
+- 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 <asm/page.h>
+ #include <asm/unistd.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)
+-{
+- 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 <asm/cacheflush.h>
+ #include <asm/unistd.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)
+-{
+- 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 <asm-generic/mman.h>
++
++#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 <asm/uaccess.h>
+
+-#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 <asm/uaccess.h>
+ #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 <asm/cacheflush.h>
+ #include <asm/cachectl.h>
+
+-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 <asm/syscalls.h>
+
+-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 <linux/module.h>
+ #include <linux/err.h>
+ #include <linux/sched.h>
++#include <linux/hugetlb.h>
++#include <linux/syscalls.h>
++#include <linux/mman.h>
++#include <linux/file.h>
+ #include <asm/uaccess.h>
+
+ #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);