diff --git a/posix/tst-mmap-offset.c b/posix/tst-mmap-offset.c
index d139c30..385df28 100644
--- a/posix/tst-mmap-offset.c
+++ b/posix/tst-mmap-offset.c
@@ -1,4 +1,4 @@
-/* BZ #18877 mmap offset test.
+/* BZ #18877 and #21270 mmap offset test.
 
    Copyright (C) 2015-2017 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
@@ -21,18 +21,37 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
 #include <sys/mman.h>
 
-static int
-printmsg (int rc, const char *msg)
+#include <support/check.h>
+
+static int fd;
+static long int page_shift;
+static char fname[] = "tst-mmap-offset-XXXXXX";
+
+static void
+do_prepare (int argc, char **argv)
 {
-  printf ("%s failed: %m\n", msg);
-  return rc;
+  fd = mkstemp64 (fname);
+  if (fd < 0)
+    FAIL_EXIT1 ("mkstemp failed");
+
+  if (unlink (fname))
+    FAIL_EXIT1 ("unlink failed");
+
+  long sz = sysconf(_SC_PAGESIZE);
+  if (sz == -1)
+    sz = 4096L;
+  page_shift = ffs (sz) - 1;
 }
 
+#define PREPARE do_prepare
+
+
 /* Check if negative offsets are handled correctly by mmap.  */
 static int
