about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTulio Magno Quites Machado Filho <tuliom@linux.ibm.com>2019-11-22 14:23:17 -0300
committerTulio Magno Quites Machado Filho <tuliom@linux.ibm.com>2019-11-22 14:23:17 -0300
commitb32c2757140d192c0b377c073327573f82190b05 (patch)
tree1d577f40aa9bb2387487da32fbf07bd6135086e1
parent22f3c11df1c4dec1ec5310b29f29572805526625 (diff)
parentcedb3e47c68d319607736a820da2d5b3b8ddff6f (diff)
downloadglibc-b32c2757140d192c0b377c073327573f82190b05.tar.gz
glibc-b32c2757140d192c0b377c073327573f82190b05.tar.xz
glibc-b32c2757140d192c0b377c073327573f82190b05.zip
Merge branch release/2.28/master into ibm/2.28/master
-rw-r--r--ChangeLog214
-rw-r--r--NEWS9
-rw-r--r--elf/dl-load.c18
-rw-r--r--elf/dl-open.c8
-rw-r--r--elf/dl-tunables.list5
-rw-r--r--elf/elf.h7
-rw-r--r--include/elf.h2
-rw-r--r--io/Makefile5
-rw-r--r--io/copy_file_range-compat.c160
-rw-r--r--io/copy_file_range.c18
-rw-r--r--io/tst-copy_file_range.c557
-rw-r--r--malloc/Makefile4
-rw-r--r--malloc/arena.c2
-rw-r--r--malloc/malloc.c45
-rw-r--r--malloc/tst-mxfast.c50
-rw-r--r--manual/llio.texi10
-rw-r--r--manual/tunables.texi16
-rw-r--r--nptl/allocatestack.c4
-rw-r--r--nptl/tst-tls1.c90
-rw-r--r--nscd/connections.c3
-rw-r--r--nss/nss_db/db-open.c6
-rw-r--r--posix/tst-mmap-offset.c9
-rw-r--r--string/memmem.c123
-rw-r--r--string/str-two-way.h9
-rw-r--r--string/strcasestr.c37
-rw-r--r--string/strstr.c172
-rw-r--r--support/Makefile2
-rw-r--r--support/support.h1
-rw-r--r--support/xposix_memalign.c (renamed from io/tst-copy_file_range-compat.c)29
-rw-r--r--support/xpthread_attr_setstack.c26
-rw-r--r--support/xthread.h2
-rw-r--r--sysdeps/aarch64/dl-machine.h35
-rw-r--r--sysdeps/aarch64/multiarch/memcpy.c2
-rw-r--r--sysdeps/generic/mmap_info.h16
-rw-r--r--sysdeps/unix/sysv/linux/aarch64/cpu-features.c1
-rw-r--r--sysdeps/unix/sysv/linux/aarch64/cpu-features.h2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/kernel-features.h1
-rw-r--r--sysdeps/unix/sysv/linux/copy_file_range.c21
-rw-r--r--sysdeps/unix/sysv/linux/kernel-features.h4
-rw-r--r--sysdeps/unix/sysv/linux/microblaze/kernel-features.h3
-rw-r--r--sysdeps/unix/sysv/linux/mips/Makefile21
-rw-r--r--sysdeps/unix/sysv/linux/mips/configure41
-rw-r--r--sysdeps/unix/sysv/linux/mips/configure.ac32
-rw-r--r--sysdeps/unix/sysv/linux/mips/mmap_info.h13
-rw-r--r--sysdeps/unix/sysv/linux/mmap64.c9
-rw-r--r--sysdeps/x86/Makefile40
-rw-r--r--sysdeps/x86/tst-cet-legacy-5.c76
-rw-r--r--sysdeps/x86/tst-cet-legacy-5a.c1
-rw-r--r--sysdeps/x86/tst-cet-legacy-5b.c1
-rw-r--r--sysdeps/x86/tst-cet-legacy-6.c76
-rw-r--r--sysdeps/x86/tst-cet-legacy-6a.c1
-rw-r--r--sysdeps/x86/tst-cet-legacy-6b.c1
-rw-r--r--sysdeps/x86/tst-cet-legacy-mod-5.c31
-rw-r--r--sysdeps/x86/tst-cet-legacy-mod-5a.c1
-rw-r--r--sysdeps/x86/tst-cet-legacy-mod-5b.c1
-rw-r--r--sysdeps/x86/tst-cet-legacy-mod-5c.c36
-rw-r--r--sysdeps/x86/tst-cet-legacy-mod-6.c31
-rw-r--r--sysdeps/x86/tst-cet-legacy-mod-6a.c1
-rw-r--r--sysdeps/x86/tst-cet-legacy-mod-6b.c1
-rw-r--r--sysdeps/x86/tst-cet-legacy-mod-6c.c36
-rw-r--r--sysdeps/x86/tst-cet-legacy-mod-6d.c1
61 files changed, 1216 insertions, 963 deletions
diff --git a/ChangeLog b/ChangeLog
index 2c82b3063a..74a337eafc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,217 @@
+2019-02-06  Stefan Liebler  <stli@linux.ibm.com>
+
+	[BZ #23403]
+	* nptl/allocatestack.c (allocate_stack): Align pointer pd for
+	TLS_TCB_AT_TP tls variant.
+	* nptl/tst-tls1.c: Migrate to support/test-driver.c.
+	Add alignment checks.
+	* support/Makefile (libsupport-routines): Add xposix_memalign and
+	xpthread_setstack.
+	* support/support.h: Add xposix_memalign.
+	* support/xthread.h: Add xpthread_attr_setstack.
+	* support/xposix_memalign.c: New File.
+	* support/xpthread_attr_setstack.c: Likewise.
+
+2019-06-18  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #24323]
+	* include/elf.h (DT_1_SUPPORTED_MASK): Include DF_1_PIE.
+	* elf/dl-load.c (_dl_map_object_from_fd): Check for DF_1_PIE and
+	fail when called from dlopen.
+
+2019-07-10  DJ Delorie  <dj@redhat.com>
+	    Sergei Trofimovich <slyfox@inbox.ru>
+
+	[BZ #24696]
+	[BZ #24695]
+	* nss/nss_db/db-open.c (internal_endent): Protect against NULL
+	mappings.
+
+2019-07-01  H.J. Lu  <hongjiu.lu@intel.com>
+
+	[BZ #24259]
+	* elf/dl-open.c (dl_open_worker): Call _dl_open_check after
+	relocation.
+	* sysdeps/x86/Makefile (tests): Add tst-cet-legacy-5a,
+	tst-cet-legacy-5b, tst-cet-legacy-6a and tst-cet-legacy-6b.
+	(modules-names): Add tst-cet-legacy-mod-5a, tst-cet-legacy-mod-5b,
+	tst-cet-legacy-mod-5c, tst-cet-legacy-mod-6a, tst-cet-legacy-mod-6b
+	and tst-cet-legacy-mod-6c.
+	(CFLAGS-tst-cet-legacy-5a.c): New.
+	(CFLAGS-tst-cet-legacy-5b.c): Likewise.
+	(CFLAGS-tst-cet-legacy-mod-5a.c): Likewise.
+	(CFLAGS-tst-cet-legacy-mod-5b.c): Likewise.
+	(CFLAGS-tst-cet-legacy-mod-5c.c): Likewise.
+	(CFLAGS-tst-cet-legacy-6a.c): Likewise.
+	(CFLAGS-tst-cet-legacy-6b.c): Likewise.
+	(CFLAGS-tst-cet-legacy-mod-6a.c): Likewise.
+	(CFLAGS-tst-cet-legacy-mod-6b.c): Likewise.
+	(CFLAGS-tst-cet-legacy-mod-6c.c): Likewise.
+	($(objpfx)tst-cet-legacy-5a): Likewise.
+	($(objpfx)tst-cet-legacy-5a.out): Likewise.
+	($(objpfx)tst-cet-legacy-mod-5a.so): Likewise.
+	($(objpfx)tst-cet-legacy-mod-5b.so): Likewise.
+	($(objpfx)tst-cet-legacy-5b): Likewise.
+	($(objpfx)tst-cet-legacy-5b.out): Likewise.
+	(tst-cet-legacy-5b-ENV): Likewise.
+	($(objpfx)tst-cet-legacy-6a): Likewise.
+	($(objpfx)tst-cet-legacy-6a.out): Likewise.
+	($(objpfx)tst-cet-legacy-mod-6a.so): Likewise.
+	($(objpfx)tst-cet-legacy-mod-6b.so): Likewise.
+	($(objpfx)tst-cet-legacy-6b): Likewise.
+	($(objpfx)tst-cet-legacy-6b.out): Likewise.
+	(tst-cet-legacy-6b-ENV): Likewise.
+	* sysdeps/x86/tst-cet-legacy-5.c: New file.
+	* sysdeps/x86/tst-cet-legacy-5a.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-5b.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-6.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-6a.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-6b.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-5.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-5a.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-5b.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-5c.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-6.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-6a.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-6b.c: Likewise.
+	* sysdeps/x86/tst-cet-legacy-mod-6c.c: Likewise.
+
+2019-08-08  Niklas Hambüchen  <mail@nh2.me>
+	    Carlos O'Donell  <carlos@redhat.com>
+
+	[BZ #24026]
+	* malloc/malloc.c (__malloc_info): Account for top chunk.
+
+2019-08-01  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #24867]
+	* malloc/malloc.c (__malloc_info): Remove unwanted leading
+	whitespace.
+
+2019-08-15  Florian Weimer  <fweimer@redhat.com>
+
+	* malloc/Makefile (tests): Only add tst-mxfast for
+	$(have-tunables).
+	* malloc/tst-mxfast.c: Fix copyright year.
+	(do_test): Fix GNU style issues.  Use TEST_COMPARE instead of
+	assert for checks.
+
+2019-08-09  DJ Delorie  <dj@redhat.com>
+
+	* elf/dl-tunables.list: Add glibc.malloc.mxfast.
+	* manual/tunables.texi: Document it.
+	* malloc/malloc.c (do_set_mxfast): New.
+	(__libc_mallopt): Call it.
+	* malloc/arena.c: Add mxfast tunable.
+	* malloc/tst-mxfast.c: New.
+	* malloc/Makefile: Add it.
+
+2018-12-19  Andreas Schwab  <schwab@suse.de>
+
+	* nscd/connections.c (check_use): Don't abort on invalid len.
+
+2019-05-17  Wilco Dijkstra  <wdijkstr@arm.com>
+
+	* malloc/malloc.c (MAX_TCACHE_COUNT): Increase to UINT16_MAX.
+	(tcache_put): Remove redundant assert.
+	(tcache_get): Remove redundant asserts.
+	(__libc_malloc): Check tcache count is not zero.
+	* manual/tunables.texi (glibc.malloc.tcache_count): Update maximum.
+
+2019-02-04  Joseph Myers  <joseph@codesourcery.com>
+
+	* malloc/malloc.c (tcache_get): Compare tcache->counts[tc_idx]
+	with 0, not tcache->entries[tc_idx].
+
+2019-09-13  Wilco Dijkstra  <wdijkstr@arm.com>
+
+	* string/memmem.c (__memmem): Rewrite to improve performance.
+
+2019-06-12  Wilco Dijkstra  <wdijkstr@arm.com>
+
+	* string/str-two-way.h (two_way_short_needle): Add inline to avoid
+	warning.
+	(two_way_long_needle): Block inlining.
+	* string/strstr.c (strstr2): Add new function.
+	(strstr3): Likewise.
+	(STRSTR): Completely rewrite strstr to improve performance.
+
+2019-09-13  Rajalakshmi Srinivasaraghavan  <raji@linux.vnet.ibm.com>
+
+	* string/memmem.c: Use memcmp for first match.
+
+2019-09-13  Wilco Dijkstra  <wdijkstr@arm.com>
+
+	* string/strcasestr.c (STRCASESTR): Simplify and speedup first match.
+	* string/strstr.c (AVAILABLE): Likewise.
+
+2019-09-06  Wilco Dijkstra  <wdijkstr@arm.com>
+
+	* manual/tunables.texi (glibc.cpu.name): Add ares tunable.
+	* sysdeps/aarch64/multiarch/memcpy.c (__libc_memcpy): Use
+	__memcpy_falkor for ares.
+	* sysdeps/unix/sysv/linux/aarch64/cpu-features.h (IS_ARES):
+	Add new define.
+	* sysdeps/unix/sysv/linux/aarch64/cpu-features.c (cpu_list):
+	Add ares cpu.
+
+2019-07-12  Adhemerval Zanella  <adhemerval.zanella@linaro.org>
+
+	[BZ #24699]
+	* posix/tst-mmap-offset.c: Mention BZ #24699.
+	(do_test_bz21270): Rename to do_test_large_offset and use
+	mmap64_maximum_offset to check for maximum expected offset value.
+	* sysdeps/generic/mmap_info.h: New file.
+	* sysdeps/unix/sysv/linux/mips/mmap_info.h: Likewise.
+	* sysdeps/unix/sysv/linux/mmap64.c (MMAP_OFF_HIGH_MASK): Define iff
+	__NR_mmap2 is used.
+
+2019-07-12  Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+	* sysdeps/aarch64/dl-machine.h (elf_machine_lazy_rel): Check
+	STO_AARCH64_VARIANT_PCS and bind such symbols at load time.
+
+2019-06-13  Szabolcs Nagy  <szabolcs.nagy@arm.com>
+
+	* elf/elf.h (STO_AARCH64_VARIANT_PCS): Define.
+	(DT_AARCH64_VARIANT_PCS): Define.
+
+2019-06-28  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #24744]
+	io: Remove the copy_file_range emulation.
+	* sysdeps/unix/sysv/linux/copy_file_range.c (copy_file_range): Do
+	not define and call copy_file_range_compat.
+	* io/Makefile (tests-static, tests-internal): Do not add
+	tst-copy_file_range-compat.
+	* io/copy_file_range-compat.c: Remove file.
+	* io/copy_file_range.c (copy_file_range): Define as stub.
+	* io/tst-copy_file_range-compat.c: Remove file.
+	* io/tst-copy_file_range.c (xdevfile): Remove variable.
+	(typical_sizes): Update comment.  Remove 16K sizes.
+	(maximum_offset, maximum_offset_errno, maximum_offset_hard_limit):
+	Remove variables.
+	(find_maximum_offset, pipe_as_source, pipe_as_destination)
+	(delayed_write_failure_beginning, delayed_write_failure_end)
+	(cross_device_failure, enospc_failure_1, enospc_failure)
+	(oappend_failure): Remove functions.
+	(tests): Adjust test case list.
+	(do_test): Remove file system search code.  Check for ENOSYS from
+	copy_file_range.  Do not free xdevfile.
+	* manual/llio.texi (Copying File Data): Document ENOSYS error from
+	copy_file_range.  Do not document the EXDEV error, which future
+	kernels may not report.  Update the wording to reflect that
+	further errors are possible.
+	* sysdeps/unix/sysv/linux/alpha/kernel-features.h
+	[__LINUX_KERNEL_VERSION < 0x040D00] (__ASSUME_COPY_FILE_RANGE): Do
+	not undefine.
+	* sysdeps/unix/sysv/linux/kernel-features.h
+	[__LINUX_KERNEL_VERSION >= 0x040500] (__ASSUME_COPY_FILE_RANGE):
+	Remove definition.
+	* sysdeps/unix/sysv/linux/microblaze/kernel-features.h
+	[__LINUX_KERNEL_VERSION < 0x040A00] (__ASSUME_COPY_FILE_RANGE): Do
+	not undefine.
+
 2019-06-20  Dmitry V. Levin  <ldv@altlinux.org>
 	    Florian Weimer  <fweimer@redhat.com>
 
diff --git a/NEWS b/NEWS
index 0f1bff99e8..f249ff690c 100644
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,14 @@ Deprecated and removed features, and other changes affecting compatibility:
   HTM state is saved and restore lazily (the state being saved even when the
   process actually does not use HTM).
 
+* The copy_file_range function fails with ENOSYS if the kernel does not
+  support the system call of the same name.  Previously, user space
+  emulation was performed, but its behavior did not match the kernel
+  behavior, which was deemed too confusing.  Applications which use the
+  copy_file_range function will have to be run on kernels which implement
+  the copy_file_range system call.  Support for most architectures was added
+  in version 4.5 of the mainline Linux kernel.
+
 The following bugs are resolved with this release:
 
   [18035] Fix pldd hang
@@ -60,6 +68,7 @@ The following bugs are resolved with this release:
   [24161] __run_fork_handlers self-deadlocks in malloc/tst-mallocfork2
   [24228] old x86 applications that use legacy libio crash on exit
   [24476] dlfcn: Guard __dlerror_main_freeres with __libc_once_get (once)
+  [24744] io: Remove the copy_file_range emulation.
 
 Security related changes:
 
diff --git a/elf/dl-load.c b/elf/dl-load.c
index c51e4b3718..162a78cb0d 100644
--- a/elf/dl-load.c
+++ b/elf/dl-load.c
@@ -1173,6 +1173,10 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
 	goto call_lose;
       }
 
+    /* dlopen of an executable is not valid because it is not possible
+       to perform proper relocations, handle static TLS, or run the
+       ELF constructors.  For PIE, the check needs the dynamic
+       section, so there is another check below.  */
     if (__glibc_unlikely (type != ET_DYN)
 	&& __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0))
       {
@@ -1209,9 +1213,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
   elf_get_dynamic_info (l, NULL);
 
   /* Make sure we are not dlopen'ing an object that has the
-     DF_1_NOOPEN flag set.  */
-  if (__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN)
-      && (mode & __RTLD_DLOPEN))
+     DF_1_NOOPEN flag set, or a PIE object.  */
+  if ((__glibc_unlikely (l->l_flags_1 & DF_1_NOOPEN)
+       && (mode & __RTLD_DLOPEN))
+      || (__glibc_unlikely (l->l_flags_1 & DF_1_PIE)
+	  && __glibc_unlikely ((mode & __RTLD_OPENEXEC) == 0)))
     {
       /* We are not supposed to load this object.  Free all resources.  */
       _dl_unmap_segments (l);
@@ -1222,7 +1228,11 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
       if (l->l_phdr_allocated)
 	free ((void *) l->l_phdr);
 
-      errstring = N_("shared object cannot be dlopen()ed");
+      if (l->l_flags_1 & DF_1_PIE)
+	errstring
+	  = N_("cannot dynamically load position-independent executable");
+      else
+	errstring = N_("shared object cannot be dlopen()ed");
       goto call_lose;
     }
 
diff --git a/elf/dl-open.c b/elf/dl-open.c
index f6c8ef1043..518a6cad69 100644
--- a/elf/dl-open.c
+++ b/elf/dl-open.c
@@ -292,8 +292,6 @@ dl_open_worker (void *a)
   _dl_debug_state ();
   LIBC_PROBE (map_complete, 3, args->nsid, r, new);
 
-  _dl_open_check (new);
-
   /* Print scope information.  */
   if (__glibc_unlikely (GLRO(dl_debug_mask) & DL_DEBUG_SCOPES))
     _dl_show_scope (new, 0);
@@ -366,6 +364,12 @@ dl_open_worker (void *a)
 	_dl_relocate_object (l, l->l_scope, reloc_mode, 0);
     }
 
+  /* NB: Workaround for [BZ #20839] which doesn't remove the NODELETE
+     object when _dl_open_check throws an exception.  Move it after
+     relocation to avoid leaving the NODELETE object mapped without
+     relocation.  */
+  _dl_open_check (new);
+
   /* If the file is not loaded now as a dependency, add the search
      list of the newly loaded object to the scope.  */
   bool any_tls = false;
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
index 1f8ecb8437..1ff6fcb6f2 100644
--- a/elf/dl-tunables.list
+++ b/elf/dl-tunables.list
@@ -85,6 +85,11 @@ glibc {
     tcache_unsorted_limit {
       type: SIZE_T
     }
+    mxfast {
+      type: SIZE_T
+      minval: 0
+      security_level: SXID_IGNORE
+    }
   }
   tune {
     hwcap_mask {
diff --git a/elf/elf.h b/elf/elf.h
index 7e2b072a7f..74f7f479ce 100644
--- a/elf/elf.h
+++ b/elf/elf.h
@@ -2847,6 +2847,13 @@ enum
 #define R_AARCH64_TLSDESC      1031	/* TLS Descriptor.  */
 #define R_AARCH64_IRELATIVE	1032	/* STT_GNU_IFUNC relocation.  */
 
+/* AArch64 specific values for the Dyn d_tag field.  */
+#define DT_AARCH64_VARIANT_PCS	(DT_LOPROC + 5)
+#define DT_AARCH64_NUM		6
+
+/* AArch64 specific values for the st_other field.  */
+#define STO_AARCH64_VARIANT_PCS 0x80
+
 /* ARM relocs.  */
 
 #define R_ARM_NONE		0	/* No reloc */
diff --git a/include/elf.h b/include/elf.h
index ab76aafb1e..14ed67ff67 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -23,7 +23,7 @@
 # endif
 # define DT_1_SUPPORTED_MASK \
    (DF_1_NOW | DF_1_NODELETE | DF_1_INITFIRST | DF_1_NOOPEN \
-    | DF_1_ORIGIN | DF_1_NODEFLIB)
+    | DF_1_ORIGIN | DF_1_NODEFLIB | DF_1_PIE)
 
 #endif /* !_ISOMAC */
 #endif /* elf.h */
diff --git a/io/Makefile b/io/Makefile
index ec5c6d7a2f..043f4b80ea 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -73,11 +73,6 @@ tests		:= test-utime test-stat test-stat2 test-lfs tst-getcwd \
 		   tst-fts tst-fts-lfs tst-open-tmpfile \
 		   tst-copy_file_range tst-getcwd-abspath \
 
-# This test includes the compat implementation of copy_file_range,
-# which uses internal, unexported libc functions.
-tests-static += tst-copy_file_range-compat
-tests-internal += tst-copy_file_range-compat
-
 # Likewise for statx, but we do not need static linking here.
 tests-internal += tst-statx
 
diff --git a/io/copy_file_range-compat.c b/io/copy_file_range-compat.c
deleted file mode 100644
index 4ab22cad19..0000000000
--- a/io/copy_file_range-compat.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/* Emulation of copy_file_range.
-   Copyright (C) 2017-2018 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/>.  */
-
-/* The following macros should be defined before including this
-   file:
-
-   COPY_FILE_RANGE_DECL   Declaration specifiers for the function below.
-   COPY_FILE_RANGE        Name of the function to define.  */
-
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-COPY_FILE_RANGE_DECL
-ssize_t
-COPY_FILE_RANGE (int infd, __off64_t *pinoff,
-                 int outfd, __off64_t *poutoff,
-                 size_t length, unsigned int flags)
-{
-  if (flags != 0)
-    {
-      __set_errno (EINVAL);
-      return -1;
-    }
-
-  {
-    struct stat64 instat;
-    struct stat64 outstat;
-    if (fstat64 (infd, &instat) != 0 || fstat64 (outfd, &outstat) != 0)
-      return -1;
-    if (S_ISDIR (instat.st_mode) || S_ISDIR (outstat.st_mode))
-      {
-        __set_errno (EISDIR);
-        return -1;
-      }
-    if (!S_ISREG (instat.st_mode) || !S_ISREG (outstat.st_mode))
-      {
-        /* We need a regular input file so that the we can seek
-           backwards in case of a write failure.  */
-        __set_errno (EINVAL);
-        return -1;
-      }
-    if (instat.st_dev != outstat.st_dev)
-      {
-        /* Cross-device copies are not supported.  */
-        __set_errno (EXDEV);
-        return -1;
-      }
-  }
-
-  /* The output descriptor must not have O_APPEND set.  */
-  {
-    int flags = __fcntl (outfd, F_GETFL);
-    if (flags & O_APPEND)
-      {
-        __set_errno (EBADF);
-        return -1;
-      }
-  }
-
-  /* Avoid an overflow in the result.  */
-  if (length > SSIZE_MAX)
-    length = SSIZE_MAX;
-
-  /* Main copying loop.  The buffer size is arbitrary and is a
-     trade-off between stack size consumption, cache usage, and
-     amortization of system call overhead.  */
-  size_t copied = 0;
-  char buf[8192];
-  while (length > 0)
-    {
-      size_t to_read = length;
-      if (to_read > sizeof (buf))
-        to_read = sizeof (buf);
-
-      /* Fill the buffer.  */
-      ssize_t read_count;
-      if (pinoff == NULL)
-        read_count = read (infd, buf, to_read);
-      else
-        read_count = __libc_pread64 (infd, buf, to_read, *pinoff);
-      if (read_count == 0)
-        /* End of file reached prematurely.  */
-        return copied;
-      if (read_count < 0)
-        {
-          if (copied > 0)
-            /* Report the number of bytes copied so far.  */
-            return copied;
-          return -1;
-        }
-      if (pinoff != NULL)
-        *pinoff += read_count;
-
-      /* Write the buffer part which was read to the destination.  */
-      char *end = buf + read_count;
-      for (char *p = buf; p < end; )
-        {
-          ssize_t write_count;
-          if (poutoff == NULL)
-            write_count = write (outfd, p, end - p);
-          else
-            write_count = __libc_pwrite64 (outfd, p, end - p, *poutoff);
-          if (write_count < 0)
-            {
-              /* Adjust the input read position to match what we have
-                 written, so that the caller can pick up after the
-                 error.  */
-              size_t written = p - buf;
-              /* NB: This needs to be signed so that we can form the
-                 negative value below.  */
-              ssize_t overread = read_count - written;
-              if (pinoff == NULL)
-                {
-                  if (overread > 0)
-                    {
-                      /* We are on an error recovery path, so we
-                         cannot deal with failure here.  */
-                      int save_errno = errno;
-                      (void) __libc_lseek64 (infd, -overread, SEEK_CUR);
-                      __set_errno (save_errno);
-                    }
-                }
-              else /* pinoff != NULL */
-                *pinoff -= overread;
-
-              if (copied + written > 0)
-                /* Report the number of bytes copied so far.  */
-                return copied + written;
-              return -1;
-            }
-          p += write_count;
-          if (poutoff != NULL)
-            *poutoff += write_count;
-        } /* Write loop.  */
-
-      copied += read_count;
-      length -= read_count;
-    }
-  return copied;
-}
diff --git a/io/copy_file_range.c b/io/copy_file_range.c
index 98bff8bd26..59fb979773 100644
--- a/io/copy_file_range.c
+++ b/io/copy_file_range.c
@@ -1,5 +1,5 @@
-/* Generic implementation of copy_file_range.
-   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+/* Stub implementation of copy_file_range.
+   Copyright (C) 2017-2019 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
@@ -16,7 +16,15 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#define COPY_FILE_RANGE_DECL
-#define COPY_FILE_RANGE copy_file_range
+#include <errno.h>
+#include <unistd.h>
 
-#include <io/copy_file_range-compat.c>
+ssize_t
+copy_file_range (int infd, __off64_t *pinoff,
+                 int outfd, __off64_t *poutoff,
+                 size_t length, unsigned int flags)
+{
+  __set_errno (ENOSYS);
+  return -1;
+}
+stub_warning (copy_file_range)
diff --git a/io/tst-copy_file_range.c b/io/tst-copy_file_range.c
index 3d531a1937..a9237cb384 100644
--- a/io/tst-copy_file_range.c
+++ b/io/tst-copy_file_range.c
@@ -1,5 +1,5 @@
 /* Tests for copy_file_range.
-   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+   Copyright (C) 2017-2019 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
@@ -20,22 +20,15 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <inttypes.h>
-#include <libgen.h>
-#include <poll.h>
-#include <sched.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <support/check.h>
-#include <support/namespace.h>
 #include <support/support.h>
 #include <support/temp_file.h>
 #include <support/test-driver.h>
 #include <support/xunistd.h>
-#ifdef CLONE_NEWNS
-# include <sys/mount.h>
-#endif
 
 /* Boolean flags which indicate whether to use pointers with explicit
    output flags.  */
@@ -49,10 +42,6 @@ static int infd;
 static char *outfile;
 static int outfd;
 
-/* Like the above, but on a different file system.  xdevfile can be
-   NULL if no suitable file system has been found.  */
-static char *xdevfile;
-
 /* Input and output offsets.  Set according to do_inoff and do_outoff
    before the test.  The offsets themselves are always set to
    zero.  */
@@ -61,13 +50,10 @@ static off64_t *pinoff;
 static off64_t outoff;
 static off64_t *poutoff;
 
-/* These are a collection of copy sizes used in tests.  The selection
-   takes into account that the fallback implementation uses an
-   internal buffer of 8192 bytes.  */
+/* These are a collection of copy sizes used in tests.    */
 enum { maximum_size = 99999 };
 static const int typical_sizes[] =
-  { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, 16383, 16384, 16385,
-    maximum_size };
+  { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, maximum_size };
 
 /* The random contents of this array can be used as a pattern to check
    for correct write operations.  */
@@ -76,101 +62,6 @@ static unsigned char random_data[maximum_size];
 /* The size chosen by the test harness.  */
 static int current_size;
 
-/* Maximum writable file offset.  Updated by find_maximum_offset
-   below.  */
-static off64_t maximum_offset;
-
-/* Error code when crossing the offset.  */
-static int maximum_offset_errno;
-
-/* If true: Writes which cross the limit will fail.  If false: Writes
-   which cross the limit will result in a partial write.  */
-static bool maximum_offset_hard_limit;
-
-/* Fills maximum_offset etc. above.  Truncates outfd as a side
-   effect.  */
-static void
-find_maximum_offset (void)
-{
-  xftruncate (outfd, 0);
-  if (maximum_offset != 0)
-    return;
-
-  uint64_t upper = -1;
-  upper >>= 1;                  /* Maximum of off64_t.  */
-  TEST_VERIFY ((off64_t) upper > 0);
-  TEST_VERIFY ((off64_t) (upper + 1) < 0);
-  if (lseek64 (outfd, upper, SEEK_SET) >= 0)
-    {
-      if (write (outfd, "", 1) == 1)
-        FAIL_EXIT1 ("created a file larger than the off64_t range");
-    }
-
-  uint64_t lower = 1024 * 1024; /* A reasonable minimum file size.  */
-  /* Loop invariant: writing at lower succeeds, writing at upper fails.  */
-  while (lower + 1 < upper)
-    {
-      uint64_t middle = (lower + upper) / 2;
-      if (test_verbose > 0)
-        printf ("info: %s: remaining test range %" PRIu64 " .. %" PRIu64
-                ", probe at %" PRIu64 "\n", __func__, lower, upper, middle);
-      xftruncate (outfd, 0);
-      if (lseek64 (outfd, middle, SEEK_SET) >= 0
-          && write (outfd, "", 1) == 1)
-        lower = middle;
-      else
-        upper = middle;
-    }
-  TEST_VERIFY (lower + 1 == upper);
-  maximum_offset = lower;
-  printf ("info: maximum writable file offset: %" PRIu64 " (%" PRIx64 ")\n",
-          lower, lower);
-
-  /* Check that writing at the valid offset actually works.  */
-  xftruncate (outfd, 0);
-  xlseek (outfd, lower, SEEK_SET);
-  TEST_COMPARE (write (outfd, "", 1), 1);
-
-  /* Cross the boundary with a two-byte write.  This can either result
-     in a short write, or a failure.  */
-  xlseek (outfd, lower, SEEK_SET);
-  ssize_t ret = write (outfd, " ", 2);
-  if (ret < 0)
-    {
-      maximum_offset_errno = errno;
-      maximum_offset_hard_limit = true;
-    }
-  else
-    maximum_offset_hard_limit = false;
-
-  /* Check that writing at the next offset actually fails.  This also
-     obtains the expected errno value.  */
-  xftruncate (outfd, 0);
-  const char *action;
-  if (lseek64 (outfd, lower + 1, SEEK_SET) != 0)
-    {
-      if (write (outfd, "", 1) != -1)
-        FAIL_EXIT1 ("write to impossible offset %" PRIu64 " succeeded",
-                    lower + 1);
-      action = "writing";
-      int errno_copy = errno;
-      if (maximum_offset_hard_limit)
-        TEST_COMPARE (errno_copy, maximum_offset_errno);
-      else
-        maximum_offset_errno = errno_copy;
-    }
-  else
-    {
-      action = "seeking";
-      maximum_offset_errno = errno;
-    }
-  printf ("info: %s out of range fails with %m (%d)\n",
-          action, maximum_offset_errno);
-
-  xftruncate (outfd, 0);
-  xlseek (outfd, 0, SEEK_SET);
-}
-
 /* Perform a copy of a file.  */
 static void
 simple_file_copy (void)
@@ -247,390 +138,6 @@ simple_file_copy (void)
   free (bytes);
 }
 
-/* Test that reading from a pipe willfails.  */
-static void
-pipe_as_source (void)
-{
-  int pipefds[2];
-  xpipe (pipefds);
-
-  for (int length = 0; length < 2; ++length)
-    {
-      if (test_verbose > 0)
-        printf ("info: %s: length=%d\n", __func__, length);
-
-      /* Make sure that there is something to copy in the pipe.  */
-      xwrite (pipefds[1], "@", 1);
-
-      TEST_COMPARE (copy_file_range (pipefds[0], pinoff, outfd, poutoff,
-                                     length, 0), -1);
-      /* Linux 4.10 and later return EINVAL.  Older kernels return
-         EXDEV.  */
-      TEST_VERIFY (errno == EINVAL || errno == EXDEV);
-      TEST_COMPARE (inoff, 0);
-      TEST_COMPARE (outoff, 0);
-      TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 0);
-
-      /* Make sure that nothing was read.  */
-      char buf = 'A';
-      TEST_COMPARE (read (pipefds[0], &buf, 1), 1);
-      TEST_COMPARE (buf, '@');
-    }
-
-  xclose (pipefds[0]);
-  xclose (pipefds[1]);
-}
-
-/* Test that writing to a pipe fails.  */
-static void
-pipe_as_destination (void)
-{
-  /* Make sure that there is something to read in the input file.  */
-  xwrite (infd, "abc", 3);
-  xlseek (infd, 0, SEEK_SET);
-
-  int pipefds[2];
-  xpipe (pipefds);
-
-  for (int length = 0; length < 2; ++length)
-    {
-      if (test_verbose > 0)
-        printf ("info: %s: length=%d\n", __func__, length);
-
-      TEST_COMPARE (copy_file_range (infd, pinoff, pipefds[1], poutoff,
-                                     length, 0), -1);
-      /* Linux 4.10 and later return EINVAL.  Older kernels return
-         EXDEV.  */
-      TEST_VERIFY (errno == EINVAL || errno == EXDEV);
-      TEST_COMPARE (inoff, 0);
-      TEST_COMPARE (outoff, 0);
-      TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
-
-      /* Make sure that nothing was written.  */
-      struct pollfd pollfd = { .fd = pipefds[0], .events = POLLIN, };
-      TEST_COMPARE (poll (&pollfd, 1, 0), 0);
-    }
-
-  xclose (pipefds[0]);
-  xclose (pipefds[1]);
-}
-
-/* Test a write failure after (potentially) writing some bytes.
-   Failure occurs near the start of the buffer.  */
-static void
-delayed_write_failure_beginning (void)
-{
-  /* We need to write something to provoke the error.  */
-  if (current_size == 0)
-    return;
-  xwrite (infd, random_data, sizeof (random_data));
-  xlseek (infd, 0, SEEK_SET);
-
-  /* Write failure near the start.  The actual error code varies among
-     file systems.  */
-  find_maximum_offset ();
-  off64_t where = maximum_offset;
-
-  if (current_size == 1)
-    ++where;
-  outoff = where;
-  if (do_outoff)
-    xlseek (outfd, 1, SEEK_SET);
-  else
-    xlseek (outfd, where, SEEK_SET);
-  if (maximum_offset_hard_limit || where > maximum_offset)
-    {
-      TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
-                                     sizeof (random_data), 0), -1);
-      TEST_COMPARE (errno, maximum_offset_errno);
-      TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
-      TEST_COMPARE (inoff, 0);
-      if (do_outoff)
-        TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1);
-      else
-        TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where);
-      TEST_COMPARE (outoff, where);
-      struct stat64 st;
-      xfstat (outfd, &st);
-      TEST_COMPARE (st.st_size, 0);
-    }
-  else
-    {
-      /* The offset is not a hard limit.  This means we write one
-         byte.  */
-      TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
-                                     sizeof (random_data), 0), 1);
-      if (do_inoff)
-        {
-          TEST_COMPARE (inoff, 1);
-          TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
-        }
-      else
-        {
-          TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 1);
-          TEST_COMPARE (inoff, 0);
-        }
-      if (do_outoff)
-        {
-          TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), 1);
-          TEST_COMPARE (outoff, where + 1);
-        }
-      else
-        {
-          TEST_COMPARE (xlseek (outfd, 0, SEEK_CUR), where + 1);
-          TEST_COMPARE (outoff, where);
-        }
-      struct stat64 st;
-      xfstat (outfd, &st);
-      TEST_COMPARE (st.st_size, where + 1);
-    }
-}
-
-/* Test a write failure after (potentially) writing some bytes.
-   Failure occurs near the end of the buffer.  */
-static void
-delayed_write_failure_end (void)
-{
-  if (current_size <= 1)
-    /* This would be same as the first test because there is not
-       enough data to write to make a difference.  */
-    return;
-  xwrite (infd, random_data, sizeof (random_data));
-  xlseek (infd, 0, SEEK_SET);
-
-  find_maximum_offset ();
-  off64_t where = maximum_offset - current_size + 1;
-  if (current_size == sizeof (random_data))
-    /* Otherwise we do not reach the non-writable byte.  */
-    ++where;
-  outoff = where;
-  if (do_outoff)
-    xlseek (outfd, 1, SEEK_SET);
-  else
-    xlseek (outfd, where, SEEK_SET);
-  ssize_t ret = copy_file_range (infd, pinoff, outfd, poutoff,
-                                 sizeof (random_data), 0);
-  if (ret < 0)
-    {
-      TEST_COMPARE (ret, -1);
-      TEST_COMPARE (errno, maximum_offset_errno);
-      struct stat64 st;
-      xfstat (outfd, &st);
-      TEST_COMPARE (st.st_size, 0);
-    }
-  else
-    {
-      /* The first copy succeeded.  This happens in the emulation
-         because the internal buffer of limited size does not
-         necessarily cross the off64_t boundary on the first write
-         operation.  */
-      if (test_verbose > 0)
-        printf ("info:   copy_file_range (%zu) returned %zd\n",
-                sizeof (random_data), ret);
-      TEST_VERIFY (ret > 0);
-      TEST_VERIFY (ret < maximum_size);
-      struct stat64 st;
-      xfstat (outfd, &st);
-      TEST_COMPARE (st.st_size, where + ret);
-      if (do_inoff)
-        {
-          TEST_COMPARE (inoff, ret);
-          TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
-        }
-      else
-          TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), ret);
-
-      char *buffer = xmalloc (ret);
-      TEST_COMPARE (pread64 (outfd, buffer, ret, where), ret);
-      TEST_VERIFY (memcmp (buffer, random_data, ret) == 0);
-      free (buffer);
-
-      /* The second copy fails.  */
-      TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
-                                     sizeof (random_data), 0), -1);
-      TEST_COMPARE (errno, maximum_offset_errno);
-    }
-}
-
-/* Test a write failure across devices.  */
-static void
-cross_device_failure (void)
-{
-  if (xdevfile == NULL)
-    /* Subtest not supported due to missing cross-device file.  */
-    return;
-
-  /* We need something to write.  */
-  xwrite (infd, random_data, sizeof (random_data));
-  xlseek (infd, 0, SEEK_SET);
-
-  int xdevfd = xopen (xdevfile, O_RDWR | O_LARGEFILE, 0);
-  TEST_COMPARE (copy_file_range (infd, pinoff, xdevfd, poutoff,
-                                 current_size, 0), -1);
-  TEST_COMPARE (errno, EXDEV);
-  TEST_COMPARE (xlseek (infd, 0, SEEK_CUR), 0);
-  struct stat64 st;
-  xfstat (xdevfd, &st);
-  TEST_COMPARE (st.st_size, 0);
-
-  xclose (xdevfd);
-}
-
-/* Try to exercise ENOSPC behavior with a tempfs file system (so that
-   we do not have to fill up a regular file system to get the error).
-   This function runs in a subprocess, so that we do not change the
-   mount namespace of the actual test process.  */
-static void
-enospc_failure_1 (void *closure)
-{
-#ifdef CLONE_NEWNS
-  support_become_root ();
-
-  /* Make sure that we do not alter the file system mounts of the
-     parents.  */
-  if (! support_enter_mount_namespace ())
-    {
-      printf ("warning: ENOSPC test skipped\n");
-      return;
-    }
-
-  char *mountpoint = closure;
-  if (mount ("none", mountpoint, "tmpfs", MS_NODEV | MS_NOEXEC,
-             "size=500k") != 0)
-    {
-      printf ("warning: could not mount tmpfs at %s: %m\n", mountpoint);
-      return;
-    }
-
-  /* The source file must reside on the same file system.  */
-  char *intmpfsfile = xasprintf ("%s/%s", mountpoint, "in");
-  int intmpfsfd = xopen (intmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600);
-  xwrite (intmpfsfd, random_data, sizeof (random_data));
-  xlseek (intmpfsfd, 1, SEEK_SET);
-  inoff = 1;
-
-  char *outtmpfsfile = xasprintf ("%s/%s", mountpoint, "out");
-  int outtmpfsfd = xopen (outtmpfsfile, O_RDWR | O_CREAT | O_LARGEFILE, 0600);
-
-  /* Fill the file with data until ENOSPC is reached.  */
-  while (true)
-    {
-      ssize_t ret = write (outtmpfsfd, random_data, sizeof (random_data));
-      if (ret < 0 && errno != ENOSPC)
-        FAIL_EXIT1 ("write to %s: %m", outtmpfsfile);
-      if (ret < sizeof (random_data))
-        break;
-    }
-  TEST_COMPARE (write (outtmpfsfd, "", 1), -1);
-  TEST_COMPARE (errno, ENOSPC);
-  off64_t maxsize = xlseek (outtmpfsfd, 0, SEEK_CUR);
-  TEST_VERIFY_EXIT (maxsize > sizeof (random_data));
-
-  /* Constructed the expected file contents.  */
-  char *expected = xmalloc (maxsize);
-  TEST_COMPARE (pread64 (outtmpfsfd, expected, maxsize, 0), maxsize);
-  /* Go back a little, so some bytes can be written.  */
-  enum { offset = 20000 };
-  TEST_VERIFY_EXIT (offset < maxsize);
-  TEST_VERIFY_EXIT (offset < sizeof (random_data));
-  memcpy (expected + maxsize - offset, random_data + 1, offset);
-
-  if (do_outoff)
-    {
-      outoff = maxsize - offset;
-      xlseek (outtmpfsfd, 2, SEEK_SET);
-    }
-  else
-    xlseek (outtmpfsfd, -offset, SEEK_CUR);
-
-  /* First call is expected to succeed because we made room for some
-     bytes.  */
-  TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff,
-                                 maximum_size, 0), offset);
-  if (do_inoff)
-    {
-      TEST_COMPARE (inoff, 1 + offset);
-      TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1);
-    }
-  else
-      TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset);
-  if (do_outoff)
-    {
-      TEST_COMPARE (outoff, maxsize);
-      TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2);
-    }
-  else
-    TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize);
-  struct stat64 st;
-  xfstat (outtmpfsfd, &st);
-  TEST_COMPARE (st.st_size, maxsize);
-  char *actual = xmalloc (st.st_size);
-  TEST_COMPARE (pread64 (outtmpfsfd, actual, st.st_size, 0), st.st_size);
-  TEST_VERIFY (memcmp (expected, actual, maxsize) == 0);
-
-  /* Second call should fail with ENOSPC.  */
-  TEST_COMPARE (copy_file_range (intmpfsfd, pinoff, outtmpfsfd, poutoff,
-                                 maximum_size, 0), -1);
-  TEST_COMPARE (errno, ENOSPC);
-
-  /* Offsets should be unchanged.  */
-  if (do_inoff)
-    {
-      TEST_COMPARE (inoff, 1 + offset);
-      TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1);
-    }
-  else
-    TEST_COMPARE (xlseek (intmpfsfd, 0, SEEK_CUR), 1 + offset);
-  if (do_outoff)
-    {
-      TEST_COMPARE (outoff, maxsize);
-      TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), 2);
-    }
-  else
-    TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_CUR), maxsize);
-  TEST_COMPARE (xlseek (outtmpfsfd, 0, SEEK_END), maxsize);
-  TEST_COMPARE (pread64 (outtmpfsfd, actual, maxsize, 0), maxsize);
-  TEST_VERIFY (memcmp (expected, actual, maxsize) == 0);
-
-  free (actual);
-  free (expected);
-
-  xclose (intmpfsfd);
-  xclose (outtmpfsfd);
-  free (intmpfsfile);
-  free (outtmpfsfile);
-
-#else /* !CLONE_NEWNS */
-  puts ("warning: ENOSPC test skipped (no mount namespaces)");
-#endif
-}
-
-/* Call enospc_failure_1 in a subprocess.  */
-static void
-enospc_failure (void)
-{
-  char *mountpoint
-    = support_create_temp_directory ("tst-copy_file_range-enospc-");
-  support_isolate_in_subprocess (enospc_failure_1, mountpoint);
-  free (mountpoint);
-}
-
-/* The target file descriptor must have O_APPEND enabled.  */
-static void
-oappend_failure (void)
-{
-  /* Add data, to make sure we do not fail because there is
-     insufficient input data.  */
-  xwrite (infd, random_data, current_size);
-  xlseek (infd, 0, SEEK_SET);
-
-  xclose (outfd);
-  outfd = xopen (outfile, O_RDWR | O_APPEND, 0);
-  TEST_COMPARE (copy_file_range (infd, pinoff, outfd, poutoff,
-                                 current_size, 0), -1);
-  TEST_COMPARE (errno, EBADF);
-}
-
 /* Test that a short input file results in a shortened copy.  */
 static void
 short_copy (void)