-do_test (void)
+do_test_bz18877 (void)
 {
   const int prot = PROT_READ | PROT_WRITE;
   const int flags = MAP_SHARED;
@@ -40,22 +59,13 @@ do_test (void)
   const unsigned long offset = 0xace00000;
   const unsigned long size = offset + length;
   void *addr;
-  int fd;
-  char fname[] = "tst-mmap-offset-XXXXXX";
-
-  fd = mkstemp64 (fname);
-  if (fd < 0)
-    return printmsg (1, "mkstemp");
-
-  if (unlink (fname))
-    return printmsg (1, "unlink");
 
   if (ftruncate64 (fd, size))
-    return printmsg (0, "ftruncate64");
+    FAIL_RET ("ftruncate64 failed");
 
   addr = mmap (NULL, length, prot, flags, fd, offset);
   if (MAP_FAILED == addr)
-    return printmsg (1, "mmap");
+    FAIL_RET ("mmap failed");
 
   /* This memcpy is likely to SIGBUS if mmap has messed up with offset.  */
   memcpy (addr, fname, sizeof (fname));
@@ -63,5 +73,45 @@ do_test (void)
   return 0;
 }
 
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+/* Check if invalid offset are handled correctly by mmap.  */
+static int
+do_test_bz21270 (void)
+{
+  /* For architectures with sizeof (off_t) < sizeof (off64_t) mmap is
+     implemented with __SYS_mmap2 syscall and the offset is represented in
+     multiples of page size.  For offset larger than
+     '1 << (page_shift + 8 * sizeof (off_t))' (that is, 1<<44 on system with
+     page size of 4096 bytes) the system call silently truncates the offset.
+     For this case glibc mmap implementation returns EINVAL.  */
+  const int prot = PROT_READ | PROT_WRITE;
+  const int flags = MAP_SHARED;
+  const int64_t offset = 1ULL << (page_shift + 8 * sizeof (uint32_t));
+  const size_t length = 4096;
+
+  void *addr = mmap64 (NULL, length, prot, flags, fd, offset);
+  if (sizeof (off_t) < sizeof (off64_t))
+    {
+      if ((addr != MAP_FAILED) && (errno != EINVAL))
+	FAIL_RET ("mmap succeed");
+    }
+  else
+    {
+      if (addr == MAP_FAILED)
+	FAIL_RET ("mmap failed");
+    }
+
+  return 0;
+}
+
+int
+do_test (void)
+{
+  int ret = 0;
+
+  ret += do_test_bz18877 ();
+  ret += do_test_bz21270 ();
+
+  return ret;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/unix/sysv/linux/aarch64/mmap.c b/sysdeps/unix/sysv/linux/aarch64/mmap.c
deleted file mode 100644
index 1dd18f9..0000000
--- a/sysdeps/unix/sysv/linux/aarch64/mmap.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Copyright (C) 2009-2017 Free Software Foundation, Inc.
-
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <sys/syscall.h>
-#include <sysdep.h>
-#include <unistd.h>
-
-__ptr_t
-__mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
-{
-  return (__ptr_t) INLINE_SYSCALL (mmap, 6, addr, len, prot, flags, fd, offset);
-}
-
-weak_alias (__mmap, mmap)
-weak_alias (__mmap, mmap64)
-weak_alias (__mmap, __mmap64)
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/mmap.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/mmap.c
deleted file mode 100644
index ebeb79b..0000000
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/mmap.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Copyright (C) 2011-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <sysdep.h>
-
-#ifndef MMAP_PAGE_UNIT
-# define MMAP_PAGE_UNIT 4096UL
-#endif
-
-__ptr_t
-__mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
-{
-  if (offset & (MMAP_PAGE_UNIT - 1))
-    {
-      __set_errno (EINVAL);
-      return MAP_FAILED;
-    }
-  return (__ptr_t) INLINE_SYSCALL (mmap2, 6, addr, len, prot, flags, fd,
-                                   offset / MMAP_PAGE_UNIT);
-}
-
-weak_alias (__mmap, mmap)
diff --git a/sysdeps/unix/sysv/linux/hppa/mmap.c b/sysdeps/unix/sysv/linux/hppa/mmap.c
deleted file mode 100644
index 72957cd..0000000
--- a/sysdeps/unix/sysv/linux/hppa/mmap.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/* Copyright (C) 1994-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <errno.h>
-
-/* Map addresses starting near ADDR and extending for LEN bytes.  From
-   OFFSET into the file FD describes according to PROT and FLAGS.  If ADDR
-   is nonzero, it is the desired mapping address.  If the MAP_FIXED bit is
-   set in FLAGS, the mapping will be at ADDR exactly (which must be
-   page-aligned); otherwise the system chooses a convenient nearby address.
-   The return value is the actual mapping address chosen or MAP_FAILED
-   for errors (in which case `errno' is set).  A successful `mmap' call
-   deallocates any previous mapping for the affected region.  */
-
-#include <sysdep.h>
-
-__ptr_t
-__mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
-{
-
-	__ptr_t ret;
-
-	ret = (__ptr_t) INLINE_SYSCALL (mmap, 6, addr, len, prot, flags, fd, offset);
-
-	/* check if it's really a negative number */
-	if(((unsigned long)ret & 0xfffff000) == 0xfffff000)
-		return MAP_FAILED;
-
-	return ret;
-
-}
-
-weak_alias (__mmap, mmap)
diff --git a/sysdeps/unix/sysv/linux/m68k/mmap.S b/sysdeps/unix/sysv/linux/m68k/mmap.S
deleted file mode 100644
index eb8e071..0000000
--- a/sysdeps/unix/sysv/linux/m68k/mmap.S
+++ /dev/null
@@ -1,42 +0,0 @@
-/* Copyright (C) 1996-2017 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-
-	.text
-ENTRY (__mmap)
-
-	move.l #SYS_ify (mmap), %d0	/* System call number in %d0.  */
-
-	lea 4(%sp), %a0			/* Address of args is 1st arg.  */
-	move.l %a0, %d1
-
-	/* Do the system call trap.  */
-	trap #0
-
-	/* Kludge: negative numbers are among the legal return values.
-	   If %d0 is between -4096 and 0 then there was an error.  */
-	cmp.l #-4096, %d0
-	jhi SYSCALL_ERROR_LABEL
-
-	/* Successful; return the syscall's value.  Copy it to %a0 because
-	   mmap is declared to return a pointer.  */
-	move.l %d0, %a0
-	rts
-PSEUDO_END (__mmap)
-
-weak_alias (__mmap, mmap)
diff --git a/sysdeps/unix/sysv/linux/m68k/mmap64.c b/sysdeps/unix/sysv/linux/m68k/mmap64.c
deleted file mode 100644
index 8bf8987..0000000
--- a/sysdeps/unix/sysv/linux/m68k/mmap64.c
+++ /dev/null
@@ -1,5 +0,0 @@
-/* ColdFire and Sun 3 kernels have PAGE_SHIFT set to 13 and expect
-   mmap2 offset to be provided in 8K pages.  Determine the shift
-   dynamically with getpagesize.  */
-#define MMAP2_PAGE_SHIFT -1
-#include <sysdeps/unix/sysv/linux/mmap64.c>
diff --git a/sysdeps/unix/sysv/linux/arm/mmap.c b/sysdeps/unix/sysv/linux/m68k/mmap_internal.h
similarity index 62%
rename from sysdeps/unix/sysv/linux/arm/mmap.c
rename to sysdeps/unix/sysv/linux/m68k/mmap_internal.h
index 4fe8678..bd8bd38 100644
--- a/sysdeps/unix/sysv/linux/arm/mmap.c
+++ b/sysdeps/unix/sysv/linux/m68k/mmap_internal.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2015-2017 Free Software Foundation, Inc.
+/* Common mmap definition for Linux implementation.  Linux/m68k version.
+   Copyright (C) 2017 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -15,4 +16,14 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <sysdeps/unix/sysv/linux/generic/wordsize-32/mmap.c>
+#ifndef MMAP_M68K_INTERNAL_LINUX_H
+#define MMAP_M68K_INTERNAL_LINUX_H
+
+/* ColdFire and Sun 3 kernels have PAGE_SHIFT set to 13 and expect
+   mmap2 offset to be provided in 8K pages.  Determine the shift
+   dynamically with getpagesize.  */
+#define MMAP2_PAGE_SHIFT -1
+
+#include_next <mmap_internal.h>
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/microblaze/mmap.S b/sysdeps/unix/sysv/linux/microblaze/mmap.S
deleted file mode 100644
index 0099993..0000000
--- a/sysdeps/unix/sysv/linux/microblaze/mmap.S
+++ /dev/null
@@ -1,50 +0,0 @@
-/* Copyright (C) 2009-2017 Free Software Foundation, Inc.
-
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-
-#define EINVAL 22
-	.text
-ENTRY (__mmap)
-	addik	r3,r0,-EINVAL
-	andi	r4,r10,0xfff
-	bnei	r4,L(skip)
-	addik	r12,r0,SYS_ify(mmap2)
-	sra	r10,r10
-	sra	r10,r10
-	sra	r10,r10
-	sra	r10,r10
-	sra	r10,r10
-	sra	r10,r10
-	sra	r10,r10
-	sra	r10,r10
-	sra	r10,r10
-	sra	r10,r10
-	sra	r10,r10
-	sra	r10,r10 ;	/* mmap2 takes the offset in pages.  */
-	brki	r14,8
-	nop
-L(skip):
-	addik	r4,r0,-4095
-	cmpu	r4,r4,r3
-	bgei	r4,SYSCALL_ERROR_LABEL
-	rtsd	r15,8
-	nop
-PSEUDO_END (__mmap)
-
-weak_alias (__mmap, mmap)
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/mmap.c b/sysdeps/unix/sysv/linux/mips/mips32/mmap.c
deleted file mode 100644
index f30b1da..0000000
--- a/sysdeps/unix/sysv/linux/mips/mips32/mmap.c
+++ /dev/null
@@ -1 +0,0 @@
-#include <sysdeps/unix/sysv/linux/generic/wordsize-32/mmap.c>
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/mmap.c b/sysdeps/unix/sysv/linux/mips/mips64/n32/mmap_internal.h
similarity index 60%
rename from sysdeps/unix/sysv/linux/mips/mips64/n32/mmap.c
rename to sysdeps/unix/sysv/linux/mips/mips64/n32/mmap_internal.h
index ca0a5b1..4b65559 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/mmap.c
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/mmap_internal.h
@@ -1,4 +1,4 @@
-/* mmap for MIPS n32.
+/* Common mmap definition for Linux implementation.  MIPS n32 version.
    Copyright (C) 2016-2017 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
@@ -16,20 +16,13 @@
    License along with the GNU C Library.  If not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <stdint.h>
-#include <sysdep.h>
+#ifndef MMAP_MIPS_N32_INTERNAL_H
+#define MMAP_MIPS_N32_INTERNAL_H
 
-__ptr_t
-__mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
-{
-  /* To handle negative offsets consistently with other architectures,
-     the offset must be zero-extended to 64-bit.  */
-  uint64_t offset_adj = (uint64_t) (uint32_t) offset;
-  return (__ptr_t) INLINE_SYSCALL (mmap, 6, addr, len, prot, flags, fd,
-				   offset_adj);
-}
+/* To handle negative offsets consistently with other architectures,
+   the offset must be zero-extended to 64-bit.  */
+#define MMAP_ADJUST_OFFSET(offset) (uint64_t) (uint32_t) offset
 
-weak_alias (__mmap, mmap)
+#include_next <mmap_internal.h>
+
+#endif
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list b/sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list
index 7af317f..5f3d047 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/syscalls.list
@@ -4,8 +4,6 @@
 # return value.
 lseek64		-	lseek		i:iii	__lseek64	__libc_lseek64 lseek64 llseek
 
-mmap64		-	mmap		b:aniiii __mmap64	mmap64
-
 readahead	-	readahead	i:iii	__readahead	readahead
 
 prlimit64	EXTRA	prlimit64	i:iipp	prlimit64
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/mmap64.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/mmap64.c
deleted file mode 100644
index 0dbd384..0000000
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/mmap64.c
+++ /dev/null
@@ -1 +0,0 @@
-/* mmap64 is the same as mmap. */
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list b/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list
index 5b5cfc2..2866420 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/syscalls.list
@@ -1,7 +1,5 @@
 # File name	Caller	Syscall name	# args	Strong name	Weak names
 
-mmap		-	mmap		b:aniiii __mmap		mmap __mmap64 mmap64
-
 readahead	-	readahead	i:iii	__readahead	readahead
 
 prlimit		EXTRA	prlimit64	i:iipp	prlimit		prlimit64
diff --git a/sysdeps/unix/sysv/linux/mmap.c b/sysdeps/unix/sysv/linux/mmap.c
new file mode 100644
index 0000000..e587c6a
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mmap.c
@@ -0,0 +1,51 @@
+/* mmap - map files or devices into memory.  Linux version.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sysdep.h>
+#include <stdint.h>
+#include <mmap_internal.h>
+
+#ifndef __OFF_T_MATCHES_OFF64_T
+
+/* An architecture may override this.  */
+# ifndef MMAP_ADJUST_OFFSET
+#  define MMAP_ADJUST_OFFSET(offset) offset
+# endif
+
+void *
+__mmap (void *addr, size_t len, int prot, int flags, int fd, off_t offset)
+{
+  MMAP_CHECK_PAGE_UNIT
+
+  if (offset & MMAP_OFF_LOW_MASK)
+    return (__ptr_t) INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+
+#ifdef __NR_mmap2
+  return (void *) MMAP_CALL (mmap2, addr, len, prot, flags, fd,
+			     offset / (uint32_t) MMAP2_PAGE_UNIT);
+#else
+  return (void *) MMAP_CALL (mmap, addr, len, prot, flags, fd,
+			     MMAP_ADJUST_OFFSET (offset));
+#endif
+}
+weak_alias (__mmap, mmap)
+
+#endif /* __OFF_T_MATCHES_OFF64_T  */
diff --git a/sysdeps/unix/sysv/linux/mmap64.c b/sysdeps/unix/sysv/linux/mmap64.c
index e823600..91c9a81 100644
--- a/sysdeps/unix/sysv/linux/mmap64.c
+++ b/sysdeps/unix/sysv/linux/mmap64.c
@@ -1,4 +1,5 @@
-/* Copyright (C) 1999-2017 Free Software Foundation, Inc.
+/* mmap - map files or devices into memory.  Linux version.
+   Copyright (C) 1999-2017 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Jakub Jelinek <jakub@redhat.com>, 1999.
 
@@ -19,39 +20,41 @@
 #include <errno.h>
 #include <unistd.h>
 #include <sys/mman.h>
-#include <string.h>
-
 #include <sysdep.h>
-#include <sys/syscall.h>
+#include <mmap_internal.h>
 
-/* This is always 12, even on architectures where PAGE_SHIFT != 12.  */
-#ifndef MMAP2_PAGE_SHIFT
-# define MMAP2_PAGE_SHIFT 12
-#endif
-#if MMAP2_PAGE_SHIFT == -1
-static int page_shift;
-#else
-#define page_shift MMAP2_PAGE_SHIFT
-#endif
+/* To avoid silent truncation of offset when using mmap2, do not accept
+   offset larger than 1 << (page_shift + off_t bits).  For archictures with
+   32 bits off_t and page size of 4096 it would be 1^44.  */
+#define MMAP_OFF_HIGH_MASK \
+  ((-(MMAP2_PAGE_UNIT << 1) << (8 * sizeof (off_t) - 1)))
 