@@ -721,14 +228,6 @@ struct test_case
 static struct test_case tests[] =
   {
     { "simple_file_copy", simple_file_copy, .sizes = true },
-    { "pipe_as_source", pipe_as_source, },
-    { "pipe_as_destination", pipe_as_destination, },
-    { "delayed_write_failure_beginning", delayed_write_failure_beginning,
-      .sizes = true },
-    { "delayed_write_failure_end", delayed_write_failure_end, .sizes = true },
-    { "cross_device_failure", cross_device_failure, .sizes = true },
-    { "enospc_failure", enospc_failure, },
-    { "oappend_failure", oappend_failure, .sizes = true },
     { "short_copy", short_copy, .sizes = true },
   };
 
@@ -739,53 +238,18 @@ do_test (void)
     *p = rand () >> 24;
 
   infd = create_temp_file ("tst-copy_file_range-in-", &infile);
-  xclose (create_temp_file ("tst-copy_file_range-out-", &outfile));
-
-  /* Try to find a different directory from the default input/output
-     file.  */
+  outfd = create_temp_file ("tst-copy_file_range-out-", &outfile);
   {
-    struct stat64 instat;
-    xfstat (infd, &instat);
-    static const char *const candidates[] =
-      { NULL, "/var/tmp", "/dev/shm" };
-    for (const char *const *c = candidates; c < array_end (candidates); ++c)
-      {
-        const char *path = *c;
-        char *to_free = NULL;
-        if (path == NULL)
-          {
-            to_free = xreadlink ("/proc/self/exe");
-            path = dirname (to_free);
-          }
-
-        struct stat64 cstat;
-        xstat (path, &cstat);
-        if (cstat.st_dev == instat.st_dev)
-          {
-            free (to_free);
-            continue;
-          }
-
-        printf ("info: using alternate temporary files directory: %s\n", path);
-        xdevfile = xasprintf ("%s/tst-copy_file_range-xdev-XXXXXX", path);
-        free (to_free);
-        break;
-      }
-    if (xdevfile != NULL)
+    ssize_t ret = copy_file_range (infd, NULL, outfd, NULL, 0, 0);
+    if (ret != 0)
       {
-        int xdevfd = mkstemp (xdevfile);
-        if (xdevfd < 0)
-          FAIL_EXIT1 ("mkstemp (\"%s\"): %m", xdevfile);
-        struct stat64 xdevst;
-        xfstat (xdevfd, &xdevst);
-        TEST_VERIFY (xdevst.st_dev != instat.st_dev);
-        add_temp_file (xdevfile);
-        xclose (xdevfd);
+        if (errno == ENOSYS)
+          FAIL_UNSUPPORTED ("copy_file_range is not support on this system");
+        FAIL_EXIT1 ("copy_file_range probing call: %m");
       }
-    else
-      puts ("warning: no alternate directory on different file system found");
   }
   xclose (infd);