+#define MMAP_OFF_MASK (MMAP_OFF_HIGH_MASK | MMAP_OFF_LOW_MASK)
+
+/* An architecture may override this.  */
+#ifndef MMAP_PREPARE
+# define MMAP_PREPARE(addr, len, prot, flags, fd, offset)
+#endif
 
 void *
 __mmap64 (void *addr, size_t len, int prot, int flags, int fd, off64_t offset)
 {
-#if MMAP2_PAGE_SHIFT == -1
-  if (page_shift == 0)
-    {
-      int page_size = __getpagesize ();
-      page_shift = __ffs (page_size) - 1;
-    }
-#endif
-  if (offset & ((1 << page_shift) - 1))
+  MMAP_CHECK_PAGE_UNIT
+
+  if (offset & MMAP_OFF_MASK)
     return (void *) INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
-  void *result;
-  result = (void *)
-    INLINE_SYSCALL (mmap2, 6, addr,
-		    len, prot, flags, fd,
-		    (off_t) (offset >> page_shift));
-  return result;
+
+  MMAP_PREPARE (addr, len, prot, flags, fd, offset);
+#ifdef __NR_mmap2
+  return (void *) MMAP_CALL (mmap2, addr, len, prot, flags, fd,
+			     (off_t) (offset / MMAP2_PAGE_UNIT));
+#else
+  return (void *) MMAP_CALL (mmap, addr, len, prot, flags, fd, offset);
+#endif
 }
 weak_alias (__mmap64, mmap64)
+
+#ifdef __OFF_T_MATCHES_OFF64_T
+weak_alias (__mmap64, mmap)
+weak_alias (__mmap64, __mmap)
+#endif
diff --git a/sysdeps/unix/sysv/linux/mmap_internal.h b/sysdeps/unix/sysv/linux/mmap_internal.h
new file mode 100644
index 0000000..70aeb53
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mmap_internal.h
@@ -0,0 +1,49 @@
+/* Common mmap definition for Linux implementation.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef MMAP_INTERNAL_LINUX_H
+#define MMAP_INTERNAL_LINUX_H 1
+
+/* This is the minimum mmap2 unit size accept by the kernel.  An architecture
+   with multiple minimum page sizes (such as m68k) might define it as -1 and
+   thus it will queried at runtime.  */
+#ifndef MMAP2_PAGE_UNIT
+# define MMAP2_PAGE_UNIT 4096ULL
+#endif
+
+#if MMAP2_PAGE_UNIT == -1
+static int page_unit;
+
+# define MMAP_CHECK_PAGE_UNIT			\
+  if (page_unit == 0)				\
+    page_unit = __getpagesize ();
+#else
+# define page_unit MMAP2_PAGE_UNIT
+# define MMAP_CHECK_PAGE_UNIT
+#endif
+
+/* Do not accept offset not multiple of page size.  */
+#define MMAP_OFF_LOW_MASK  (MMAP2_PAGE_UNIT - 1)
+
+/* An architecture may override this.  */
+#ifndef MMAP_CALL
+# define MMAP_CALL(__nr, __addr, __len, __prot, __flags, __fd, __offset) \
+  INLINE_SYSCALL_CALL (__nr, __addr, __len, __prot, __flags, __fd, __offset)
+#endif
+
+#endif /* MMAP_INTERNAL_LINUX_H  */
diff --git a/sysdeps/unix/sysv/linux/i386/mmap.c b/sysdeps/unix/sysv/linux/s390/mmap_internal.h
similarity index 57%
rename from sysdeps/unix/sysv/linux/i386/mmap.c
rename to sysdeps/unix/sysv/linux/s390/mmap_internal.h
index abf3a26..2b11ce4 100644
--- a/sysdeps/unix/sysv/linux/i386/mmap.c
+++ b/sysdeps/unix/sysv/linux/s390/mmap_internal.h
@@ -1,4 +1,5 @@
-/* Copyright (C) 2015-2017 Free Software Foundation, Inc.
+/* mmap - map files or devices into memory.  Linux/s390 version.
+   Copyright (C) 2017 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -15,22 +16,17 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <sysdep.h>
+#ifndef MMAP_S390_INTERNAL_H
+# define MMAP_S390_INTERNAL_H
 
-#ifndef MMAP_PAGE_UNIT
-# define MMAP_PAGE_UNIT 4096UL
-#endif
+#define MMAP_CALL(__nr, __addr, __len, __prot, __flags, __fd, __offset)	\
+  ({									\
+    long int __args[6] = { (long int) (__addr), (long int) (__len),	\
+			   (long int) (__prot), (long int) (__flags),	\
+			   (long int) (__fd), (long int) (__offset) };	\
+    INLINE_SYSCALL_CALL (__nr, __args);					\
+  })
 
-__ptr_t
-__mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
-{
-  if (offset & (MMAP_PAGE_UNIT - 1))
-    return (__ptr_t) INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
-  return (__ptr_t) INLINE_SYSCALL (mmap2, 6, addr, len, prot, flags, fd,
-                                   offset / MMAP_PAGE_UNIT);
-}
+#include_next <mmap_internal.h>
 
-weak_alias (__mmap, mmap)
+#endif
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/mmap.S b/sysdeps/unix/sysv/linux/s390/s390-32/mmap.S
deleted file mode 100644
index 99b56ed..0000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/mmap.S
+++ /dev/null
@@ -1,74 +0,0 @@
-/* Copyright (C) 2000-2017 Free Software Foundation, Inc.
-   Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-
-#define EINVAL	22
-
-	.text
-ENTRY(__mmap)
-	/* Save registers and setup stack frame.  */
-	stm     %r6,%r15,24(%r15)
-	cfi_offset (%r15, -36)
-	cfi_offset (%r14, -40)
-	cfi_offset (%r13, -44)
-	cfi_offset (%r12, -48)
-	cfi_offset (%r11, -52)
-	cfi_offset (%r10, -56)
-	cfi_offset (%r9, -60)
-	cfi_offset (%r8, -64)
-	cfi_offset (%r7, -68)
-	cfi_offset (%r6, -72)
-	lr      %r1,%r15
-	ahi     %r15,-120               /* buy stack space */
-	cfi_adjust_cfa_offset (120)
-	st      %r1,0(%r15)             /* store back chain */
-
-	/* Store parameters on stack, because mmap2
-	 * takes only one parameter: a pointer to the parameter area
-	 */
-	st      %r6,0x70(%r15)          /* Store 'fd'.      */
-	st      %r5,0x6C(%r15)          /* Store 'flags'.   */
-	st      %r4,0x68(%r15)          /* Store 'prot'.    */
-	st      %r3,0x64(%r15)          /* Store 'length'.  */
-	st      %r2,0x60(%r15)          /* Store 'start'.   */
-	l       %r1,216(%r15)           /* Load offset.     */
-
-	tml     %r1,0x0fff              /* Offset page aligned ?  */
-	lhi     %r2,-EINVAL
-	jnz     1f                      /* No -> EINVAL.  */
-	srl     %r1,12                  /* mmap2 takes the offset in pages.  */
-	st      %r1,0x74(%r15)          /* Store page offset.  */
-	la      %r2,0x60(%r15)          /* Load address of parameter list.  */
-	svc     SYS_ify(mmap2)          /* Do the system call trap.  */
-
-1:	l       %r15,0(%r15)            /* Load back chain.  */
-	cfi_adjust_cfa_offset (-120)
-	lm      %r6,%r15,24(%r15)       /* Load registers.  */
-
-	/* check gpr 2 for error */
-	lhi     %r0,-4096
-	clr     %r2,%r0
-	jnl     SYSCALL_ERROR_LABEL
-
-	/* Successful; return the syscall's value.  */
-	br      %r14
-
-PSEUDO_END (__mmap)
-
-weak_alias (__mmap, mmap)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/mmap64.S b/sysdeps/unix/sysv/linux/s390/s390-32/mmap64.S
deleted file mode 100644
index f182578..0000000
--- a/sysdeps/unix/sysv/linux/s390/s390-32/mmap64.S
+++ /dev/null
@@ -1,81 +0,0 @@
-/* Copyright (C) 2000-2017 Free Software Foundation, Inc.
-   Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-
-#define EINVAL	22
-#define ENOSYS	38
-
-	.text
-ENTRY(__mmap64)
-	/* Save registers and setup stack frame.  */
-	stm	%r6,%r15,24(%r15)
-	cfi_offset (%r15, -36)
-	cfi_offset (%r14, -40)
-	cfi_offset (%r13, -44)
-	cfi_offset (%r12, -48)
-	cfi_offset (%r11, -52)
-	cfi_offset (%r10, -56)
-	cfi_offset (%r9, -60)
-	cfi_offset (%r8, -64)
-	cfi_offset (%r7, -68)
-	cfi_offset (%r6, -72)
-	lr	%r1,%r15
-	ahi	%r15,-120		/* Buy stack space.   */
-	cfi_adjust_cfa_offset (120)
-	st	%r1,0(%r15)		/* Store back chain.  */
-
-	/* Store parameters on stack, because mmap2
-	 * takes only one parameter: a pointer to the parameter area.  */
-	st	%r6,0x70(%r15)		/* Store 'fd'.	    */
-	st	%r5,0x6C(%r15)		/* Store 'flags'.   */
-	st	%r4,0x68(%r15)		/* Store 'prot'.    */
-	st	%r3,0x64(%r15)		/* Store 'length'.  */
-	st	%r2,0x60(%r15)		/* Store 'start'.   */
-
-	lm	%r0,%r1,216(%r15)	/* Load 64 bit offset.	*/
-	tml	%r1,0x0fff		/* Offset page aligned ?  */
-	jnz	2f			/* No -> EINVAL.  */
-	srdl	%r0,12			/* mmap2 takes the offset in pages.  */
-	ltr	%r0,%r0			/* Offset > 2^44 ?  */
-	jnz	2f
-	st	%r1,0x74(%r15)		/* Store page offset.  */
-
-	la	%r2,0x60(%r15)		/* Load address of parameter list.  */
-	svc	SYS_ify(mmap2)		/* Do the system call trap.  */
-
-	l	%r15,0(%r15)		/* Load back chain.  */
-	cfi_adjust_cfa_offset (-120)
-	lm	%r6,%r15,24(%r15)	/* Load registers.  */
-
-	/* Check gpr 2 for error.  */
-	lhi	%r0,-4096
-	clr	%r2,%r0
-	jnl	SYSCALL_ERROR_LABEL
-
-	/* Successful; return the syscall's value.  */
-	br	%r14
-
-2:	lhi	%r2,-EINVAL
-	l	%r15,0(%r15)		/* Load back chain.  */
-	lm	%r6,%r15,24(%r15)	/* Load registers.  */
-	j	SYSCALL_ERROR_LABEL
-
-PSEUDO_END (__mmap64)
-
-weak_alias (__mmap64, mmap64)
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/mmap.S b/sysdeps/unix/sysv/linux/s390/s390-64/mmap.S
deleted file mode 100644
index 06d31bb..0000000
--- a/sysdeps/unix/sysv/linux/s390/s390-64/mmap.S
+++ /dev/null
@@ -1,78 +0,0 @@
-/* Wrapper around mmap system call.  64 bit S/390 version.
-   Copyright (C) 2001-2017 Free Software Foundation, Inc.
-   Contributed by Martin Schwidefsky (schwidefsky@de.ibm.com).
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sysdep.h>
-
-#define EINVAL	22
-
-        .text
-
-ENTRY(__mmap)
-	/* Save registers and setup stack frame.  */
-        stmg    %r6,%r15,48(%r15)
-	cfi_offset (%r15,-40)
-	cfi_offset (%r14,-48)
-	cfi_offset (%r13,-56)
-	cfi_offset (%r12,-64)
-	cfi_offset (%r11,-72)
-	cfi_offset (%r10,-80)
-	cfi_offset (%r9,-88)
-	cfi_offset (%r8,-96)
-	cfi_offset (%r7,-104)
-	cfi_offset (%r6,-112)
-        lgr     %r1,%r15
-        lg      %r0,8(%r15)             /* Load eos.  */
-        aghi    %r15,-208               /* Buy stack space.  */
-	cfi_adjust_cfa_offset (208)
-        stg     %r1,0(%r15)             /* Store back chain.  */
-        stg     %r0,8(%r15)             /* Store eos.  */
-
-        /* Store parameters on stack, because old_mmap
-           takes only one parameter: a pointer to the parameter area.  */
-        mvc     200(8,%r15),368(%r15)   /* Move 'offset'.  */
-        lgfr    %r6,%r6
-        stg     %r6,192(%r15)           /* Store 'fd'.  */
-        lgfr    %r5,%r5
-        stg     %r5,184(%r15)           /* Store 'flags'.  */
-        lgfr    %r4,%r4
-        stg     %r4,176(%r15)           /* Store 'prot'.  */
-        stg     %r3,168(%r15)           /* Store 'length'.  */
-        stg     %r2,160(%r15)           /* Store 'start'.  */
-
-        la      %r2,160(%r15)           /* Load address of parameter list.  */
-        /* Do the system call trap.  */
-        svc     SYS_ify(mmap)
-
-        lg      %r15,0(%r15)            /* Load back chain.  */
-	cfi_adjust_cfa_offset (-208)
-        lmg     %r6,%r15,48(%r15)       /* Load registers.  */
-
-        /* Check gpr 2 for error.  */
-        lghi    %r0,-4096
-        clgr    %r2,%r0
-        jgnl    SYSCALL_ERROR_LABEL
-
-        /* Successful; return the syscall's value.  */
-        br      %r14
-
-PSEUDO_END (__mmap)
-
-weak_alias (__mmap, mmap)
-weak_alias (__mmap, mmap64)
-weak_alias (__mmap, __mmap64)
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/mmap.c b/sysdeps/unix/sysv/linux/wordsize-64/mmap.c
deleted file mode 100644
index a784b62..0000000
--- a/sysdeps/unix/sysv/linux/wordsize-64/mmap.c
+++ /dev/null
@@ -1,40 +0,0 @@
-/* Linux mmap system call.  64-bit version.
-   Copyright (C) 2015-2017 Free Software Foundation, Inc.
-
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public License as
-   published by the Free Software Foundation; either version 2.1 of the
-   License, or (at your option) any later version.
-
-   The GNU C Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <http://www.gnu.org/licenses/>.  */
-
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <errno.h>
-#include <sysdep.h>
-
-/* An architecture may override this.  */
-#ifndef MMAP_PREPARE
-# define MMAP_PREPARE(addr, len, prot, flags, fd, offset)
-#endif
-
-__ptr_t
-__mmap (__ptr_t addr, size_t len, int prot, int flags, int fd, off_t offset)
-{
-  MMAP_PREPARE (addr, len, prot, flags, fd, offset);
-  return (__ptr_t) INLINE_SYSCALL (mmap, 6, addr, len, prot, flags,
-				   fd, offset);
-}
-
-weak_alias (__mmap, mmap)
-weak_alias (__mmap, mmap64)
-weak_alias (__mmap, __mmap64)
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/mmap64.c b/sysdeps/unix/sysv/linux/wordsize-64/mmap64.c
deleted file mode 100644
index 0dbd384..0000000
--- a/sysdeps/unix/sysv/linux/wordsize-64/mmap64.c
+++ /dev/null
@@ -1 +0,0 @@
-/* mmap64 is the same as mmap. */
diff --git a/sysdeps/unix/sysv/linux/wordsize-64/syscalls.list b/sysdeps/unix/sysv/linux/wordsize-64/syscalls.list
index e71cd7b..0c60647 100644
--- a/sysdeps/unix/sysv/linux/wordsize-64/syscalls.list
+++ b/sysdeps/unix/sysv/linux/wordsize-64/syscalls.list
@@ -2,7 +2,6 @@
 
 fstatfs		-	fstatfs		i:ip	__fstatfs	fstatfs fstatfs64 __fstatfs64
 statfs		-	statfs		i:sp	__statfs	statfs statfs64