+  xclose (outfd);
 
   for (do_inoff = 0; do_inoff < 2; ++do_inoff)
     for (do_outoff = 0; do_outoff < 2; ++do_outoff)
@@ -827,7 +291,6 @@ do_test (void)
 
   free (infile);
   free (outfile);
-  free (xdevfile);
 
   return 0;
 }
diff --git a/malloc/Makefile b/malloc/Makefile
index 388cf7e9ee..775b8db7e5 100644
--- a/malloc/Makefile
+++ b/malloc/Makefile
@@ -54,7 +54,7 @@ tests-internal += \
 	 tst-dynarray-at-fail \
 
 ifneq (no,$(have-tunables))
-tests += tst-malloc-usable-tunables
+tests += tst-malloc-usable-tunables tst-mxfast
 tests-static += tst-malloc-usable-static-tunables
 endif
 
@@ -196,6 +196,8 @@ tst-malloc-usable-static-ENV = $(tst-malloc-usable-ENV)
 tst-malloc-usable-tunables-ENV = GLIBC_TUNABLES=glibc.malloc.check=3
 tst-malloc-usable-static-tunables-ENV = $(tst-malloc-usable-tunables-ENV)
 
+tst-mxfast-ENV = GLIBC_TUNABLES=glibc.malloc.tcache_count=0:glibc.malloc.mxfast=0
+
 ifeq ($(experimental-malloc),yes)
 CPPFLAGS-malloc.c += -DUSE_TCACHE=1
 else