-mmap		-	mmap		b:aniiii __mmap		mmap __mmap64 mmap64
 readahead	-	readahead	i:iii	__readahead	readahead
 sendfile	-	sendfile	i:iipi	sendfile	sendfile64
 sync_file_range	-	sync_file_range	Ci:iiii	sync_file_range
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/mmap.c b/sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h
similarity index 88%
rename from sysdeps/unix/sysv/linux/x86_64/64/mmap.c
rename to sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h
index 9091b09..06254ef 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/mmap.c
+++ b/sysdeps/unix/sysv/linux/x86_64/64/mmap_internal.h
@@ -17,6 +17,9 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#ifndef MMAP_X86_64_INTERNAL_H
+#define MMAP_X86_64_INTERNAL_H
+
 #include <ldsodefs.h>
 
 /* If the Prefer_MAP_32BIT_EXEC bit is set, try to map executable pages
@@ -26,7 +29,7 @@
       && ((prot) & PROT_EXEC) != 0					\
       && HAS_ARCH_FEATURE (Prefer_MAP_32BIT_EXEC))			\
     {									\
-      __ptr_t ret = (__ptr_t) INLINE_SYSCALL (mmap, 6, (addr), (len),	\
+      void *ret = (void*) INLINE_SYSCALL_CALL (mmap, (addr), (len),	\
 					      (prot),			\
 					      (flags) | MAP_32BIT,	\
 					      (fd), (offset));		\
@@ -34,4 +37,6 @@
 	return ret;							\
     }
 
-#include <sysdeps/unix/sysv/linux/wordsize-64/mmap.c>
+#include_next <mmap_internal.h>
+
+#endif