diff --git a/malloc/arena.c b/malloc/arena.c
index 497ae475e7..2cad4344ea 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -237,6 +237,7 @@ TUNABLE_CALLBACK_FNDECL (set_tcache_max, size_t)
 TUNABLE_CALLBACK_FNDECL (set_tcache_count, size_t)
 TUNABLE_CALLBACK_FNDECL (set_tcache_unsorted_limit, size_t)
 #endif
+TUNABLE_CALLBACK_FNDECL (set_mxfast, size_t)
 #else
 /* Initialization routine. */
 #include <string.h>
@@ -324,6 +325,7 @@ ptmalloc_init (void)
   TUNABLE_GET (tcache_unsorted_limit, size_t,
 	       TUNABLE_CALLBACK (set_tcache_unsorted_limit));
 # endif
+  TUNABLE_GET (mxfast, size_t, TUNABLE_CALLBACK (set_mxfast));
 #else
   const char *s = NULL;
   if (__glibc_likely (_environ != NULL))
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 0e7970001a..63a6cec350 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -321,6 +321,10 @@ __malloc_assert (const char *assertion, const char *file, unsigned int line,
 /* This is another arbitrary limit, which tunables can change.  Each
    tcache bin will hold at most this number of chunks.  */
 # define TCACHE_FILL_COUNT 7
+
+/* Maximum chunks in tcache bins for tunables.  This value must fit the range
+   of tcache->counts[] entries, else they may overflow.  */
+# define MAX_TCACHE_COUNT UINT16_MAX
 #endif
 
 
@@ -1624,7 +1628,7 @@ static INTERNAL_SIZE_T global_max_fast;
 
 #define set_max_fast(s) \
   global_max_fast = (((s) == 0)						      \
-                     ? SMALLBIN_WIDTH : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
+                     ? MIN_CHUNK_SIZE / 2 : ((s + SIZE_SZ) & ~MALLOC_ALIGN_MASK))
 
 static inline INTERNAL_SIZE_T
 get_max_fast (void)
@@ -2908,12 +2912,10 @@ typedef struct tcache_entry
    time), this is for performance reasons.  */
 typedef struct tcache_perthread_struct
 {
-  char counts[TCACHE_MAX_BINS];
+  uint16_t counts[TCACHE_MAX_BINS];
   tcache_entry *entries[TCACHE_MAX_BINS];
 } tcache_perthread_struct;
 
-#define MAX_TCACHE_COUNT 127	/* Maximum value of counts[] entries.  */
-
 static __thread bool tcache_shutting_down = false;
 static __thread tcache_perthread_struct *tcache = NULL;
 
@@ -2923,7 +2925,6 @@ static __always_inline void
 tcache_put (mchunkptr chunk, size_t tc_idx)
 {
   tcache_entry *e = (tcache_entry *) chunk2mem (chunk);
-  assert (tc_idx < TCACHE_MAX_BINS);
 
   /* Mark this chunk as "in the tcache" so the test in _int_free will
      detect a double free.  */
@@ -2940,8 +2941,6 @@ static __always_inline void *
 tcache_get (size_t tc_idx)
 {
   tcache_entry *e = tcache->entries[tc_idx];
-  assert (tc_idx < TCACHE_MAX_BINS);
-  assert (tcache->entries[tc_idx] > 0);
   tcache->entries[tc_idx] = e->next;
   --(tcache->counts[tc_idx]);
   e->key = NULL;
@@ -3046,9 +3045,8 @@ __libc_malloc (size_t bytes)
 
   DIAG_PUSH_NEEDS_COMMENT;
   if (tc_idx < mp_.tcache_bins
-      /*&& tc_idx < TCACHE_MAX_BINS*/ /* to appease gcc */
       && tcache
-      && tcache->entries[tc_idx] != NULL)
+      && tcache->counts[tc_idx] > 0)
     {
       return tcache_get (tc_idx);
     }
@@ -5142,6 +5140,19 @@ do_set_tcache_unsorted_limit (size_t value)
 }
 #endif
 
+static inline int
+__always_inline
+do_set_mxfast (size_t value)
+{
+  if (value >= 0 && value <= MAX_FAST_SIZE)
+    {
+      LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ());
+      set_max_fast (value);
+      return 1;
+    }
+  return 0;
+}
+
 int
 __libc_mallopt (int param_number, int value)
 {
@@ -5161,13 +5172,7 @@ __libc_mallopt (int param_number, int value)
   switch (param_number)
     {
     case M_MXFAST:
-      if (value >= 0 && value <= MAX_FAST_SIZE)
-        {
-          LIBC_PROBE (memory_mallopt_mxfast, 2, value, get_max_fast ());
-          set_max_fast (value);
-        }
-      else
-        res = 0;
+      do_set_mxfast (value);
       break;
 
     case M_TRIM_THRESHOLD:
@@ -5433,6 +5438,12 @@ __malloc_info (int options, FILE *fp)
 
       __libc_lock_lock (ar_ptr->mutex);
 
+      /* Account for top chunk.  The top-most available chunk is
+	 treated specially and is never in any bin. See "initial_top"
+	 comments.  */
+      avail = chunksize (ar_ptr->top);
+      nblocks = 1;  /* Top always exists.  */
+
       for (size_t i = 0; i < NFASTBINS; ++i)
 	{
 	  mchunkptr p = fastbin (ar_ptr, i);
@@ -5518,7 +5529,7 @@ __malloc_info (int options, FILE *fp)
 
       for (size_t i = 0; i < nsizes; ++i)
 	if (sizes[i].count != 0 && i != NFASTBINS)
-	  fprintf (fp, "							      \
+	  fprintf (fp, "\
   <size from=\"%zu\" to=\"%zu\" total=\"%zu\" count=\"%zu\"/>\n",
 		   sizes[i].from, sizes[i].to, sizes[i].total, sizes[i].count);
 
diff --git a/malloc/tst-mxfast.c b/malloc/tst-mxfast.c
new file mode 100644
index 0000000000..7a7750bc71
--- /dev/null
+++ b/malloc/tst-mxfast.c
@@ -0,0 +1,50 @@
+/* Test that glibc.malloc.mxfast tunable works.
+   Copyright (C) 2019 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/>.  */
+
+/* This test verifies that setting the glibc.malloc.mxfast tunable to
+   zero results in free'd blocks being returned to the small bins, not
+   the fast bins.  */
+
+#include <malloc.h>
+#include <support/check.h>
+
+int
+do_test (void)
+{
+  struct mallinfo m;
+  char *volatile p1;
+  char *volatile p2;
+
+  /* Arbitrary value; must be in default fastbin range.  */
+  p1 = malloc (3);
+  /* Something large so that p1 isn't a "top block" */
+  p2 = malloc (512);
+  free (p1);
+
+  m = mallinfo ();
+
+  /* This will fail if there are any blocks in the fastbins.  */
+  TEST_COMPARE (m.smblks, 0);
+
+  /* To keep gcc happy.  */
+  free (p2);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/manual/llio.texi b/manual/llio.texi
index 2733b9cb73..26f7d2cb3e 100644
--- a/manual/llio.texi
+++ b/manual/llio.texi
@@ -1404,10 +1404,13 @@ failure occurs.  The return value is zero if the end of the input file
 is encountered immediately.
 
 If no bytes can be copied, to report an error, @code{copy_file_range}
-returns the value @math{-1} and sets @code{errno}.  The following
-@code{errno} error conditions are specific to this function:
+returns the value @math{-1} and sets @code{errno}.  The table below
+lists some of the error conditions for this function.
 
 @table @code
+@item ENOSYS
+The kernel does not implement the required functionality.
+
 @item EISDIR
 At least one of the descriptors @var{inputfd} or @var{outputfd} refers
 to a directory.
@@ -1437,9 +1440,6 @@ reading.
 
 The argument @var{outputfd} is not a valid file descriptor open for
 writing, or @var{outputfd} has been opened with @code{O_APPEND}.
-
-@item EXDEV
-The input and output files reside on different file systems.
 @end table
 
 In addition, @code{copy_file_range} can fail with the error codes
diff --git a/manual/tunables.texi b/manual/tunables.texi
index 9dccf2ee7f..028868ded3 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -188,7 +188,7 @@ per-thread cache.  The default (and maximum) value is 1032 bytes on
 
 @deftp Tunable glibc.malloc.tcache_count
 The maximum number of chunks of each size to cache. The default is 7.
-The upper limit is 127.  If set to zero, the per-thread cache is effectively
+The upper limit is 65535.  If set to zero, the per-thread cache is effectively
 disabled.
 
 The approximate maximum overhead of the per-thread cache is thus equal
@@ -213,6 +213,18 @@ pre-fill the per-thread cache with.  The default, or when set to zero,
 is no limit.
 @end deftp
 
+@deftp Tunable glibc.malloc.mxfast
+One of the optimizations malloc uses is to maintain a series of ``fast
+bins'' that hold chunks up to a specific size.  The default and
+maximum size which may be held this way is 80 bytes on 32-bit systems
+or 160 bytes on 64-bit systems.  Applications which value size over
+speed may choose to reduce the size of requests which are serviced
+from fast bins with this tunable.  Note that the value specified
+includes malloc's internal overhead, which is normally the size of one
+pointer, so add 4 on 32-bit systems or 8 on 64-bit systems to the size
+passed to @code{malloc} for the largest bin size to enable.
+@end deftp
+
 @node Elision Tunables
 @section Elision Tunables
 @cindex elision tunables
@@ -333,7 +345,7 @@ This tunable is specific to powerpc, powerpc64 and powerpc64le.
 The @code{glibc.tune.cpu=xxx} tunable allows the user to tell @theglibc{} to
 assume that the CPU is @code{xxx} where xxx may have one of these values:
 @code{generic}, @code{falkor}, @code{thunderxt88}, @code{thunderx2t99},
-@code{thunderx2t99p1}.
+@code{thunderx2t99p1}, @code{ares}.
 
 This tunable is specific to aarch64.
 @end deftp
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index 04e3f08465..d0971a97fd 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -572,7 +572,9 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
 
 	  /* Place the thread descriptor at the end of the stack.  */
 #if TLS_TCB_AT_TP
-	  pd = (struct pthread *) ((char *) mem + size) - 1;
+	  pd = (struct pthread *) ((((uintptr_t) mem + size)
+				    - TLS_TCB_SIZE)
+				   & ~__static_tls_align_m1);
 #elif TLS_DTV_AT_TP
 	  pd = (struct pthread *) ((((uintptr_t) mem + size
 				    - __static_tls_size)
diff --git a/nptl/tst-tls1.c b/nptl/tst-tls1.c
index 1295170532..573dd376ca 100644
--- a/nptl/tst-tls1.c
+++ b/nptl/tst-tls1.c
@@ -19,12 +19,16 @@
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
-
+#include <stdint.h>
+#include <inttypes.h>
+#include <support/support.h>
+#include <support/check.h>
+#include <support/xthread.h>
 
 struct test_s
 {
-  int a;
-  int b;
+  __attribute__ ((aligned(0x20))) int a;
+  __attribute__ ((aligned(0x200))) int b;
 };
 
 #define INIT_A 1
@@ -36,15 +40,34 @@ __thread struct test_s s __attribute__ ((tls_model ("initial-exec"))) =
   .b = INIT_B
 };
 
+/* Use noinline in combination with not static to ensure that the
+   alignment check is really done.  Otherwise it was optimized out!  */
+__attribute__ ((noinline)) void
+check_alignment (const char *thr_name, const char *ptr_name,
+		 int *ptr, int alignment)
+{
+  uintptr_t offset_aligment = ((uintptr_t) ptr) & (alignment - 1);
+  if (offset_aligment)
+    {
+      FAIL_EXIT1 ("%s (%p) is not 0x%x-byte aligned in %s thread\n",
+		  ptr_name, ptr, alignment, thr_name);
+    }
+}
+
+static void
+check_s (const char *thr_name)
+{
+  if (s.a != INIT_A || s.b != INIT_B)
+    FAIL_EXIT1 ("initial value of s in %s thread wrong\n", thr_name);
+
+  check_alignment (thr_name, "s.a", &s.a, 0x20);
+  check_alignment (thr_name, "s.b", &s.b, 0x200);
+}
 
 static void *
 tf (void *arg)
 {
-  if (s.a != INIT_A || s.b != INIT_B)
-    {
-      puts ("initial value of s in child thread wrong");
-      exit (1);
-    }
+  check_s ("child");
 
   ++s.a;
 
@@ -55,25 +78,14 @@ tf (void *arg)
 int
 do_test (void)
 {
-  if (s.a != INIT_A || s.b != INIT_B)
-    {
-      puts ("initial value of s in main thread wrong");
-      exit (1);
-    }
+  check_s ("main");
 
   pthread_attr_t a;
 
-  if (pthread_attr_init (&a) != 0)
-    {
-      puts ("attr_init failed");
-      exit (1);
-    }
+  xpthread_attr_init (&a);
 
-  if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0)
-    {
-      puts ("attr_setstacksize failed");
-      return 1;
-    }
+#define STACK_SIZE (1 * 1024 * 1024)
+  xpthread_attr_setstacksize (&a, STACK_SIZE);
 
 #define N 10
   int i;
@@ -83,29 +95,25 @@ do_test (void)
       pthread_t th[M];
       int j;
       for (j = 0; j < M; ++j, ++s.a)
-	if (pthread_create (&th[j], &a, tf, NULL) != 0)
-	  {
-	    puts ("pthread_create failed");
-	    exit (1);
-	  }
+	th[j] = xpthread_create (&a, tf, NULL);
 
       for (j = 0; j < M; ++j)
-	if (pthread_join (th[j], NULL) != 0)
-	  {
-	    puts ("pthread_join failed");
-	    exit (1);
-	  }
+	xpthread_join (th[j]);
     }
 
-  if (pthread_attr_destroy (&a) != 0)
-    {
-      puts ("attr_destroy failed");
-      exit (1);
-    }
+  /* Also check the alignment of the tls variables if a misaligned stack is
+     specified.  */
+  pthread_t th;
+  void *thr_stack = NULL;
+  thr_stack = xposix_memalign (0x200, STACK_SIZE + 1);
+  xpthread_attr_setstack (&a, thr_stack + 1, STACK_SIZE);
+  th = xpthread_create (&a, tf, NULL);
+  xpthread_join (th);
+  free (thr_stack);
+
+  xpthread_attr_destroy (&a);
 
   return 0;
 }
 
-
-#define TEST_FUNCTION do_test ()
-#include "../test-skeleton.c"
+#include <support/test-driver.c>
diff --git a/nscd/connections.c b/nscd/connections.c
index 47fbb9923a..9818200764 100644
--- a/nscd/connections.c
+++ b/nscd/connections.c
@@ -304,7 +304,8 @@ static int
 check_use (const char *data, nscd_ssize_t first_free, uint8_t *usemap,
 	   enum usekey use, ref_t start, size_t len)
 {
-  assert (len >= 2);
+  if (len < 2)
+    return 0;
 
   if (start > first_free || start + len > first_free
       || (start & BLOCK_ALIGN_M1))
diff --git a/nss/nss_db/db-open.c b/nss/nss_db/db-open.c
index 8538f8e961..ac430f445a 100644
--- a/nss/nss_db/db-open.c
+++ b/nss/nss_db/db-open.c
@@ -63,5 +63,9 @@ internal_setent (const char *file, struct nss_db_map *mapping)
 void
 internal_endent (struct nss_db_map *mapping)
 {
-  munmap (mapping->header, mapping->len);
+  if (mapping->header != NULL)
+    {
+      munmap (mapping->header, mapping->len);
+      mapping->header = NULL;
+    }
 }
diff --git a/posix/tst-mmap-offset.c b/posix/tst-mmap-offset.c
index 92ea794c5a..cf17ba077c 100644
--- a/posix/tst-mmap-offset.c
+++ b/posix/tst-mmap-offset.c
@@ -1,4 +1,4 @@
-/* BZ #18877 and #21270 mmap offset test.
+/* BZ #18877, BZ #21270, and BZ #24699 mmap offset test.
 
    Copyright (C) 2015-2018 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
@@ -24,6 +24,7 @@
 #include <unistd.h>
 #include <errno.h>
 #include <sys/mman.h>
+#include <mmap_info.h>
 
 #include <support/check.h>
 
@@ -76,7 +77,7 @@ do_test_bz18877 (void)
 
 /* Check if invalid offset are handled correctly by mmap.  */
 static int
-do_test_bz21270 (void)
+do_test_large_offset (void)
 {
   /* For architectures with sizeof (off_t) < sizeof (off64_t) mmap is
      implemented with __SYS_mmap2 syscall and the offset is represented in
@@ -90,7 +91,7 @@ do_test_bz21270 (void)
   const size_t length = 4096;
 
   void *addr = mmap64 (NULL, length, prot, flags, fd, offset);
-  if (sizeof (off_t) < sizeof (off64_t))
+  if (mmap64_maximum_offset (page_shift) < UINT64_MAX)
     {
       if ((addr != MAP_FAILED) && (errno != EINVAL))
 	FAIL_RET ("mmap succeed");
@@ -110,7 +111,7 @@ do_test (void)
   int ret = 0;
 
   ret += do_test_bz18877 ();
-  ret += do_test_bz21270 ();
+  ret += do_test_large_offset ();
 
   return ret;
 }
diff --git a/string/memmem.c b/string/memmem.c
index 43efaa3fb7..7fbe1cb5d6 100644
--- a/string/memmem.c
+++ b/string/memmem.c
@@ -15,17 +15,13 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-/* This particular implementation was written by Eric Blake, 2008.  */
-
 #ifndef _LIBC
 # include <config.h>
 #endif
 
-/* Specification of memmem.  */
 #include <string.h>
 
 #ifndef _LIBC
-# define __builtin_expect(expr, val)   (expr)
 # define __memmem	memmem
 #endif
 
@@ -36,47 +32,98 @@
 
 #undef memmem
 
-/* Return the first occurrence of NEEDLE in HAYSTACK.  Return HAYSTACK
-   if NEEDLE_LEN is 0, otherwise NULL if NEEDLE is not found in
-   HAYSTACK.  */
+/* Hash character pairs so a small shift table can be used.  All bits of
+   p[0] are included, but not all bits from p[-1].  So if two equal hashes
+   match on p[-1], p[0] matches too.  Hash collisions are harmless and result
+   in smaller shifts.  */
+#define hash2(p) (((size_t)(p)[0] - ((size_t)(p)[-1] << 3)) % sizeof (shift))
+
+/* Fast memmem algorithm with guaranteed linear-time performance.
+   Small needles up to size 2 use a dedicated linear search.  Longer needles
+   up to size 256 use a novel modified Horspool algorithm.  It hashes pairs
+   of characters to quickly skip past mismatches.  The main search loop only
+   exits if the last 2 characters match, avoiding unnecessary calls to memcmp
+   and allowing for a larger skip if there is no match.  A self-adapting
+   filtering check is used to quickly detect mismatches in long needles.
+   By limiting the needle length to 256, the shift table can be reduced to 8
+   bits per entry, lowering preprocessing overhead and minimizing cache effects.
+   The limit also implies worst-case performance is linear.
+   Needles larger than 256 characters use the linear-time Two-Way algorithm.  */
 void *
-__memmem (const void *haystack_start, size_t haystack_len,
-	  const void *needle_start, size_t needle_len)
+__memmem (const void *haystack, size_t hs_len,
+	  const void *needle, size_t ne_len)
 {
-  /* Abstract memory is considered to be an array of 'unsigned char' values,
-     not an array of 'char' values.  See ISO C 99 section 6.2.6.1.  */
-  const unsigned char *haystack = (const unsigned char *) haystack_start;
-  const unsigned char *needle = (const unsigned char *) needle_start;
-
-  if (needle_len == 0)
-    /* The first occurrence of the empty string is deemed to occur at
-       the beginning of the string.  */
-    return (void *) haystack;
-
-  /* Sanity check, otherwise the loop might search through the whole
-     memory.  */
-  if (__glibc_unlikely (haystack_len < needle_len))
+  const unsigned char *hs = (const unsigned char *) haystack;
+  const unsigned char *ne = (const unsigned char *) needle;
+
+  if (ne_len == 0)
+    return (void *) hs;
+  if (ne_len == 1)
+    return (void *) memchr (hs, ne[0], hs_len);
+
+  /* Ensure haystack length is >= needle length.  */
+  if (hs_len < ne_len)
     return NULL;
 
-  /* Use optimizations in memchr when possible, to reduce the search
-     size of haystack using a linear algorithm with a smaller
-     coefficient.  However, avoid memchr for long needles, since we
-     can often achieve sublinear performance.  */
-  if (needle_len < LONG_NEEDLE_THRESHOLD)
+  const unsigned char *end = hs + hs_len - ne_len;
+
+  if (ne_len == 2)
+    {
+      uint32_t nw = ne[0] << 16 | ne[1], hw = hs[0] << 16 | hs[1];
+      for (hs++; hs <= end && hw != nw; )
+	hw = hw << 16 | *++hs;
+      return hw == nw ? (void *)hs - 1 : NULL;
+    }
+
+  /* Use Two-Way algorithm for very long needles.  */
+  if (__builtin_expect (ne_len > 256, 0))
+    return two_way_long_needle (hs, hs_len, ne, ne_len);
+
+  uint8_t shift[256];
+  size_t tmp, shift1;
+  size_t m1 = ne_len - 1;
+  size_t offset = 0;
+
+  memset (shift, 0, sizeof (shift));
+  for (int i = 1; i < m1; i++)
+    shift[hash2 (ne + i)] = i;
+  /* Shift1 is the amount we can skip after matching the hash of the
+     needle end but not the full needle.  */
+  shift1 = m1 - shift[hash2 (ne + m1)];
+  shift[hash2 (ne + m1)] = m1;
+
+  for ( ; hs <= end; )
     {
-      haystack = memchr (haystack, *needle, haystack_len);
-      if (!haystack || __builtin_expect (needle_len == 1, 0))
-	return (void *) haystack;
-      haystack_len -= haystack - (const unsigned char *) haystack_start;
-      if (haystack_len < needle_len)
-	return NULL;
-      return two_way_short_needle (haystack, haystack_len, needle, needle_len);
+      /* Skip past character pairs not in the needle.  */
+      do
+	{
+	  hs += m1;
+	  tmp = shift[hash2 (hs)];
+	}
+      while (tmp == 0 && hs <= end);
+
+      /* If the match is not at the end of the needle, shift to the end
+	 and continue until we match the hash of the needle end.  */
+      hs -= tmp;
+      if (tmp < m1)
+	continue;
+
+      /* Hash of the last 2 characters matches.  If the needle is long,
+	 try to quickly filter out mismatches.  */
+      if (m1 < 15 || memcmp (hs + offset, ne + offset, 8) == 0)
+	{
+	  if (memcmp (hs, ne, m1) == 0)
+	    return (void *) hs;
+
+	  /* Adjust filter offset when it doesn't find the mismatch.  */
+	  offset = (offset >= 8 ? offset : m1) - 8;
+	}
+
+      /* Skip based on matching the hash of the needle end.  */
+      hs += shift1;
     }
-  else
-    return two_way_long_needle (haystack, haystack_len, needle, needle_len);
+  return NULL;
 }
 libc_hidden_def (__memmem)
 weak_alias (__memmem, memmem)
 libc_hidden_weak (memmem)
-
-#undef LONG_NEEDLE_THRESHOLD
diff --git a/string/str-two-way.h b/string/str-two-way.h
index 523d946c59..358959bef0 100644
--- a/string/str-two-way.h
+++ b/string/str-two-way.h
@@ -221,7 +221,7 @@ critical_factorization (const unsigned char *needle, size_t needle_len,
    most 2 * HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching.
    If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 *
    HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching.  */
-static RETURN_TYPE
+static inline RETURN_TYPE
 two_way_short_needle (const unsigned char *haystack, size_t haystack_len,
 		      const unsigned char *needle, size_t needle_len)
 {
@@ -382,8 +382,11 @@ two_way_short_needle (const unsigned char *haystack, size_t haystack_len,
    and sublinear performance O(HAYSTACK_LEN / NEEDLE_LEN) is possible.
    If AVAILABLE modifies HAYSTACK_LEN (as in strstr), then at most 3 *
    HAYSTACK_LEN - NEEDLE_LEN comparisons occur in searching, and
-   sublinear performance is not possible.  */
-static RETURN_TYPE
+   sublinear performance is not possible.
+
+   Since this function is large and complex, block inlining to avoid
+   slowing down the common case of small needles.  */
+__attribute__((noinline)) static RETURN_TYPE
 two_way_long_needle (const unsigned char *haystack, size_t haystack_len,
 		     const unsigned char *needle, size_t needle_len)
 {
diff --git a/string/strcasestr.c b/string/strcasestr.c
index 421764bd1b..8aa76037dc 100644
--- a/string/strcasestr.c
+++ b/string/strcasestr.c
@@ -59,31 +59,22 @@
    case-insensitive comparison.  This function gives unspecified
    results in multibyte locales.  */
 char *
-STRCASESTR (const char *haystack_start, const char *needle_start)
+STRCASESTR (const char *haystack, const char *needle)
 {
-  const char *haystack = haystack_start;
-  const char *needle = needle_start;
   size_t needle_len; /* Length of NEEDLE.  */
   size_t haystack_len; /* Known minimum length of HAYSTACK.  */
-  bool ok = true; /* True if NEEDLE is prefix of HAYSTACK.  */
-
-  /* Determine length of NEEDLE, and in the process, make sure
-     HAYSTACK is at least as long (no point processing all of a long
-     NEEDLE if HAYSTACK is too short).  */
-  while (*haystack && *needle)
-    {
-      ok &= (TOLOWER ((unsigned char) *haystack)
-	     == TOLOWER ((unsigned char) *needle));
-      haystack++;
-      needle++;
-    }
-  if (*needle)
+
+  /* Handle empty NEEDLE special case.  */
+  if (needle[0] == '\0')
+    return (char *) haystack;
+
+  /* Ensure HAYSTACK length is at least as long as NEEDLE length.
+     Since a match may occur early on in a huge HAYSTACK, use strnlen
+     and read ahead a few cachelines for improved performance.  */
+  needle_len = strlen (needle);
+  haystack_len = __strnlen (haystack, needle_len + 256);
+  if (haystack_len < needle_len)
     return NULL;
-  if (ok)
-    return (char *) haystack_start;
-  needle_len = needle - needle_start;
-  haystack = haystack_start + 1;
-  haystack_len = needle_len - 1;
 
   /* Perform the search.  Abstract memory is considered to be an array
      of 'unsigned char' values, not an array of 'char' values.  See
@@ -91,10 +82,10 @@ STRCASESTR (const char *haystack_start, const char *needle_start)
   if (needle_len < LONG_NEEDLE_THRESHOLD)
     return two_way_short_needle ((const unsigned char *) haystack,
 				 haystack_len,
-				 (const unsigned char *) needle_start,
+				 (const unsigned char *) needle,
 				 needle_len);
   return two_way_long_needle ((const unsigned char *) haystack, haystack_len,
-			      (const unsigned char *) needle_start,
+			      (const unsigned char *) needle,
 			      needle_len);
 }
 
diff --git a/string/strstr.c b/string/strstr.c
index 79ebcc7532..7ffb18ab42 100644
--- a/string/strstr.c
+++ b/string/strstr.c
@@ -16,29 +16,17 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-/* This particular implementation was written by Eric Blake, 2008.  */
-
 #ifndef _LIBC
 # include <config.h>
 #endif
 
-/* Specification of strstr.  */
 #include <string.h>
 
-#include <stdbool.h>
-
-#ifndef _LIBC
-# define __builtin_expect(expr, val)   (expr)
-#endif
-
 #define RETURN_TYPE char *
 #define AVAILABLE(h, h_l, j, n_l)			\
   (((j) + (n_l) <= (h_l)) \
    || ((h_l) += __strnlen ((void*)((h) + (h_l)), (n_l) + 512), \
        (j) + (n_l) <= (h_l)))
-#define CHECK_EOL (1)
-#define RET0_IF_0(a) if (!a) goto ret0
-#define FASTSEARCH(S,C,N) (void*) strchr ((void*)(S), (C))
 #include "str-two-way.h"
 
 #undef strstr
@@ -47,48 +35,128 @@
 #define STRSTR strstr
 #endif
 
-/* Return the first occurrence of NEEDLE in HAYSTACK.  Return HAYSTACK
-   if NEEDLE is empty, otherwise NULL if NEEDLE is not found in
-   HAYSTACK.  */
+static inline char *
+strstr2 (const unsigned char *hs, const unsigned char *ne)
+{
+  uint32_t h1 = (ne[0] << 16) | ne[1];
+  uint32_t h2 = 0;
+  for (int c = hs[0]; h1 != h2 && c != 0; c = *++hs)
+      h2 = (h2 << 16) | c;
+  return h1 == h2 ? (char *)hs - 2 : NULL;
+}
+
+static inline char *
+strstr3 (const unsigned char *hs, const unsigned char *ne)
+{
+  uint32_t h1 = ((uint32_t)ne[0] << 24) | (ne[1] << 16) | (ne[2] << 8);
+  uint32_t h2 = 0;
+  for (int c = hs[0]; h1 != h2 && c != 0; c = *++hs)
+      h2 = (h2 | c) << 8;
+  return h1 == h2 ? (char *)hs - 3 : NULL;
+}
+
+/* Hash character pairs so a small shift table can be used.  All bits of
+   p[0] are included, but not all bits from p[-1].  So if two equal hashes
+   match on p[-1], p[0] matches too.  Hash collisions are harmless and result
+   in smaller shifts.  */
+#define hash2(p) (((size_t)(p)[0] - ((size_t)(p)[-1] << 3)) % sizeof (shift))
+
+/* Fast strstr algorithm with guaranteed linear-time performance.
+   Small needles up to size 3 use a dedicated linear search.  Longer needles
+   up to size 256 use a novel modified Horspool algorithm.  It hashes pairs
+   of characters to quickly skip past mismatches.  The main search loop only
+   exits if the last 2 characters match, avoiding unnecessary calls to memcmp
+   and allowing for a larger skip if there is no match.  A self-adapting
+   filtering check is used to quickly detect mismatches in long needles.
+   By limiting the needle length to 256, the shift table can be reduced to 8
+   bits per entry, lowering preprocessing overhead and minimizing cache effects.
+   The limit also implies worst-case performance is linear.
+   Needles larger than 256 characters use the linear-time Two-Way algorithm.  */
 char *
-STRSTR (const char *haystack_start, const char *needle_start)
+STRSTR (const char *haystack, const char *needle)
 {
-  const char *haystack = haystack_start;
-  const char *needle = needle_start;
-  size_t needle_len; /* Length of NEEDLE.  */
-  size_t haystack_len; /* Known minimum length of HAYSTACK.  */
-  bool ok = true; /* True if NEEDLE is prefix of HAYSTACK.  */
-
-  /* Determine length of NEEDLE, and in the process, make sure
-     HAYSTACK is at least as long (no point processing all of a long
-     NEEDLE if HAYSTACK is too short).  */
-  while (*haystack && *needle)
-    ok &= *haystack++ == *needle++;
-  if (*needle)
+  const unsigned char *hs = (const unsigned char *) haystack;
+  const unsigned char *ne = (const unsigned char *) needle;
+
+  /* Handle short needle special cases first.  */
+  if (ne[0] == '\0')
+    return (char *)hs;
+  hs = (const unsigned char *)strchr ((const char*)hs, ne[0]);
+  if (hs == NULL || ne[1] == '\0')
+    return (char*)hs;
+  if (ne[2] == '\0')
+    return strstr2 (hs, ne);
+  if (ne[3] == '\0')
+    return strstr3 (hs, ne);
+
+  /* Ensure haystack length is at least as long as needle length.
+     Since a match may occur early on in a huge haystack, use strnlen
+     and read ahead a few cachelines for improved performance.  */
+  size_t ne_len = strlen ((const char*)ne);
+  size_t hs_len = __strnlen ((const char*)hs, ne_len | 512);
+  if (hs_len < ne_len)
     return NULL;
-  if (ok)
-    return (char *) haystack_start;
-
-  /* Reduce the size of haystack using strchr, since it has a smaller
-     linear coefficient than the Two-Way algorithm.  */
-  needle_len = needle - needle_start;
-  haystack = strchr (haystack_start + 1, *needle_start);
-  if (!haystack || __builtin_expect (needle_len == 1, 0))
-    return (char *) haystack;
-  needle -= needle_len;
-  haystack_len = (haystack > haystack_start + needle_len ? 1
-		  : needle_len + haystack_start - haystack);
-
-  /* Perform the search.  Abstract memory is considered to be an array
-     of 'unsigned char' values, not an array of 'char' values.  See
-     ISO C 99 section 6.2.6.1.  */
-  if (needle_len < LONG_NEEDLE_THRESHOLD)
-    return two_way_short_needle ((const unsigned char *) haystack,
-				 haystack_len,
-				 (const unsigned char *) needle, needle_len);
-  return two_way_long_needle ((const unsigned char *) haystack, haystack_len,
-			      (const unsigned char *) needle, needle_len);
+
+  /* Check whether we have a match.  This improves performance since we
+     avoid initialization overheads.  */
+  if (memcmp (hs, ne, ne_len) == 0)
+    return (char *) hs;
+
+  /* Use Two-Way algorithm for very long needles.  */
+  if (__glibc_unlikely (ne_len > 256))
+    return two_way_long_needle (hs, hs_len, ne, ne_len);
+
+  const unsigned char *end = hs + hs_len - ne_len;
+  uint8_t shift[256];
+  size_t tmp, shift1;
+  size_t m1 = ne_len - 1;
+  size_t offset = 0;
+
+  /* Initialize bad character shift hash table.  */
+  memset (shift, 0, sizeof (shift));
+  for (int i = 1; i < m1; i++)
+    shift[hash2 (ne + i)] = i;
+  /* Shift1 is the amount we can skip after matching the hash of the
+     needle end but not the full needle.  */
+  shift1 = m1 - shift[hash2 (ne + m1)];
+  shift[hash2 (ne + m1)] = m1;
+
+  while (1)
+    {
+      if (__glibc_unlikely (hs > end))
+	{
+	  end += __strnlen ((const char*)end + m1 + 1, 2048);
+	  if (hs > end)
+	    return NULL;
+	}
+
+      /* Skip past character pairs not in the needle.  */
+      do
+	{
+	  hs += m1;
+	  tmp = shift[hash2 (hs)];
+	}
+      while (tmp == 0 && hs <= end);
+
+      /* If the match is not at the end of the needle, shift to the end
+	 and continue until we match the hash of the needle end.  */
+      hs -= tmp;
+      if (tmp < m1)
+	continue;
+
+      /* Hash of the last 2 characters matches.  If the needle is long,
+	 try to quickly filter out mismatches.  */
+      if (m1 < 15 || memcmp (hs + offset, ne + offset, 8) == 0)
+	{
+	  if (memcmp (hs, ne, m1) == 0)
+	    return (void *) hs;
+
+	  /* Adjust filter offset when it doesn't find the mismatch.  */
+	  offset = (offset >= 8 ? offset : m1) - 8;
+	}
+
+      /* Skip based on matching the hash of the needle end.  */
+      hs += shift1;
+    }
 }
 libc_hidden_builtin_def (strstr)
-
-#undef LONG_NEEDLE_THRESHOLD
diff --git a/support/Makefile b/support/Makefile
index b43fa524a7..3c0d870c96 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -93,10 +93,12 @@ libsupport-routines = \
   xopen \
   xpipe \
   xpoll \
+  xposix_memalign \
   xpthread_attr_destroy \
   xpthread_attr_init \
   xpthread_attr_setdetachstate \
   xpthread_attr_setguardsize \
+  xpthread_attr_setstack \
   xpthread_attr_setstacksize \
   xpthread_barrier_destroy \
   xpthread_barrier_init \
diff --git a/support/support.h b/support/support.h
index 4ea92e1c21..9d95ebbea1 100644
--- a/support/support.h
+++ b/support/support.h
@@ -76,6 +76,7 @@ char *support_quote_string (const char *);
 void *xmalloc (size_t) __attribute__ ((malloc));
 void *xcalloc (size_t n, size_t s) __attribute__ ((malloc));
 void *xrealloc (void *p, size_t n);
+void *xposix_memalign (size_t alignment, size_t n);
 char *xasprintf (const char *format, ...)
   __attribute__ ((format (printf, 1, 2), malloc));
 char *xstrdup (const char *);
diff --git a/io/tst-copy_file_range-compat.c b/support/xposix_memalign.c
index 00c109a74d..5501a0846a 100644
--- a/io/tst-copy_file_range-compat.c
+++ b/support/xposix_memalign.c
@@ -1,5 +1,5 @@
-/* Test the fallback implementation of copy_file_range.
-   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+/* Error-checking wrapper for posix_memalign.
+   Copyright (C) 2019 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
@@ -16,15 +16,20 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-/* Get the declaration of the official copy_of_range function.  */
-#include <unistd.h>
+#include <support/support.h>
+#include <stdlib.h>
+#include <errno.h>
 
-/* Compile a local version of copy_file_range.  */
-#define COPY_FILE_RANGE_DECL static
-#define COPY_FILE_RANGE copy_file_range_compat
-#include <io/copy_file_range-compat.c>
+void *
+xposix_memalign (size_t alignment, size_t n)
+{
+  void *p = NULL;
 
-/* Re-use the test, but run it against copy_file_range_compat defined
-   above.  */
-#define copy_file_range copy_file_range_compat
-#include "tst-copy_file_range.c"
+  int ret = posix_memalign (&p, alignment, n);
+  if (ret)
+    {
+      errno = ret;
+      oom_error ("posix_memalign", n);
+    }
+  return p;
+}
diff --git a/support/xpthread_attr_setstack.c b/support/xpthread_attr_setstack.c
new file mode 100644
index 0000000000..c3772e240b
--- /dev/null
+++ b/support/xpthread_attr_setstack.c
@@ -0,0 +1,26 @@
+/* pthread_attr_setstack with error checking.
+   Copyright (C) 2019 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 <support/xthread.h>
+
+void
+xpthread_attr_setstack (pthread_attr_t *attr, void *stackaddr, size_t stacksize)
+{
+  xpthread_check_return ("pthread_attr_setstack",
+			 pthread_attr_setstack (attr, stackaddr, stacksize));
+}
diff --git a/support/xthread.h b/support/xthread.h
index 1af7728087..00e2f59737 100644
--- a/support/xthread.h
+++ b/support/xthread.h
@@ -68,6 +68,8 @@ void xpthread_attr_destroy (pthread_attr_t *attr);
 void xpthread_attr_init (pthread_attr_t *attr);
 void xpthread_attr_setdetachstate (pthread_attr_t *attr,
 				   int detachstate);
+void xpthread_attr_setstack (pthread_attr_t *attr, void *stackaddr,
+			     size_t stacksize);
 void xpthread_attr_setstacksize (pthread_attr_t *attr,
 				 size_t stacksize);
 void xpthread_attr_setguardsize (pthread_attr_t *attr,
diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h
index 4935aa7c54..9617cb754f 100644
--- a/sysdeps/aarch64/dl-machine.h
+++ b/sysdeps/aarch64/dl-machine.h
@@ -388,10 +388,37 @@ elf_machine_lazy_rel (struct link_map *map,
   /* Check for unexpected PLT reloc type.  */
   if (__builtin_expect (r_type == AARCH64_R(JUMP_SLOT), 1))
     {
-      if (__builtin_expect (map->l_mach.plt, 0) == 0)
-	*reloc_addr += l_addr;
-      else
-	*reloc_addr = map->l_mach.plt;
+      if (map->l_mach.plt == 0)
+	{
+	  /* Prelinking.  */
+	  *reloc_addr += l_addr;
+	  return;
+	}
+
+      if (1) /* DT_AARCH64_VARIANT_PCS is not available, so always check.  */
+	{
+	  /* Check the symbol table for variant PCS symbols.  */
+	  const Elf_Symndx symndx = ELFW (R_SYM) (reloc->r_info);
+	  const ElfW (Sym) *symtab =
+	    (const void *)D_PTR (map, l_info[DT_SYMTAB]);
+	  const ElfW (Sym) *sym = &symtab[symndx];
+	  if (__glibc_unlikely (sym->st_other & STO_AARCH64_VARIANT_PCS))
+	    {
+	      /* Avoid lazy resolution of variant PCS symbols.  */
+	      const struct r_found_version *version = NULL;
+	      if (map->l_info[VERSYMIDX (DT_VERSYM)] != NULL)
+		{
+		  const ElfW (Half) *vernum =
+		    (const void *)D_PTR (map, l_info[VERSYMIDX (DT_VERSYM)]);
+		  version = &map->l_versions[vernum[symndx] & 0x7fff];
+		}
+	      elf_machine_rela (map, reloc, sym, version, reloc_addr,
+				skip_ifunc);
+	      return;
+	    }
+	}
+
+      *reloc_addr = map->l_mach.plt;
     }
   else if (__builtin_expect (r_type == AARCH64_R(TLSDESC), 1))
     {
diff --git a/sysdeps/aarch64/multiarch/memcpy.c b/sysdeps/aarch64/multiarch/memcpy.c
index 4a04a63b0f..8f5d4e7df5 100644
--- a/sysdeps/aarch64/multiarch/memcpy.c
+++ b/sysdeps/aarch64/multiarch/memcpy.c
@@ -36,7 +36,7 @@ extern __typeof (__redirect_memcpy) __memcpy_falkor attribute_hidden;
 libc_ifunc (__libc_memcpy,
             (IS_THUNDERX (midr)
 	     ? __memcpy_thunderx
-	     : (IS_FALKOR (midr) || IS_PHECDA (midr)
+	     : (IS_FALKOR (midr) || IS_PHECDA (midr) || IS_ARES (midr)
 		? __memcpy_falkor
 		: (IS_THUNDERX2 (midr) || IS_THUNDERX2PA (midr)
 		  ? __memcpy_thunderx2
diff --git a/sysdeps/generic/mmap_info.h b/sysdeps/generic/mmap_info.h
new file mode 100644
index 0000000000..b3087df2d3
--- /dev/null
+++ b/sysdeps/generic/mmap_info.h
@@ -0,0 +1,16 @@
+/* As default architectures with sizeof (off_t) < sizeof (off64_t) the 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.  */
+
+/* Return the maximum value expected as offset argument in mmap64 call.  */
+static inline uint64_t
+mmap64_maximum_offset (long int page_shift)
+{
+  if (sizeof (off_t) < sizeof (off64_t))
+    return (UINT64_C(1) << (page_shift + (8 * sizeof (off_t)))) - 1;
+  else
+    return UINT64_MAX;
+}
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
index 39eba0186f..56076849ca 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.c
@@ -36,6 +36,7 @@ static struct cpu_list cpu_list[] = {
       {"thunderx2t99",   0x431F0AF0},
       {"thunderx2t99p1", 0x420F5160},
       {"phecda",	 0x680F0000},
+      {"ares",		 0x411FD0C0},
       {"generic", 	 0x0}
 };
 
diff --git a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
index eb35adfbe9..153d258afe 100644
--- a/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
+++ b/sysdeps/unix/sysv/linux/aarch64/cpu-features.h
@@ -51,6 +51,8 @@
 
 #define IS_PHECDA(midr) (MIDR_IMPLEMENTOR(midr) == 'h'			      \
                         && MIDR_PARTNUM(midr) == 0x000)
+#define IS_ARES(midr) (MIDR_IMPLEMENTOR(midr) == 'A'			      \
+			&& MIDR_PARTNUM(midr) == 0xd0c)
 
 struct cpu_features
 {
diff --git a/sysdeps/unix/sysv/linux/alpha/kernel-features.h b/sysdeps/unix/sysv/linux/alpha/kernel-features.h
index 402d2573d7..26344cd610 100644
--- a/sysdeps/unix/sysv/linux/alpha/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/alpha/kernel-features.h
@@ -48,7 +48,6 @@
 /* Support for copy_file_range, statx was added in kernel 4.13.  */
 #if __LINUX_KERNEL_VERSION < 0x040D00
 # undef __ASSUME_MLOCK2
-# undef __ASSUME_COPY_FILE_RANGE
 # undef __ASSUME_STATX
 #endif
 
diff --git a/sysdeps/unix/sysv/linux/copy_file_range.c b/sysdeps/unix/sysv/linux/copy_file_range.c
index 7b1a50f752..b88b7c9e2e 100644
--- a/sysdeps/unix/sysv/linux/copy_file_range.c
+++ b/sysdeps/unix/sysv/linux/copy_file_range.c
@@ -20,27 +20,16 @@
 #include <sysdep-cancel.h>
 #include <unistd.h>
 
-/* Include the fallback implementation.  */
-#ifndef __ASSUME_COPY_FILE_RANGE
-#define COPY_FILE_RANGE_DECL static
-#define COPY_FILE_RANGE copy_file_range_compat
-#include <io/copy_file_range-compat.c>
-#endif
-
 ssize_t
 copy_file_range (int infd, __off64_t *pinoff,
                  int outfd, __off64_t *poutoff,
                  size_t length, unsigned int flags)
 {
 #ifdef __NR_copy_file_range
-  ssize_t ret = SYSCALL_CANCEL (copy_file_range, infd, pinoff, outfd, poutoff,
-                                length, flags);
-# ifndef __ASSUME_COPY_FILE_RANGE
-  if (ret == -1 && errno == ENOSYS)
-    ret = copy_file_range_compat (infd, pinoff, outfd, poutoff, length, flags);
-# endif
-  return ret;
-#else  /* !__NR_copy_file_range */
-  return copy_file_range_compat (infd, pinoff, outfd, poutoff, length, flags);
+  return SYSCALL_CANCEL (copy_file_range, infd, pinoff, outfd, poutoff,
+                         length, flags);
+#else
+  __set_errno (ENOSYS);
+  return -1;
 #endif
 }
diff --git a/sysdeps/unix/sysv/linux/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h
index 5543d92d7e..7a74835495 100644
--- a/sysdeps/unix/sysv/linux/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/kernel-features.h
@@ -111,10 +111,6 @@
 # define __ASSUME_MLOCK2 1
 #endif
 
-#if __LINUX_KERNEL_VERSION >= 0x040500
-# define __ASSUME_COPY_FILE_RANGE 1
-#endif
-
 /* Support for statx was added in kernel 4.11.  */
 #if __LINUX_KERNEL_VERSION >= 0x040B00
 # define __ASSUME_STATX 1
diff --git a/sysdeps/unix/sysv/linux/microblaze/kernel-features.h b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h
index e8e2ac6a87..0dab05bedc 100644
--- a/sysdeps/unix/sysv/linux/microblaze/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h
@@ -58,9 +58,6 @@
 # undef __ASSUME_EXECVEAT
 #endif
 
-/* Support for the copy_file_range syscall was added in 4.10.  */
-#if __LINUX_KERNEL_VERSION < 0x040A00
-# undef __ASSUME_COPY_FILE_RANGE
 #endif
 
 /* Support for statx was added in kernel 4.12.  */
diff --git a/sysdeps/unix/sysv/linux/mips/Makefile b/sysdeps/unix/sysv/linux/mips/Makefile
index 8217f42e75..03044e7365 100644
--- a/sysdeps/unix/sysv/linux/mips/Makefile
+++ b/sysdeps/unix/sysv/linux/mips/Makefile
@@ -63,14 +63,25 @@ sysdep-dl-routines += dl-static
 
 sysdep_routines += dl-vdso
 endif
-
-# Supporting non-executable stacks on MIPS requires changes to both
-# the Linux kernel and glibc.  See
-# <https://sourceware.org/ml/libc-alpha/2016-01/msg00567.html> and
-# <https://sourceware.org/ml/libc-alpha/2016-01/msg00719.html>.
+# If the compiler doesn't use GNU.stack note,
+# this test is expected to fail.
+ifneq ($(mips-has-gnustack),yes)
 test-xfail-check-execstack = yes
 endif
+endif
 
 ifeq ($(subdir),stdlib)
 gen-as-const-headers += ucontext_i.sym
 endif
+
+ifeq ($(mips-force-execstack),yes)
+CFLAGS-.o += -Wa,-execstack
+CFLAGS-.os += -Wa,-execstack
+CFLAGS-.op += -Wa,-execstack
+CFLAGS-.oS += -Wa,-execstack
+
+ASFLAGS-.o += -Wa,-execstack
+ASFLAGS-.os += -Wa,-execstack
+ASFLAGS-.op += -Wa,-execstack
+ASFLAGS-.oS += -Wa,-execstack
+endif
diff --git a/sysdeps/unix/sysv/linux/mips/configure b/sysdeps/unix/sysv/linux/mips/configure
index 1ee7f41a36..25f98e0c7b 100644
--- a/sysdeps/unix/sysv/linux/mips/configure
+++ b/sysdeps/unix/sysv/linux/mips/configure
@@ -475,3 +475,44 @@ if test -z "$arch_minimum_kernel"; then
     arch_minimum_kernel=4.5.0
   fi
 fi
+
+# Check if we are supposed to run on kernels older than 4.8.0. If so,
+# force executable stack to avoid potential runtime problems with fpu
+# emulation.
+# NOTE: The check below assumes that in absence of user-provided minumum_kernel
+# we will default to arch_minimum_kernel which is currently less than 4.8.0 for
+# all known configurations. If this changes, the check must be updated.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the compiler must use executable stack" >&5
+$as_echo_n "checking whether the compiler must use executable stack... " >&6; }
+if ${libc_cv_mips_force_execstack+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  libc_cv_mips_force_execstack=no
+  if test $libc_mips_float = hard; then
+    if test -n "$minimum_kernel"; then
+
+       min_version=$((`echo "$minimum_kernel.0.0.0" | sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1 \* 65536 + \2 \* 256 + \3/'`))
+
+       if test $min_version -lt 264192; then
+         libc_cv_mips_force_execstack=yes
+       fi
+    else
+      libc_cv_mips_force_execstack=yes
+    fi
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_mips_force_execstack" >&5
+$as_echo "$libc_cv_mips_force_execstack" >&6; }
+
+libc_mips_has_gnustack=$libc_cv_as_noexecstack
+
+if test $libc_cv_mips_force_execstack = yes; then
+  libc_mips_has_gnustack=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: forcing executable stack for pre-4.8.0 Linux kernels" >&5
+$as_echo "$as_me: WARNING: forcing executable stack for pre-4.8.0 Linux kernels" >&2;}
+fi
+
+config_vars="$config_vars
+mips-force-execstack = ${libc_cv_mips_force_execstack}"
+config_vars="$config_vars
+mips-has-gnustack = ${libc_mips_has_gnustack}"
diff --git a/sysdeps/unix/sysv/linux/mips/configure.ac b/sysdeps/unix/sysv/linux/mips/configure.ac
index 9147aa4582..3db1b32b08 100644
--- a/sysdeps/unix/sysv/linux/mips/configure.ac
+++ b/sysdeps/unix/sysv/linux/mips/configure.ac
@@ -134,3 +134,35 @@ if test -z "$arch_minimum_kernel"; then
     arch_minimum_kernel=4.5.0
   fi
 fi
+
+# Check if we are supposed to run on kernels older than 4.8.0. If so,
+# force executable stack to avoid potential runtime problems with fpu
+# emulation.
+# NOTE: The check below assumes that in absence of user-provided minumum_kernel
+# we will default to arch_minimum_kernel which is currently less than 4.8.0 for
+# all known configurations. If this changes, the check must be updated.
+AC_CACHE_CHECK([whether the compiler must use executable stack],
+        libc_cv_mips_force_execstack, [dnl
+libc_cv_mips_force_execstack=no
+  if test $libc_mips_float = hard; then
+    if test -n "$minimum_kernel"; then
+       changequote(,)
+       min_version=$((`echo "$minimum_kernel.0.0.0" | sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\1 \* 65536 + \2 \* 256 + \3/'`))
+       changequote([,])
+       if test $min_version -lt 264192; then
+         libc_cv_mips_force_execstack=yes
+       fi
+    else
+      libc_cv_mips_force_execstack=yes
+    fi
+  fi])
+
+libc_mips_has_gnustack=$libc_cv_as_noexecstack
+
+if test $libc_cv_mips_force_execstack = yes; then
+  libc_mips_has_gnustack=no
+  AC_MSG_WARN([forcing executable stack for pre-4.8.0 Linux kernels])
+fi
+
+LIBC_CONFIG_VAR([mips-force-execstack],[${libc_cv_mips_force_execstack}])
+LIBC_CONFIG_VAR([mips-has-gnustack],[${libc_mips_has_gnustack}])
diff --git a/sysdeps/unix/sysv/linux/mips/mmap_info.h b/sysdeps/unix/sysv/linux/mips/mmap_info.h
new file mode 100644
index 0000000000..07c9e3a044
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/mips/mmap_info.h
@@ -0,0 +1,13 @@
+/* mips64n32 uses __NR_mmap for mmap64 while still having sizeof (off_t)
+   smaller than sizeof (off64_t).  So it allows mapping large offsets
+   using mmap64 than 32-bit archs which uses __NR_mmap2.  */
+
+static inline uint64_t
+mmap64_maximum_offset (long int page_shift)
+{
+#if _MIPS_SIM == _ABIN32 || _MIPS_SIM == _ABI64
+  return UINT64_MAX;
+#else
+  return (UINT64_C(1) << (page_shift + (8 * sizeof (off_t)))) - 1;
+#endif
+}
diff --git a/sysdeps/unix/sysv/linux/mmap64.c b/sysdeps/unix/sysv/linux/mmap64.c
index 118624185e..5d7598b4ba 100644
--- a/sysdeps/unix/sysv/linux/mmap64.c
+++ b/sysdeps/unix/sysv/linux/mmap64.c
@@ -23,11 +23,18 @@
 #include <sysdep.h>
 #include <mmap_internal.h>
 
+#ifdef __NR_mmap2
 /* 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 \
+# define MMAP_OFF_HIGH_MASK \
   ((-(MMAP2_PAGE_UNIT << 1) << (8 * sizeof (off_t) - 1)))
+#else
+/* Some ABIs might use __NR_mmap while having sizeof (off_t) smaller than
+   sizeof (off64_t) (currently only MIPS64n32).  For this case just set
+   zero the higher bits so mmap with large offset does not fail.  */
+# define MMAP_OFF_HIGH_MASK  0x0
+#endif
 
 #define MMAP_OFF_MASK (MMAP_OFF_HIGH_MASK | MMAP_OFF_LOW_MASK)
 
diff --git a/sysdeps/x86/Makefile b/sysdeps/x86/Makefile
index 337b0b63dc..43ad4a79ff 100644
--- a/sysdeps/x86/Makefile
+++ b/sysdeps/x86/Makefile
@@ -19,12 +19,17 @@ ifeq ($(subdir),elf)
 sysdep-dl-routines += dl-cet
 
 tests += tst-cet-legacy-1 tst-cet-legacy-2 tst-cet-legacy-2a \
-	 tst-cet-legacy-3 tst-cet-legacy-4
+	 tst-cet-legacy-3 tst-cet-legacy-4 \
+	 tst-cet-legacy-5a tst-cet-legacy-6a
 ifneq (no,$(have-tunables))
-tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c
+tests += tst-cet-legacy-4a tst-cet-legacy-4b tst-cet-legacy-4c \
+	 tst-cet-legacy-5b tst-cet-legacy-6b
 endif
 modules-names += tst-cet-legacy-mod-1 tst-cet-legacy-mod-2 \
-		 tst-cet-legacy-mod-4
+		 tst-cet-legacy-mod-4 tst-cet-legacy-mod-5a \
+		 tst-cet-legacy-mod-5b tst-cet-legacy-mod-5c \
+		 tst-cet-legacy-mod-6a tst-cet-legacy-mod-6b \
+		 tst-cet-legacy-mod-6c
 
 CFLAGS-tst-cet-legacy-2.c += -fcf-protection=branch
 CFLAGS-tst-cet-legacy-2a.c += -fcf-protection
@@ -35,6 +40,16 @@ CFLAGS-tst-cet-legacy-4.c += -fcf-protection=branch
 CFLAGS-tst-cet-legacy-4a.c += -fcf-protection
 CFLAGS-tst-cet-legacy-4b.c += -fcf-protection
 CFLAGS-tst-cet-legacy-mod-4.c += -fcf-protection=none
+CFLAGS-tst-cet-legacy-5a.c += -fcf-protection
+CFLAGS-tst-cet-legacy-5b.c += -fcf-protection
+CFLAGS-tst-cet-legacy-mod-5a.c += -fcf-protection=none
+CFLAGS-tst-cet-legacy-mod-5b.c += -fcf-protection
+CFLAGS-tst-cet-legacy-mod-5c.c += -fcf-protection
+CFLAGS-tst-cet-legacy-6a.c += -fcf-protection
+CFLAGS-tst-cet-legacy-6b.c += -fcf-protection
+CFLAGS-tst-cet-legacy-mod-6a.c += -fcf-protection=none
+CFLAGS-tst-cet-legacy-mod-6b.c += -fcf-protection
+CFLAGS-tst-cet-legacy-mod-6c.c += -fcf-protection
 
 $(objpfx)tst-cet-legacy-1: $(objpfx)tst-cet-legacy-mod-1.so \
 		       $(objpfx)tst-cet-legacy-mod-2.so
@@ -44,6 +59,17 @@ $(objpfx)tst-cet-legacy-2a: $(objpfx)tst-cet-legacy-mod-2.so $(libdl)
 $(objpfx)tst-cet-legacy-2a.out: $(objpfx)tst-cet-legacy-mod-1.so
 $(objpfx)tst-cet-legacy-4: $(libdl)
 $(objpfx)tst-cet-legacy-4.out: $(objpfx)tst-cet-legacy-mod-4.so
+$(objpfx)tst-cet-legacy-5a: $(libdl)
+$(objpfx)tst-cet-legacy-5a.out: $(objpfx)tst-cet-legacy-mod-5a.so \
+				$(objpfx)tst-cet-legacy-mod-5b.so
+$(objpfx)tst-cet-legacy-mod-5a.so: $(objpfx)tst-cet-legacy-mod-5c.so
+$(objpfx)tst-cet-legacy-mod-5b.so: $(objpfx)tst-cet-legacy-mod-5c.so
+$(objpfx)tst-cet-legacy-6a: $(libdl)
+$(objpfx)tst-cet-legacy-6a.out: $(objpfx)tst-cet-legacy-mod-6a.so \
+				$(objpfx)tst-cet-legacy-mod-6b.so
+$(objpfx)tst-cet-legacy-mod-6a.so: $(objpfx)tst-cet-legacy-mod-6c.so
+$(objpfx)tst-cet-legacy-mod-6b.so: $(objpfx)tst-cet-legacy-mod-6c.so
+LDFLAGS-tst-cet-legacy-mod-6c.so = -Wl,--enable-new-dtags,-z,nodelete
 ifneq (no,$(have-tunables))
 $(objpfx)tst-cet-legacy-4a: $(libdl)
 $(objpfx)tst-cet-legacy-4a.out: $(objpfx)tst-cet-legacy-mod-4.so
@@ -54,6 +80,14 @@ tst-cet-legacy-4b-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=on
 $(objpfx)tst-cet-legacy-4c: $(libdl)
 $(objpfx)tst-cet-legacy-4c.out: $(objpfx)tst-cet-legacy-mod-4.so
 tst-cet-legacy-4c-ENV = GLIBC_TUNABLES=glibc.tune.x86_shstk=off
+$(objpfx)tst-cet-legacy-5b: $(libdl)
+$(objpfx)tst-cet-legacy-5b.out: $(objpfx)tst-cet-legacy-mod-5a.so \
+				$(objpfx)tst-cet-legacy-mod-5b.so
+tst-cet-legacy-5b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off
+$(objpfx)tst-cet-legacy-6b: $(libdl)
+$(objpfx)tst-cet-legacy-6b.out: $(objpfx)tst-cet-legacy-mod-6a.so \
+				$(objpfx)tst-cet-legacy-mod-6b.so
+tst-cet-legacy-6b-ENV = GLIBC_TUNABLES=glibc.tune.x86_ibt=off:glibc.tune.x86_shstk=off
 endif
 endif
 
diff --git a/sysdeps/x86/tst-cet-legacy-5.c b/sysdeps/x86/tst-cet-legacy-5.c
new file mode 100644
index 0000000000..fbf640f664
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-5.c
@@ -0,0 +1,76 @@
+/* Check compatibility of CET-enabled executable with dlopened legacy
+   shared object.
+   Copyright (C) 2019 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 <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+static void
+do_test_1 (const char *modname, bool fail)
+{
+  int (*fp) (void);
+  void *h;
+
+  h = dlopen (modname, RTLD_LAZY);
+  if (h == NULL)
+    {
+      if (fail)
+	{
+	  const char *err = dlerror ();
+	  if (strstr (err, "shadow stack isn't enabled") == NULL)
+	    {
+	      printf ("incorrect dlopen '%s' error: %s\n", modname,
+		      dlerror ());
+	      exit (1);
+	    }
+
+	  return;
+	}
+
+      printf ("cannot open '%s': %s\n", modname, dlerror ());
+      exit (1);
+    }
+
+  fp = dlsym (h, "test");
+  if (fp == NULL)
+    {
+      printf ("cannot get symbol 'test': %s\n", dlerror ());
+      exit (1);
+    }
+
+  if (fp () != 0)
+    {
+      puts ("test () != 0");
+      exit (1);
+    }
+
+  dlclose (h);
+}
+
+static int
+do_test (void)
+{
+  do_test_1 ("tst-cet-legacy-mod-5a.so", true);
+  do_test_1 ("tst-cet-legacy-mod-5b.so", false);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/x86/tst-cet-legacy-5a.c b/sysdeps/x86/tst-cet-legacy-5a.c
new file mode 100644
index 0000000000..fc5a609dff
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-5a.c
@@ -0,0 +1 @@
+#include "tst-cet-legacy-5.c"
diff --git a/sysdeps/x86/tst-cet-legacy-5b.c b/sysdeps/x86/tst-cet-legacy-5b.c
new file mode 100644
index 0000000000..fc5a609dff
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-5b.c
@@ -0,0 +1 @@
+#include "tst-cet-legacy-5.c"
diff --git a/sysdeps/x86/tst-cet-legacy-6.c b/sysdeps/x86/tst-cet-legacy-6.c
new file mode 100644
index 0000000000..9151225264
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-6.c
@@ -0,0 +1,76 @@
+/* Check compatibility of CET-enabled executable with dlopened legacy
+   shared object.
+   Copyright (C) 2019 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 <dlfcn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+static void
+do_test_1 (const char *modname, bool fail)
+{
+  int (*fp) (void);
+  void *h;
+
+  h = dlopen (modname, RTLD_LAZY);
+  if (h == NULL)
+    {
+      if (fail)
+	{
+	  const char *err = dlerror ();
+	  if (strstr (err, "shadow stack isn't enabled") == NULL)
+	    {
+	      printf ("incorrect dlopen '%s' error: %s\n", modname,
+		      dlerror ());
+	      exit (1);
+	    }
+
+	  return;
+	}
+
+      printf ("cannot open '%s': %s\n", modname, dlerror ());
+      exit (1);
+    }
+
+  fp = dlsym (h, "test");
+  if (fp == NULL)
+    {
+      printf ("cannot get symbol 'test': %s\n", dlerror ());
+      exit (1);
+    }
+
+  if (fp () != 0)
+    {
+      puts ("test () != 0");
+      exit (1);
+    }
+
+  dlclose (h);
+}
+
+static int
+do_test (void)
+{
+  do_test_1 ("tst-cet-legacy-mod-6a.so", true);
+  do_test_1 ("tst-cet-legacy-mod-6b.so", false);
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/x86/tst-cet-legacy-6a.c b/sysdeps/x86/tst-cet-legacy-6a.c
new file mode 100644
index 0000000000..2d1546d36b
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-6a.c
@@ -0,0 +1 @@
+#include "tst-cet-legacy-6.c"
diff --git a/sysdeps/x86/tst-cet-legacy-6b.c b/sysdeps/x86/tst-cet-legacy-6b.c
new file mode 100644
index 0000000000..2d1546d36b
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-6b.c
@@ -0,0 +1 @@
+#include "tst-cet-legacy-6.c"
diff --git a/sysdeps/x86/tst-cet-legacy-mod-5.c b/sysdeps/x86/tst-cet-legacy-mod-5.c
new file mode 100644
index 0000000000..3c1071c2ef
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-mod-5.c
@@ -0,0 +1,31 @@
+/* Check compatibility of CET-enabled executable with dlopened legacy
+   shared object.
+   Copyright (C) 2019 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 <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void foo (void);
+
+int
+test (void)
+{
+  foo ();
+  return 0;
+}
diff --git a/sysdeps/x86/tst-cet-legacy-mod-5a.c b/sysdeps/x86/tst-cet-legacy-mod-5a.c
new file mode 100644
index 0000000000..daa43e4e8d
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-mod-5a.c
@@ -0,0 +1 @@
+#include "tst-cet-legacy-mod-5.c"
diff --git a/sysdeps/x86/tst-cet-legacy-mod-5b.c b/sysdeps/x86/tst-cet-legacy-mod-5b.c
new file mode 100644
index 0000000000..daa43e4e8d
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-mod-5b.c
@@ -0,0 +1 @@
+#include "tst-cet-legacy-mod-5.c"
diff --git a/sysdeps/x86/tst-cet-legacy-mod-5c.c b/sysdeps/x86/tst-cet-legacy-mod-5c.c
new file mode 100644
index 0000000000..e529a42ac0
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-mod-5c.c
@@ -0,0 +1,36 @@
+/* Check compatibility of CET-enabled executable with dlopened legacy
+   shared object.
+   Copyright (C) 2019 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 <stdlib.h>
+
+static int called = 0;
+
+static void
+__attribute__ ((constructor))
+init (void)
+{
+  called = 1;
+}
+
+void
+foo (void)
+{
+  if (!called)
+    abort ();
+}
diff --git a/sysdeps/x86/tst-cet-legacy-mod-6.c b/sysdeps/x86/tst-cet-legacy-mod-6.c
new file mode 100644
index 0000000000..3c1071c2ef
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-mod-6.c
@@ -0,0 +1,31 @@
+/* Check compatibility of CET-enabled executable with dlopened legacy
+   shared object.
+   Copyright (C) 2019 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 <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+extern void foo (void);
+
+int
+test (void)
+{
+  foo ();
+  return 0;
+}
diff --git a/sysdeps/x86/tst-cet-legacy-mod-6a.c b/sysdeps/x86/tst-cet-legacy-mod-6a.c
new file mode 100644
index 0000000000..c89b8fe8ff
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-mod-6a.c
@@ -0,0 +1 @@
+#include "tst-cet-legacy-mod-6.c"
diff --git a/sysdeps/x86/tst-cet-legacy-mod-6b.c b/sysdeps/x86/tst-cet-legacy-mod-6b.c
new file mode 100644
index 0000000000..c89b8fe8ff
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-mod-6b.c
@@ -0,0 +1 @@
+#include "tst-cet-legacy-mod-6.c"
diff --git a/sysdeps/x86/tst-cet-legacy-mod-6c.c b/sysdeps/x86/tst-cet-legacy-mod-6c.c
new file mode 100644
index 0000000000..e529a42ac0
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-mod-6c.c
@@ -0,0 +1,36 @@
+/* Check compatibility of CET-enabled executable with dlopened legacy
+   shared object.
+   Copyright (C) 2019 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 <stdlib.h>
+
+static int called = 0;
+
+static void
+__attribute__ ((constructor))
+init (void)
+{
+  called = 1;
+}
+
+void
+foo (void)
+{
+  if (!called)
+    abort ();
+}
diff --git a/sysdeps/x86/tst-cet-legacy-mod-6d.c b/sysdeps/x86/tst-cet-legacy-mod-6d.c
new file mode 100644
index 0000000000..eb233a1d10
--- /dev/null
+++ b/sysdeps/x86/tst-cet-legacy-mod-6d.c
@@ -0,0 +1 @@
+#include "tst-cet-legacy-mod-6c.c"