summaryrefslogtreecommitdiff
path: root/glibc-32
diff options
context:
space:
mode:
authorTim Biermann <tbier@posteo.de>2021-12-11 22:59:48 +0100
committerTim Biermann <tbier@posteo.de>2021-12-11 22:59:48 +0100
commit9686d5573bdd39f2c31c27082b8bd98b3cebd77a (patch)
treef94861b659671b1edaabe81264e2370a88d55bd5 /glibc-32
parentef16948581c3f6e52e21065310fc7d8d581a6317 (diff)
downloadcore-9686d5573bdd39f2c31c27082b8bd98b3cebd77a.tar.gz
core-9686d5573bdd39f2c31c27082b8bd98b3cebd77a.tar.xz
glibc-32: included upstream fixes
Diffstat (limited to 'glibc-32')
-rw-r--r--glibc-32/.signature5
-rw-r--r--glibc-32/Pkgfile5
-rw-r--r--glibc-32/glibc-2.34-upstream-fixes.patch4387
3 files changed, 4393 insertions, 4 deletions
diff --git a/glibc-32/.signature b/glibc-32/.signature
index 58f95f12..70c87f01 100644
--- a/glibc-32/.signature
+++ b/glibc-32/.signature
@@ -1,10 +1,11 @@
untrusted comment: verify with /etc/ports/core.pub
-RWRJc1FUaeVeqqIvfNfyoGIl3dJWeU+KOTOKkWvyJpUsCaumvqsUo08Gd66SzkGuMdBJ4qYBU1BI/SCmLS1faxl+je8FS/rAIws=
-SHA256 (Pkgfile) = 344f3dce94b58f4108dd81e696ed2005138ab6558ddb75131e3943a7602d473b
+RWRJc1FUaeVeqrneHjowycLr7W204qXt5Wf3z/w3P42URNoZQg+kIhdH+H6rnVPZcJSAbumo5a5L5RKfobLZiNQr5hAieTyOyg0=
+SHA256 (Pkgfile) = 68d47984366f1181f91cfb699012fe591e176a30f4981d2317811874343dbbc9
SHA256 (.footprint) = 28c0be81580495d8789fce4c11a415bd557693f979c5beb40977cbac1607853b
SHA256 (glibc-2.34.tar.xz) = 44d26a1fe20b8853a48f470ead01e4279e869ac149b195dda4e44a195d981ab2
SHA256 (linux-5.10.tar.xz) = dcdf99e43e98330d925016985bfbc7b83c66d367b714b2de0cbbfcbf83d8ca43
SHA256 (glibc-c-utf8-locale-1.patch) = c48c306658ede269fb4a43140d41a3f609bffd17a8f661127e3e4dde48b85cd4
SHA256 (glibc-c-utf8-locale-2.patch) = a9d3c0660e6a48bb22dc77afbc7bb47ce79ca0d8c2ee8ebee4228d8d4952214e
SHA256 (glibc-python3.patch) = 4a6511436c8abb708f5cb7e9baaf9812f2dc4bb5665a9376c1e270eae4f8b14f
+SHA256 (glibc-2.34-upstream-fixes.patch) = 54e965200314f627a3412dd723d31e44a56ae9a156fce066d2a742caa86c0a36
SHA256 (lib32.conf) = 2f174d2bcefe1c29327690514f34d6970fffdd54398320ca23a11b5f1e3c9b2d
diff --git a/glibc-32/Pkgfile b/glibc-32/Pkgfile
index 2e780f06..489ea204 100644
--- a/glibc-32/Pkgfile
+++ b/glibc-32/Pkgfile
@@ -4,11 +4,11 @@
name=glibc-32
version=2.34
-release=1
+release=2
source=(https://ftp.gnu.org/gnu/glibc/glibc-$version.tar.xz
https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.10.tar.xz
glibc-c-utf8-locale-1.patch glibc-c-utf8-locale-2.patch
- glibc-python3.patch
+ glibc-python3.patch glibc-2.34-upstream-fixes.patch
lib32.conf)
build() {
@@ -18,6 +18,7 @@ build() {
make INSTALL_HDR_PATH=$PKG/usr headers_install
chown root:root $PKG/usr
+ patch -p1 -d $SRC/glibc-${version:0:4} -i $SRC/glibc-2.34-upstream-fixes.patch
patch -p1 -d $SRC/glibc-${version:0:4} -i $SRC/glibc-python3.patch
patch -p1 -d $SRC/glibc-${version:0:4} -i $SRC/glibc-c-utf8-locale-1.patch
patch -p1 -d $SRC/glibc-${version:0:4} -i $SRC/glibc-c-utf8-locale-2.patch
diff --git a/glibc-32/glibc-2.34-upstream-fixes.patch b/glibc-32/glibc-2.34-upstream-fixes.patch
new file mode 100644
index 00000000..02585341
--- /dev/null
+++ b/glibc-32/glibc-2.34-upstream-fixes.patch
@@ -0,0 +1,4387 @@
+diff --git a/NEWS b/NEWS
+index 3c610744c9..698964bb9e 100644
+--- a/NEWS
++++ b/NEWS
+@@ -4,6 +4,25 @@ See the end for copying conditions.
+
+ Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
+ using `glibc' in the "product" field.
++
++Version 2.34.1
++
++The following bugs are resolved with this release:
++
++ [12889] nptl: Fix race between pthread_kill and thread exit
++ [19193] nptl: pthread_kill, pthread_cancel should not fail after exit
++ [28036] Incorrect types for pthread_mutexattr_set/getrobust_np
++ [28182] _TIME_BITS=64 in C++ has issues with fcntl, ioctl, prctl
++ [28310] Do not use affinity mask for sysconf (_SC_NPROCESSORS_CONF)
++ [28340] ld.so crashes while loading a DSO with a read-only dynamic section
++ [28357] deadlock between pthread_create and ELF constructors
++ [28361] nptl: Avoid setxid deadlock with blocked signals in thread exit
++ [28407] pthread_kill assumes that kill and tgkill are equivalent
++ [28524] Conversion from ISO-2022-JP-3 with iconv may emit spurious NULs
++ [28607] Masked signals are delivered on thread exit
++ [28532] powerpc64[le]: CFI for assembly templated syscalls is incorrect
++ [28678] nptl/tst-create1 hangs sporadically
++
+
+ Version 2.34
+
+diff --git a/bits/stdlib-bsearch.h b/bits/stdlib-bsearch.h
+index 4132dc6af0..e2fcea6e17 100644
+--- a/bits/stdlib-bsearch.h
++++ b/bits/stdlib-bsearch.h
+@@ -29,14 +29,23 @@ bsearch (const void *__key, const void *__base, size_t __nmemb, size_t __size,
+ while (__l < __u)
+ {
+ __idx = (__l + __u) / 2;
+- __p = (void *) (((const char *) __base) + (__idx * __size));
++ __p = (const void *) (((const char *) __base) + (__idx * __size));
+ __comparison = (*__compar) (__key, __p);
+ if (__comparison < 0)
+ __u = __idx;
+ else if (__comparison > 0)
+ __l = __idx + 1;
+ else
+- return (void *) __p;
++ {
++#if __GNUC_PREREQ(4, 6)
++# pragma GCC diagnostic push
++# pragma GCC diagnostic ignored "-Wcast-qual"
++#endif
++ return (void *) __p;
++#if __GNUC_PREREQ(4, 6)
++# pragma GCC diagnostic pop
++#endif
++ }
+ }
+
+ return NULL;
+diff --git a/elf/Makefile b/elf/Makefile
+index d05f410592..118d579c42 100644
+--- a/elf/Makefile
++++ b/elf/Makefile
+@@ -224,7 +224,7 @@ tests += restest1 preloadtest loadfail multiload origtest resolvfail \
+ tst-tls-ie tst-tls-ie-dlmopen argv0test \
+ tst-glibc-hwcaps tst-glibc-hwcaps-prepend tst-glibc-hwcaps-mask \
+ tst-tls20 tst-tls21 tst-dlmopen-dlerror tst-dlmopen-gethostbyname \
+- tst-dl-is_dso
++ tst-dl-is_dso tst-ro-dynamic
+ # reldep9
+ tests-internal += loadtest unload unload2 circleload1 \
+ neededtest neededtest2 neededtest3 neededtest4 \
+@@ -357,7 +357,7 @@ modules-names = testobj1 testobj2 testobj3 testobj4 testobj5 testobj6 \
+ libmarkermod4-1 libmarkermod4-2 libmarkermod4-3 libmarkermod4-4 \
+ tst-tls20mod-bad tst-tls21mod tst-dlmopen-dlerror-mod \
+ tst-auxvalmod \
+- tst-dlmopen-gethostbyname-mod \
++ tst-dlmopen-gethostbyname-mod tst-ro-dynamic-mod \
+
+ # Most modules build with _ISOMAC defined, but those filtered out
+ # depend on internal headers.
+@@ -399,8 +399,9 @@ endif
+ modules-execstack-yes = tst-execstack-mod
+ extra-test-objs += $(addsuffix .os,$(strip $(modules-names)))
+
+-# filtmod1.so, tst-big-note-lib.so have special rules.
+-modules-names-nobuild := filtmod1 tst-big-note-lib
++# filtmod1.so, tst-big-note-lib.so, tst-ro-dynamic-mod.so have special
++# rules.
++modules-names-nobuild := filtmod1 tst-big-note-lib tst-ro-dynamic-mod
+
+ tests += $(tests-static)
+
+@@ -1906,3 +1907,10 @@ $(objpfx)tst-getauxval-static.out: $(objpfx)tst-auxvalmod.so
+ tst-getauxval-static-ENV = LD_LIBRARY_PATH=$(objpfx):$(common-objpfx)
+
+ $(objpfx)tst-dlmopen-gethostbyname.out: $(objpfx)tst-dlmopen-gethostbyname-mod.so
++
++$(objpfx)tst-ro-dynamic: $(objpfx)tst-ro-dynamic-mod.so
++$(objpfx)tst-ro-dynamic-mod.so: $(objpfx)tst-ro-dynamic-mod.os \
++ tst-ro-dynamic-mod.map
++ $(LINK.o) -nostdlib -nostartfiles -shared -o $@ \
++ -Wl,--script=tst-ro-dynamic-mod.map \
++ $(objpfx)tst-ro-dynamic-mod.os
+diff --git a/elf/dl-close.c b/elf/dl-close.c
+index f39001cab9..cd7b9c9fe8 100644
+--- a/elf/dl-close.c
++++ b/elf/dl-close.c
+@@ -549,6 +549,9 @@ _dl_close_worker (struct link_map *map, bool force)
+ size_t tls_free_end;
+ tls_free_start = tls_free_end = NO_TLS_OFFSET;
+
++ /* Protects global and module specitic TLS state. */
++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
++
+ /* We modify the list of loaded objects. */
+ __rtld_lock_lock_recursive (GL(dl_load_write_lock));
+
+@@ -784,6 +787,9 @@ _dl_close_worker (struct link_map *map, bool force)
+ GL(dl_tls_static_used) = tls_free_start;
+ }
+
++ /* TLS is cleaned up for the unloaded modules. */
++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
++
+ #ifdef SHARED
+ /* Auditing checkpoint: we have deleted all objects. */
+ if (__glibc_unlikely (do_audit))
+diff --git a/elf/dl-load.c b/elf/dl-load.c
+index 650e4edc35..0976977fbd 100644
+--- a/elf/dl-load.c
++++ b/elf/dl-load.c
+@@ -1130,6 +1130,7 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
+ struct loadcmd loadcmds[l->l_phnum];
+ size_t nloadcmds = 0;
+ bool has_holes = false;
++ bool empty_dynamic = false;
+
+ /* The struct is initialized to zero so this is not necessary:
+ l->l_ld = 0;
+@@ -1142,13 +1143,16 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
+ segments are mapped in. We record the addresses it says
+ verbatim, and later correct for the run-time load address. */
+ case PT_DYNAMIC:
+- if (ph->p_filesz)
++ if (ph->p_filesz == 0)
++ empty_dynamic = true; /* Usually separate debuginfo. */
++ else
+ {
+ /* Debuginfo only files from "objcopy --only-keep-debug"
+ contain a PT_DYNAMIC segment with p_filesz == 0. Skip
+ such a segment to avoid a crash later. */
+ l->l_ld = (void *) ph->p_vaddr;
+ l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
++ l->l_ld_readonly = (ph->p_flags & PF_W) == 0;
+ }
+ break;
+
+@@ -1264,6 +1268,13 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
+ goto lose;
+ }
+
++ /* This check recognizes most separate debuginfo files. */
++ if (__glibc_unlikely ((l->l_ld == 0 && type == ET_DYN) || empty_dynamic))
++ {
++ errstring = N_("object file has no dynamic section");
++ goto lose;
++ }
++
+ /* Length of the sections to be loaded. */
+ maplength = loadcmds[nloadcmds - 1].allocend - loadcmds[0].mapstart;
+
+@@ -1281,18 +1292,10 @@ _dl_map_object_from_fd (const char *name, const char *origname, int fd,
+ }
+ }
+
+- if (l->l_ld == 0)
+- {
+- if (__glibc_unlikely (type == ET_DYN))
+- {
+- errstring = N_("object file has no dynamic section");
+- goto lose;
+- }
+- }
+- else
++ if (l->l_ld != 0)
+ l->l_ld = (ElfW(Dyn) *) ((ElfW(Addr)) l->l_ld + l->l_addr);
+
+- elf_get_dynamic_info (l, NULL);
++ elf_get_dynamic_info (l);
+
+ /* Make sure we are not dlopen'ing an object that has the
+ DF_1_NOOPEN flag set, or a PIE object. */
+diff --git a/elf/dl-open.c b/elf/dl-open.c
+index ec386626f9..bc68e2c376 100644
+--- a/elf/dl-open.c
++++ b/elf/dl-open.c
+@@ -66,6 +66,9 @@ struct dl_open_args
+ libc_map value in the namespace in case of a dlopen failure. */
+ bool libc_already_loaded;
+
++ /* Set to true if the end of dl_open_worker_begin was reached. */
++ bool worker_continue;
++
+ /* Original parameters to the program and the current environment. */
+ int argc;
+ char **argv;
+@@ -482,7 +485,7 @@ call_dl_init (void *closure)
+ }
+
+ static void
+-dl_open_worker (void *a)
++dl_open_worker_begin (void *a)
+ {
+ struct dl_open_args *args = a;
+ const char *file = args->file;
+@@ -774,6 +777,36 @@ dl_open_worker (void *a)
+ _dl_call_libc_early_init (libc_map, false);
+ }
+
++ args->worker_continue = true;
++}
++
++static void
++dl_open_worker (void *a)
++{
++ struct dl_open_args *args = a;
++
++ args->worker_continue = false;
++
++ {
++ /* Protects global and module specific TLS state. */
++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
++
++ struct dl_exception ex;
++ int err = _dl_catch_exception (&ex, dl_open_worker_begin, args);
++
++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
++
++ if (__glibc_unlikely (ex.errstring != NULL))
++ /* Reraise the error. */
++ _dl_signal_exception (err, &ex, NULL);
++ }
++
++ if (!args->worker_continue)
++ return;
++
++ int mode = args->mode;
++ struct link_map *new = args->map;
++
+ /* Run the initializer functions of new objects. Temporarily
+ disable the exception handler, so that lazy binding failures are
+ fatal. */
+@@ -886,7 +919,7 @@ no more namespaces available for dlmopen()"));
+ /* Avoid keeping around a dangling reference to the libc.so link
+ map in case it has been cached in libc_map. */
+ if (!args.libc_already_loaded)
+- GL(dl_ns)[nsid].libc_map = NULL;
++ GL(dl_ns)[args.nsid].libc_map = NULL;
+
+ /* Remove the object from memory. It may be in an inconsistent
+ state if relocation failed, for example. */
+diff --git a/elf/dl-reloc-static-pie.c b/elf/dl-reloc-static-pie.c
+index d5bd2f31e9..2fb02d7276 100644
+--- a/elf/dl-reloc-static-pie.c
++++ b/elf/dl-reloc-static-pie.c
+@@ -40,7 +40,17 @@ _dl_relocate_static_pie (void)
+
+ /* Read our own dynamic section and fill in the info array. */
+ main_map->l_ld = ((void *) main_map->l_addr + elf_machine_dynamic ());
+- elf_get_dynamic_info (main_map, NULL);
++
++ const ElfW(Phdr) *ph, *phdr = GL(dl_phdr);
++ size_t phnum = GL(dl_phnum);
++ for (ph = phdr; ph < &phdr[phnum]; ++ph)
++ if (ph->p_type == PT_DYNAMIC)
++ {
++ main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
++ break;
++ }
++
++ elf_get_dynamic_info (main_map);
+
+ # ifdef ELF_MACHINE_BEFORE_RTLD_RELOC
+ ELF_MACHINE_BEFORE_RTLD_RELOC (main_map->l_info);
+diff --git a/elf/dl-support.c b/elf/dl-support.c
+index 0155718175..d8c06ba7eb 100644
+--- a/elf/dl-support.c
++++ b/elf/dl-support.c
+@@ -229,6 +229,13 @@ __rtld_lock_define_initialized_recursive (, _dl_load_lock)
+ list of loaded objects while an object is added to or removed from
+ that list. */
+ __rtld_lock_define_initialized_recursive (, _dl_load_write_lock)
++ /* This lock protects global and module specific TLS related data.
++ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation),
++ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are
++ accessed and when TLS related relocations are processed for a
++ module. It was introduced to keep pthread_create accessing TLS
++ state that is being set up. */
++__rtld_lock_define_initialized_recursive (, _dl_load_tls_lock)
+
+
+ #ifdef HAVE_AUX_VECTOR
+diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
+index d47bef1340..2c684c2db2 100644
+--- a/elf/dl-sysdep.c
++++ b/elf/dl-sysdep.c
+@@ -317,7 +317,7 @@ _dl_show_auxv (void)
+ [AT_SYSINFO_EHDR - 2] = { "SYSINFO_EHDR: 0x", hex },
+ [AT_RANDOM - 2] = { "RANDOM: 0x", hex },
+ [AT_HWCAP2 - 2] = { "HWCAP2: 0x", hex },
+- [AT_MINSIGSTKSZ - 2] = { "MINSIGSTKSZ ", dec },
++ [AT_MINSIGSTKSZ - 2] = { "MINSIGSTKSZ: ", dec },
+ [AT_L1I_CACHESIZE - 2] = { "L1I_CACHESIZE: ", dec },
+ [AT_L1I_CACHEGEOMETRY - 2] = { "L1I_CACHEGEOMETRY: 0x", hex },
+ [AT_L1D_CACHESIZE - 2] = { "L1D_CACHESIZE: ", dec },
+diff --git a/elf/dl-tls.c b/elf/dl-tls.c
+index 423e380f7c..40263cf586 100644
+--- a/elf/dl-tls.c
++++ b/elf/dl-tls.c
+@@ -532,7 +532,7 @@ _dl_allocate_tls_init (void *result)
+ size_t maxgen = 0;
+
+ /* Protects global dynamic TLS related state. */
+- __rtld_lock_lock_recursive (GL(dl_load_lock));
++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
+
+ /* Check if the current dtv is big enough. */
+ if (dtv[-1].counter < GL(dl_tls_max_dtv_idx))
+@@ -606,7 +606,7 @@ _dl_allocate_tls_init (void *result)
+ listp = listp->next;
+ assert (listp != NULL);
+ }
+- __rtld_lock_unlock_recursive (GL(dl_load_lock));
++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+
+ /* The DTV version is up-to-date now. */
+ dtv[0].counter = maxgen;
+@@ -745,7 +745,7 @@ _dl_update_slotinfo (unsigned long int req_modid)
+
+ Here the dtv needs to be updated to new_gen generation count.
+
+- This code may be called during TLS access when GL(dl_load_lock)
++ This code may be called during TLS access when GL(dl_load_tls_lock)
+ is not held. In that case the user code has to synchronize with
+ dlopen and dlclose calls of relevant modules. A module m is
+ relevant if the generation of m <= new_gen and dlclose of m is
+@@ -867,11 +867,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
+ if (__glibc_unlikely (the_map->l_tls_offset
+ != FORCED_DYNAMIC_TLS_OFFSET))
+ {
+- __rtld_lock_lock_recursive (GL(dl_load_lock));
++ __rtld_lock_lock_recursive (GL(dl_load_tls_lock));
+ if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET))
+ {
+ the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET;
+- __rtld_lock_unlock_recursive (GL(dl_load_lock));
++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+ }
+ else if (__glibc_likely (the_map->l_tls_offset
+ != FORCED_DYNAMIC_TLS_OFFSET))
+@@ -883,7 +883,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
+ #else
+ # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
+ #endif
+- __rtld_lock_unlock_recursive (GL(dl_load_lock));
++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+
+ dtv[GET_ADDR_MODULE].pointer.to_free = NULL;
+ dtv[GET_ADDR_MODULE].pointer.val = p;
+@@ -891,7 +891,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
+ return (char *) p + GET_ADDR_OFFSET;
+ }
+ else
+- __rtld_lock_unlock_recursive (GL(dl_load_lock));
++ __rtld_lock_unlock_recursive (GL(dl_load_tls_lock));
+ }
+ struct dtv_pointer result = allocate_and_init (the_map);
+ dtv[GET_ADDR_MODULE].pointer = result;
+@@ -962,7 +962,7 @@ _dl_tls_get_addr_soft (struct link_map *l)
+ return NULL;
+
+ dtv_t *dtv = THREAD_DTV ();
+- /* This may be called without holding the GL(dl_load_lock). Reading
++ /* This may be called without holding the GL(dl_load_tls_lock). Reading
+ arbitrary gen value is fine since this is best effort code. */
+ size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
+ if (__glibc_unlikely (dtv[0].counter != gen))
+diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h
+index d8ec32377d..4aa2058abf 100644
+--- a/elf/get-dynamic-info.h
++++ b/elf/get-dynamic-info.h
+@@ -28,7 +28,7 @@ static
+ auto
+ #endif
+ inline void __attribute__ ((unused, always_inline))
+-elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
++elf_get_dynamic_info (struct link_map *l)
+ {
+ #if __ELF_NATIVE_CLASS == 32
+ typedef Elf32_Word d_tag_utype;
+@@ -69,28 +69,15 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
+ info[i] = dyn;
+ }
+
+-#define DL_RO_DYN_TEMP_CNT 8
+-
+-#ifndef DL_RO_DYN_SECTION
+ /* Don't adjust .dynamic unnecessarily. */
+- if (l->l_addr != 0)
++ if (l->l_addr != 0 && dl_relocate_ld (l))
+ {
+ ElfW(Addr) l_addr = l->l_addr;
+- int cnt = 0;
+
+ # define ADJUST_DYN_INFO(tag) \
+ do \
+ if (info[tag] != NULL) \
+- { \
+- if (temp) \
+- { \
+- temp[cnt].d_tag = info[tag]->d_tag; \
+- temp[cnt].d_un.d_ptr = info[tag]->d_un.d_ptr + l_addr; \
+- info[tag] = temp + cnt++; \
+- } \
+- else \
+- info[tag]->d_un.d_ptr += l_addr; \
+- } \
++ info[tag]->d_un.d_ptr += l_addr; \
+ while (0)
+
+ ADJUST_DYN_INFO (DT_HASH);
+@@ -107,9 +94,7 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp)
+ ADJUST_DYN_INFO (VERSYMIDX (DT_VERSYM));
+ ADJUST_DYN_INFO (ADDRIDX (DT_GNU_HASH));
+ # undef ADJUST_DYN_INFO
+- assert (cnt <= DL_RO_DYN_TEMP_CNT);
+ }
+-#endif
+ if (info[DT_PLTREL] != NULL)
+ {
+ #if ELF_MACHINE_NO_RELA
+diff --git a/elf/ldconfig.c b/elf/ldconfig.c
+index 1037e8d0cf..b8893637f8 100644
+--- a/elf/ldconfig.c
++++ b/elf/ldconfig.c
+@@ -503,7 +503,11 @@ add_dir_1 (const char *line, const char *from_file, int from_line)
+ entry->path[--i] = '\0';
+
+ if (i == 0)
+- return;
++ {
++ free (entry->path);
++ free (entry);
++ return;
++ }
+
+ char *path = entry->path;
+ if (opt_chroot != NULL)
+diff --git a/elf/rtld.c b/elf/rtld.c
+index d733359eaf..d83ac1bdc4 100644
+--- a/elf/rtld.c
++++ b/elf/rtld.c
+@@ -322,6 +322,7 @@ struct rtld_global _rtld_global =
+ #ifdef _LIBC_REENTRANT
+ ._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
+ ._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
++ ._dl_load_tls_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER,
+ #endif
+ ._dl_nns = 1,
+ ._dl_ns =
+@@ -463,6 +464,7 @@ _dl_start_final (void *arg, struct dl_start_final_info *info)
+ #ifndef DONT_USE_BOOTSTRAP_MAP
+ GL(dl_rtld_map).l_addr = info->l.l_addr;
+ GL(dl_rtld_map).l_ld = info->l.l_ld;
++ GL(dl_rtld_map).l_ld_readonly = info->l.l_ld_readonly;
+ memcpy (GL(dl_rtld_map).l_info, info->l.l_info,
+ sizeof GL(dl_rtld_map).l_info);
+ GL(dl_rtld_map).l_mach = info->l.l_mach;
+@@ -546,7 +548,8 @@ _dl_start (void *arg)
+
+ /* Read our own dynamic section and fill in the info array. */
+ bootstrap_map.l_ld = (void *) bootstrap_map.l_addr + elf_machine_dynamic ();
+- elf_get_dynamic_info (&bootstrap_map, NULL);
++ bootstrap_map.l_ld_readonly = DL_RO_DYN_SECTION;
++ elf_get_dynamic_info (&bootstrap_map);
+
+ #if NO_TLS_OFFSET != 0
+ bootstrap_map.l_tls_offset = NO_TLS_OFFSET;
+@@ -1468,6 +1471,7 @@ dl_main (const ElfW(Phdr) *phdr,
+ /* This tells us where to find the dynamic section,
+ which tells us everything we need to do. */
+ main_map->l_ld = (void *) main_map->l_addr + ph->p_vaddr;
++ main_map->l_ld_readonly = (ph->p_flags & PF_W) == 0;
+ break;
+ case PT_INTERP:
+ /* This "interpreter segment" was used by the program loader to
+@@ -1613,7 +1617,7 @@ dl_main (const ElfW(Phdr) *phdr,
+ if (! rtld_is_main)
+ {
+ /* Extract the contents of the dynamic section for easy access. */
+- elf_get_dynamic_info (main_map, NULL);
++ elf_get_dynamic_info (main_map);
+
+ /* If the main map is libc.so, update the base namespace to
+ refer to this map. If libc.so is loaded later, this happens
+diff --git a/elf/setup-vdso.h b/elf/setup-vdso.h
+index 86c491e49c..f44748bc98 100644
+--- a/elf/setup-vdso.h
++++ b/elf/setup-vdso.h
+@@ -33,8 +33,6 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
+ 0, LM_ID_BASE);
+ if (__glibc_likely (l != NULL))
+ {
+- static ElfW(Dyn) dyn_temp[DL_RO_DYN_TEMP_CNT] attribute_relro;
+-
+ l->l_phdr = ((const void *) GLRO(dl_sysinfo_dso)
+ + GLRO(dl_sysinfo_dso)->e_phoff);
+ l->l_phnum = GLRO(dl_sysinfo_dso)->e_phnum;
+@@ -45,6 +43,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
+ {
+ l->l_ld = (void *) ph->p_vaddr;
+ l->l_ldnum = ph->p_memsz / sizeof (ElfW(Dyn));
++ l->l_ld_readonly = (ph->p_flags & PF_W) == 0;
+ }
+ else if (ph->p_type == PT_LOAD)
+ {
+@@ -65,7 +64,7 @@ setup_vdso (struct link_map *main_map __attribute__ ((unused)),
+ l->l_map_end += l->l_addr;
+ l->l_text_end += l->l_addr;
+ l->l_ld = (void *) ((ElfW(Addr)) l->l_ld + l->l_addr);
+- elf_get_dynamic_info (l, dyn_temp);
++ elf_get_dynamic_info (l);
+ _dl_setup_hash (l);
+ l->l_relocated = 1;
+
+diff --git a/elf/tst-ro-dynamic-mod.c b/elf/tst-ro-dynamic-mod.c
+new file mode 100644
+index 0000000000..6d99925964
+--- /dev/null
++++ b/elf/tst-ro-dynamic-mod.c
+@@ -0,0 +1,19 @@
++/* Test case for DSO with readonly dynamic section.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++int foo = -1;
+diff --git a/elf/tst-ro-dynamic-mod.map b/elf/tst-ro-dynamic-mod.map
+new file mode 100644
+index 0000000000..2fe4a2998c
+--- /dev/null
++++ b/elf/tst-ro-dynamic-mod.map
+@@ -0,0 +1,16 @@
++SECTIONS
++{
++ . = SIZEOF_HEADERS;
++ .dynamic : { *(.dynamic) } :text :dynamic
++ .rodata : { *(.data*) *(.bss*) } :text
++ /DISCARD/ : {
++ *(.note.gnu.property)
++ }
++ .note : { *(.note.*) } :text :note
++}
++PHDRS
++{
++ text PT_LOAD FLAGS(5) FILEHDR PHDRS;
++ dynamic PT_DYNAMIC FLAGS(4);
++ note PT_NOTE FLAGS(4);
++}
+diff --git a/elf/tst-ro-dynamic.c b/elf/tst-ro-dynamic.c
+new file mode 100644
+index 0000000000..3a18f8789a
+--- /dev/null
++++ b/elf/tst-ro-dynamic.c
+@@ -0,0 +1,31 @@
++/* Test case for DSO with readonly dynamic section.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++#include <support/check.h>
++#include <support/test-driver.h>
++
++extern int foo;
++
++static int
++do_test (void)
++{
++ TEST_COMPARE (foo, -1);
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
+index 62bee28769..cc391d8f93 100644
+--- a/iconv/gconv_conf.c
++++ b/iconv/gconv_conf.c
+@@ -478,7 +478,7 @@ __gconv_read_conf (void)
+ __gconv_get_path ();
+
+ for (cnt = 0; __gconv_path_elem[cnt].name != NULL; ++cnt)
+- gconv_parseconfdir (__gconv_path_elem[cnt].name,
++ gconv_parseconfdir (NULL, __gconv_path_elem[cnt].name,
+ __gconv_path_elem[cnt].len);
+ #endif
+
+diff --git a/iconv/gconv_parseconfdir.h b/iconv/gconv_parseconfdir.h
+index a4153e54c6..a586268abc 100644
+--- a/iconv/gconv_parseconfdir.h
++++ b/iconv/gconv_parseconfdir.h
+@@ -39,7 +39,6 @@
+ /* Name of the file containing the module information in the directories
+ along the path. */
+ static const char gconv_conf_filename[] = "gconv-modules";
+-static const char gconv_conf_dirname[] = "gconv-modules.d";
+
+ static void add_alias (char *);
+ static void add_module (char *, const char *, size_t, int);
+@@ -110,19 +109,28 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len)
+ return true;
+ }
+
++/* Prefix DIR (with length DIR_LEN) with PREFIX if the latter is non-NULL and
++ parse configuration in it. */
++
+ static __always_inline bool
+-gconv_parseconfdir (const char *dir, size_t dir_len)
++gconv_parseconfdir (const char *prefix, const char *dir, size_t dir_len)
+ {
+- /* No slash needs to be inserted between dir and gconv_conf_filename;
+- dir already ends in a slash. */
+- char *buf = malloc (dir_len + sizeof (gconv_conf_dirname));
++ /* No slash needs to be inserted between dir and gconv_conf_filename; dir
++ already ends in a slash. The additional 2 is to accommodate the ".d"
++ when looking for configuration files in gconv-modules.d. */
++ size_t buflen = dir_len + sizeof (gconv_conf_filename) + 2;
++ char *buf = malloc (buflen + (prefix != NULL ? strlen (prefix) : 0));
++ char *cp = buf;
+ bool found = false;
+
+ if (buf == NULL)
+ return false;
+
+- char *cp = mempcpy (mempcpy (buf, dir, dir_len), gconv_conf_filename,
+- sizeof (gconv_conf_filename));
++ if (prefix != NULL)
++ cp = stpcpy (cp, prefix);
++
++ cp = mempcpy (mempcpy (cp, dir, dir_len), gconv_conf_filename,
++ sizeof (gconv_conf_filename));
+
+ /* Read the gconv-modules configuration file first. */
+ found = read_conf_file (buf, dir, dir_len);
+@@ -153,12 +161,11 @@ gconv_parseconfdir (const char *dir, size_t dir_len)
+ struct stat64 st;
+ if (asprintf (&conf, "%s/%s", buf, ent->d_name) < 0)
+ continue;
+- if (ent->d_type == DT_UNKNOWN
+- && (lstat64 (conf, &st) == -1
+- || !S_ISREG (st.st_mode)))
+- continue;
+
+- found |= read_conf_file (conf, dir, dir_len);
++ if (ent->d_type != DT_UNKNOWN
++ || (lstat64 (conf, &st) != -1 && S_ISREG (st.st_mode)))
++ found |= read_conf_file (conf, dir, dir_len);
++
+ free (conf);
+ }
+ }
+diff --git a/iconv/iconv_charmap.c b/iconv/iconv_charmap.c
+index e2d53fee3c..a8b6b56124 100644
+--- a/iconv/iconv_charmap.c
++++ b/iconv/iconv_charmap.c
+@@ -234,6 +234,8 @@ charmap_conversion (const char *from_code, struct charmap_t *from_charmap,
+ while (++remaining < argc);
+
+ /* All done. */
++ if (output != stdout)
++ fclose (output);
+ free_table (cvtbl);
+ return status;
+ }
+diff --git a/iconv/iconvconfig.c b/iconv/iconvconfig.c
+index 783b2bbdbb..273a71f673 100644
+--- a/iconv/iconvconfig.c
++++ b/iconv/iconvconfig.c
+@@ -653,13 +653,21 @@ add_module (char *rp, const char *directory,
+ static int
+ handle_dir (const char *dir)
+ {
++ char *newp = NULL;
+ size_t dirlen = strlen (dir);
+ bool found = false;
+
+- char *fulldir = xasprintf ("%s%s%s", dir[0] == '/' ? prefix : "",
+- dir, dir[dirlen - 1] != '/' ? "/" : "");
++ /* End directory path with a '/' if it doesn't already. */
++ if (dir[dirlen - 1] != '/')
++ {
++ newp = xmalloc (dirlen + 2);
++ memcpy (newp, dir, dirlen);
++ newp[dirlen++] = '/';
++ newp[dirlen] = '\0';
++ dir = newp;
++ }
+
+- found = gconv_parseconfdir (fulldir, strlen (fulldir));
++ found = gconv_parseconfdir (dir[0] == '/' ? prefix : NULL, dir, dirlen);
+
+ if (!found)
+ {
+@@ -671,7 +679,7 @@ handle_dir (const char *dir)
+ "configuration files with names ending in .conf.");
+ }
+
+- free (fulldir);
++ free (newp);
+
+ return found ? 0 : 1;
+ }
+diff --git a/iconvdata/Makefile b/iconvdata/Makefile
+index c216f959df..d5507a048c 100644
+--- a/iconvdata/Makefile
++++ b/iconvdata/Makefile
+@@ -1,4 +1,5 @@
+ # Copyright (C) 1997-2021 Free Software Foundation, Inc.
++# Copyright (C) The GNU Toolchain Authors.
+ # This file is part of the GNU C Library.
+
+ # The GNU C Library is free software; you can redistribute it and/or
+@@ -74,7 +75,7 @@ ifeq (yes,$(build-shared))
+ tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
+ tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
+ bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \
+- bug-iconv13 bug-iconv14
++ bug-iconv13 bug-iconv14 bug-iconv15
+ ifeq ($(have-thread-library),yes)
+ tests += bug-iconv3
+ endif
+@@ -327,6 +328,8 @@ $(objpfx)bug-iconv12.out: $(addprefix $(objpfx), $(gconv-modules)) \
+ $(addprefix $(objpfx),$(modules.so))
+ $(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \
+ $(addprefix $(objpfx),$(modules.so))
++$(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \
++ $(addprefix $(objpfx),$(modules.so))
+
+ $(objpfx)iconv-test.out: run-iconv-test.sh \
+ $(addprefix $(objpfx), $(gconv-modules)) \
+diff --git a/iconvdata/bug-iconv15.c b/iconvdata/bug-iconv15.c
+new file mode 100644
+index 0000000000..cc04bd0313
+--- /dev/null
++++ b/iconvdata/bug-iconv15.c
+@@ -0,0 +1,60 @@
++/* Bug 28524: Conversion from ISO-2022-JP-3 with iconv
++ may emit spurious NUL character on state reset.
++ Copyright (C) The GNU Toolchain Authors.
++ 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
++ <https://www.gnu.org/licenses/>. */
++
++#include <stddef.h>
++#include <iconv.h>
++#include <support/check.h>
++
++static int
++do_test (void)
++{
++ char in[] = "\x1b(I";
++ char *inbuf = in;
++ size_t inleft = sizeof (in) - 1;
++ char out[1];
++ char *outbuf = out;
++ size_t outleft = sizeof (out);
++ iconv_t cd;
++
++ cd = iconv_open ("UTF8", "ISO-2022-JP-3");
++ TEST_VERIFY_EXIT (cd != (iconv_t) -1);
++
++ /* First call to iconv should alter internal state.
++ Now, JISX0201_Kana_set is selected and
++ state value != ASCII_set. */
++ TEST_VERIFY (iconv (cd, &inbuf, &inleft, &outbuf, &outleft) != (size_t) -1);
++
++ /* No bytes should have been added to
++ the output buffer at this point. */
++ TEST_VERIFY (outbuf == out);
++ TEST_VERIFY (outleft == sizeof (out));
++
++ /* Second call shall emit spurious NUL character in unpatched glibc. */
++ TEST_VERIFY (iconv (cd, NULL, NULL, &outbuf, &outleft) != (size_t) -1);
++
++ /* No characters are expected to be produced. */
++ TEST_VERIFY (outbuf == out);
++ TEST_VERIFY (outleft == sizeof (out));
++
++ TEST_VERIFY_EXIT (iconv_close (cd) != -1);
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/iconvdata/iso-2022-jp-3.c b/iconvdata/iso-2022-jp-3.c
+index c8ba88cdc9..5fc0c0f739 100644
+--- a/iconvdata/iso-2022-jp-3.c
++++ b/iconvdata/iso-2022-jp-3.c
+@@ -1,5 +1,6 @@
+ /* Conversion module for ISO-2022-JP-3.
+ Copyright (C) 1998-2021 Free Software Foundation, Inc.
++ Copyright (C) The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998,
+ and Bruno Haible <bruno@clisp.org>, 2002.
+@@ -81,20 +82,31 @@ enum
+ the output state to the initial state. This has to be done during the
+ flushing. */
+ #define EMIT_SHIFT_TO_INIT \
+- if (data->__statep->__count != ASCII_set) \
++ if ((data->__statep->__count & ~7) != ASCII_set) \
+ { \
+ if (FROM_DIRECTION) \
+ { \
+- if (__glibc_likely (outbuf + 4 <= outend)) \
++ uint32_t ch = data->__statep->__count >> 6; \
++ \
++ if (__glibc_unlikely (ch != 0)) \
+ { \
+- /* Write out the last character. */ \
+- *((uint32_t *) outbuf) = data->__statep->__count >> 6; \
+- outbuf += sizeof (uint32_t); \
+- data->__statep->__count = ASCII_set; \
++ if (__glibc_likely (outbuf + 4 <= outend)) \
++ { \
++ /* Write out the last character. */ \
++ put32u (outbuf, ch); \
++ outbuf += 4; \
++ data->__statep->__count &= 7; \
++ data->__statep->__count |= ASCII_set; \
++ } \
++ else \
++ /* We don't have enough room in the output buffer. */ \
++ status = __GCONV_FULL_OUTPUT; \
+ } \
+ else \
+- /* We don't have enough room in the output buffer. */ \
+- status = __GCONV_FULL_OUTPUT; \
++ { \
++ data->__statep->__count &= 7; \
++ data->__statep->__count |= ASCII_set; \
++ } \
+ } \
+ else \
+ { \
+diff --git a/include/link.h b/include/link.h
+index 4af16cb596..c46aced9f7 100644
+--- a/include/link.h
++++ b/include/link.h
+@@ -205,6 +205,7 @@ struct link_map
+ unsigned int l_free_initfini:1; /* Nonzero if l_initfini can be
+ freed, ie. not allocated with
+ the dummy malloc in ld.so. */
++ unsigned int l_ld_readonly:1; /* Nonzero if dynamic section is readonly. */
+
+ /* NODELETE status of the map. Only valid for maps of type
+ lt_loaded. Lazy binding sets l_nodelete_active directly,
+@@ -342,6 +343,8 @@ struct link_map
+ unsigned long long int l_serial;
+ };
+
++#include <dl-relocate-ld.h>
++
+ /* Information used by audit modules. For most link maps, this data
+ immediate follows the link map in memory. For the dynamic linker,
+ it is allocated separately. See link_map_audit_state in
+diff --git a/include/sys/sysinfo.h b/include/sys/sysinfo.h
+index 7388356a19..c490561581 100644
+--- a/include/sys/sysinfo.h
++++ b/include/sys/sysinfo.h
+@@ -9,10 +9,15 @@
+ extern int __get_nprocs_conf (void);
+ libc_hidden_proto (__get_nprocs_conf)
+
+-/* Return number of available processors. */
++/* Return number of available processors (not all of them will be
++ available to the caller process). */
+ extern int __get_nprocs (void);
+ libc_hidden_proto (__get_nprocs)
+
++/* Return the number of available processors which the process can
++ be scheduled. */
++extern int __get_nprocs_sched (void) attribute_hidden;
++
+ /* Return number of physical pages of memory in the system. */
+ extern long int __get_phys_pages (void);
+ libc_hidden_proto (__get_phys_pages)
+diff --git a/io/fcntl.h b/io/fcntl.h
+index 8917a73b42..1c96f98f4d 100644
+--- a/io/fcntl.h
++++ b/io/fcntl.h
+@@ -187,10 +187,10 @@ extern int fcntl64 (int __fd, int __cmd, ...);
+ # endif
+ #else /* __USE_TIME_BITS64 */
+ # ifdef __REDIRECT
+-extern int __REDIRECT (fcntl, (int __fd, int __request, ...),
+- __fcntl_time64) __THROW;
+-extern int __REDIRECT (fcntl64, (int __fd, int __request, ...),
+- __fcntl_time64) __THROW;
++extern int __REDIRECT_NTH (fcntl, (int __fd, int __request, ...),
++ __fcntl_time64);
++extern int __REDIRECT_NTH (fcntl64, (int __fd, int __request, ...),
++ __fcntl_time64);
+ # else
+ extern int __fcntl_time64 (int __fd, int __request, ...) __THROW;
+ # define fcntl64 __fcntl_time64
+diff --git a/io/tst-closefrom.c b/io/tst-closefrom.c
+index d4c187073c..395ec0d894 100644
+--- a/io/tst-closefrom.c
++++ b/io/tst-closefrom.c
+@@ -24,31 +24,22 @@
+ #include <support/check.h>
+ #include <support/descriptors.h>
+ #include <support/xunistd.h>
++#include <support/support.h>
+
+ #include <array_length.h>
+
+ #define NFDS 100
+
+-static int
+-open_multiple_temp_files (void)
+-{
+- /* Check if the temporary file descriptor has no no gaps. */
+- int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
+- for (int i = 1; i <= NFDS; i++)
+- TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600), lowfd + i);
+- return lowfd;
+-}
+-
+ static int
+ closefrom_test (void)
+ {
+ struct support_descriptors *descrs = support_descriptors_list ();
+
+- int lowfd = open_multiple_temp_files ();
++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
+
+- const int maximum_fd = lowfd + NFDS;
++ const int maximum_fd = lowfd + NFDS - 1;
+ const int half_fd = lowfd + NFDS / 2;
+- const int gap = maximum_fd / 4;
++ const int gap = lowfd + NFDS / 4;
+
+ /* Close half of the descriptors and check result. */
+ closefrom (half_fd);
+@@ -58,7 +49,7 @@ closefrom_test (void)
+ TEST_COMPARE (fcntl (i, F_GETFL), -1);
+ TEST_COMPARE (errno, EBADF);
+ }
+- for (int i = 0; i < half_fd; i++)
++ for (int i = lowfd; i < half_fd; i++)
+ TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+ /* Create some gaps, close up to a threshold, and check result. */
+@@ -74,7 +65,7 @@ closefrom_test (void)
+ TEST_COMPARE (fcntl (i, F_GETFL), -1);
+ TEST_COMPARE (errno, EBADF);
+ }
+- for (int i = 0; i < gap; i++)
++ for (int i = lowfd; i < gap; i++)
+ TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+ /* Close the remmaining but the last one. */
+diff --git a/malloc/arena.c b/malloc/arena.c
+index 667484630e..f1f0af8648 100644
+--- a/malloc/arena.c
++++ b/malloc/arena.c
+@@ -879,7 +879,7 @@ arena_get2 (size_t size, mstate avoid_arena)
+ narenas_limit = mp_.arena_max;
+ else if (narenas > mp_.arena_test)
+ {
+- int n = __get_nprocs ();
++ int n = __get_nprocs_sched ();
+
+ if (n >= 1)
+ narenas_limit = NARENAS_FROM_NCORES (n);
+diff --git a/malloc/malloc-debug.c b/malloc/malloc-debug.c
+index 9922ef5f25..3d7e6d44fd 100644
+--- a/malloc/malloc-debug.c
++++ b/malloc/malloc-debug.c
+@@ -1,5 +1,6 @@
+ /* Malloc debug DSO.
+ Copyright (C) 2021 Free Software Foundation, Inc.
++ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -399,17 +400,17 @@ strong_alias (__debug_calloc, calloc)
+ size_t
+ malloc_usable_size (void *mem)
+ {
++ if (mem == NULL)
++ return 0;
++
+ if (__is_malloc_debug_enabled (MALLOC_MCHECK_HOOK))
+ return mcheck_usable_size (mem);
+ if (__is_malloc_debug_enabled (MALLOC_CHECK_HOOK))
+ return malloc_check_get_size (mem);
+
+- if (mem != NULL)
+- {
+- mchunkptr p = mem2chunk (mem);
+- if (DUMPED_MAIN_ARENA_CHUNK (p))
+- return chunksize (p) - SIZE_SZ;
+- }
++ mchunkptr p = mem2chunk (mem);
++ if (DUMPED_MAIN_ARENA_CHUNK (p))
++ return chunksize (p) - SIZE_SZ;
+
+ return musable (mem);
+ }
+diff --git a/malloc/malloc.c b/malloc/malloc.c
+index e065785af7..7882c70f0a 100644
+--- a/malloc/malloc.c
++++ b/malloc/malloc.c
+@@ -1,5 +1,6 @@
+ /* Malloc implementation for multiple threads without lock contention.
+ Copyright (C) 1996-2021 Free Software Foundation, Inc.
++ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+ Contributed by Wolfram Gloger <wg@malloc.de>
+ and Doug Lea <dl@cs.oswego.edu>, 2001.
+@@ -5009,20 +5010,13 @@ __malloc_trim (size_t s)
+ static size_t
+ musable (void *mem)
+ {
+- mchunkptr p;
+- if (mem != 0)
+- {
+- size_t result = 0;
+-
+- p = mem2chunk (mem);
++ mchunkptr p = mem2chunk (mem);
+
+- if (chunk_is_mmapped (p))
+- result = chunksize (p) - CHUNK_HDR_SZ;
+- else if (inuse (p))
+- result = memsize (p);
++ if (chunk_is_mmapped (p))
++ return chunksize (p) - CHUNK_HDR_SZ;
++ else if (inuse (p))
++ return memsize (p);
+
+- return result;
+- }
+ return 0;
+ }
+
+@@ -5030,10 +5024,9 @@ musable (void *mem)
+ size_t
+ __malloc_usable_size (void *m)
+ {
+- size_t result;
+-
+- result = musable (m);
+- return result;
++ if (m == NULL)
++ return 0;
++ return musable (m);
+ }
+ #endif
+
+diff --git a/malloc/tst-malloc-usable.c b/malloc/tst-malloc-usable.c
+index a1074b782a..b0d702be10 100644
+--- a/malloc/tst-malloc-usable.c
++++ b/malloc/tst-malloc-usable.c
+@@ -2,6 +2,7 @@
+ MALLOC_CHECK_ exported to a positive value.
+
+ Copyright (C) 2012-2021 Free Software Foundation, Inc.
++ Copyright The GNU Toolchain Authors.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+@@ -21,29 +22,24 @@
+ #include <malloc.h>
+ #include <string.h>
+ #include <stdio.h>
++#include <support/support.h>
++#include <support/check.h>
+
+ static int
+ do_test (void)
+ {
+ size_t usable_size;
+ void *p = malloc (7);
+- if (!p)
+- {
+- printf ("memory allocation failed\n");
+- return 1;
+- }
+
++ TEST_VERIFY_EXIT (p != NULL);
+ usable_size = malloc_usable_size (p);
+- if (usable_size != 7)
+- {
+- printf ("malloc_usable_size: expected 7 but got %zu\n", usable_size);
+- return 1;
+- }
+-
++ TEST_COMPARE (usable_size, 7);
+ memset (p, 0, usable_size);
+ free (p);
++
++ TEST_COMPARE (malloc_usable_size (NULL), 0);
++
+ return 0;
+ }
+
+-#define TEST_FUNCTION do_test ()
+-#include "../test-skeleton.c"
++#include "support/test-driver.c"
+diff --git a/misc/getsysstats.c b/misc/getsysstats.c
+index 0eedface6d..57d93601e2 100644
+--- a/misc/getsysstats.c
++++ b/misc/getsysstats.c
+@@ -45,6 +45,12 @@ weak_alias (__get_nprocs, get_nprocs)
+ link_warning (get_nprocs, "warning: get_nprocs will always return 1")
+
+
++int
++__get_nprocs_sched (void)
++{
++ return 1;
++}
++
+ long int
+ __get_phys_pages (void)
+ {
+diff --git a/misc/sys/ioctl.h b/misc/sys/ioctl.h
+index 6884d9925f..9945c1e918 100644
+--- a/misc/sys/ioctl.h
++++ b/misc/sys/ioctl.h
+@@ -42,8 +42,8 @@ __BEGIN_DECLS
+ extern int ioctl (int __fd, unsigned long int __request, ...) __THROW;
+ #else
+ # ifdef __REDIRECT
+-extern int __REDIRECT (ioctl, (int __fd, unsigned long int __request, ...),
+- __ioctl_time64) __THROW;
++extern int __REDIRECT_NTH (ioctl, (int __fd, unsigned long int __request, ...),
++ __ioctl_time64);
+ # else
+ extern int __ioctl_time64 (int __fd, unsigned long int __request, ...) __THROW;
+ # define ioctl __ioctl_time64
+diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
+index cfe37a3443..50065bc9bd 100644
+--- a/nptl/allocatestack.c
++++ b/nptl/allocatestack.c
+@@ -32,6 +32,7 @@
+ #include <futex-internal.h>
+ #include <kernel-features.h>
+ #include <nptl-stack.h>
++#include <libc-lock.h>
+
+ /* Default alignment of stack. */
+ #ifndef STACK_ALIGN
+@@ -127,6 +128,8 @@ get_cached_stack (size_t *sizep, void **memp)
+ /* No pending event. */
+ result->nextevent = NULL;
+
++ result->exiting = false;
++ __libc_lock_init (result->exit_lock);
+ result->tls_state = (struct tls_internal_t) { 0 };
+
+ /* Clear the DTV. */
+diff --git a/nptl/descr.h b/nptl/descr.h
+index c85778d449..4de84138fb 100644
+--- a/nptl/descr.h
++++ b/nptl/descr.h
+@@ -396,6 +396,12 @@ struct pthread
+ PTHREAD_CANCEL_ASYNCHRONOUS). */
+ unsigned char canceltype;
+
++ /* Used in __pthread_kill_internal to detected a thread that has
++ exited or is about to exit. exit_lock must only be acquired
++ after blocking signals. */
++ bool exiting;
++ int exit_lock; /* A low-level lock (for use with __libc_lock_init etc). */
++
+ /* Used on strsignal. */
+ struct tls_internal_t tls_state;
+
+diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c
+index cc25ff21f3..9bac6e3b76 100644
+--- a/nptl/pthread_cancel.c
++++ b/nptl/pthread_cancel.c
+@@ -62,10 +62,11 @@ __pthread_cancel (pthread_t th)
+ {
+ volatile struct pthread *pd = (volatile struct pthread *) th;
+
+- /* Make sure the descriptor is valid. */
+- if (INVALID_TD_P (pd))
+- /* Not a valid thread handle. */
+- return ESRCH;
++ if (pd->tid == 0)
++ /* The thread has already exited on the kernel side. Its outcome
++ (regular exit, other cancelation) has already been
++ determined. */
++ return 0;
+
+ static int init_sigcancel = 0;
+ if (atomic_load_relaxed (&init_sigcancel) == 0)
+diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
+index d8ec299cb1..3db0c9fdf4 100644
+--- a/nptl/pthread_create.c
++++ b/nptl/pthread_create.c
+@@ -37,6 +37,7 @@
+ #include <sys/single_threaded.h>
+ #include <version.h>
+ #include <clone_internal.h>
++#include <futex-internal.h>
+
+ #include <shlib-compat.h>
+
+@@ -406,8 +407,6 @@ start_thread (void *arg)
+ unwind_buf.priv.data.prev = NULL;
+ unwind_buf.priv.data.cleanup = NULL;
+
+- __libc_signal_restore_set (&pd->sigmask);
+-
+ /* Allow setxid from now onwards. */
+ if (__glibc_unlikely (atomic_exchange_acq (&pd->setxid_futex, 0) == -2))
+ futex_wake (&pd->setxid_futex, 1, FUTEX_PRIVATE);
+@@ -417,6 +416,8 @@ start_thread (void *arg)
+ /* Store the new cleanup handler info. */
+ THREAD_SETMEM (pd, cleanup_jmp_buf, &unwind_buf);
+
++ __libc_signal_restore_set (&pd->sigmask);
++
+ LIBC_PROBE (pthread_start, 3, (pthread_t) pd, pd->start_routine, pd->arg);
+
+ /* Run the code the user provided. */
+@@ -485,6 +486,27 @@ start_thread (void *arg)
+ /* This was the last thread. */
+ exit (0);
+
++ /* This prevents sending a signal from this thread to itself during
++ its final stages. This must come after the exit call above
++ because atexit handlers must not run with signals blocked.
++
++ Do not block SIGSETXID. The setxid handshake below expects the
++ signal to be delivered. (SIGSETXID cannot run application code,
++ nor does it use pthread_kill.) Reuse the pd->sigmask space for
++ computing the signal mask, to save stack space. */
++ __sigfillset (&pd->sigmask);
++ __sigdelset (&pd->sigmask, SIGSETXID);
++ INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &pd->sigmask, NULL,
++ __NSIG_BYTES);
++
++ /* Tell __pthread_kill_internal that this thread is about to exit.
++ If there is a __pthread_kill_internal in progress, this delays
++ the thread exit until the signal has been queued by the kernel
++ (so that the TID used to send it remains valid). */
++ __libc_lock_lock (pd->exit_lock);
++ pd->exiting = true;
++ __libc_lock_unlock (pd->exit_lock);
++
+ #ifndef __ASSUME_SET_ROBUST_LIST
+ /* If this thread has any robust mutexes locked, handle them now. */
+ # if __PTHREAD_MUTEX_HAVE_PREV
+diff --git a/nptl/pthread_kill.c b/nptl/pthread_kill.c
+index f79a2b26fc..35bf1f973e 100644
+--- a/nptl/pthread_kill.c
++++ b/nptl/pthread_kill.c
+@@ -16,39 +16,66 @@
+ License along with the GNU C Library; if not, see
+ <https://www.gnu.org/licenses/>. */
+
++#include <libc-lock.h>
+ #include <unistd.h>
+ #include <pthreadP.h>
+ #include <shlib-compat.h>
+
+-int
+-__pthread_kill_internal (pthread_t threadid, int signo)
++/* Sends SIGNO to THREADID. If the thread is about to exit or has
++ already exited on the kernel side, return NO_TID. Otherwise return
++ 0 or an error code. */
++static int
++__pthread_kill_implementation (pthread_t threadid, int signo, int no_tid)
+ {
+- pid_t tid;
+ struct pthread *pd = (struct pthread *) threadid;
+-
+ if (pd == THREAD_SELF)
+- /* It is a special case to handle raise() implementation after a vfork
+- call (which does not update the PD tid field). */
+- tid = INLINE_SYSCALL_CALL (gettid);
+- else
+- /* Force load of pd->tid into local variable or register. Otherwise
+- if a thread exits between ESRCH test and tgkill, we might return
+- EINVAL, because pd->tid would be cleared by the kernel. */
+- tid = atomic_forced_read (pd->tid);
+-
+- int val;
+- if (__glibc_likely (tid > 0))
+ {
+- pid_t pid = __getpid ();
+-
+- val = INTERNAL_SYSCALL_CALL (tgkill, pid, tid, signo);
+- val = (INTERNAL_SYSCALL_ERROR_P (val)
+- ? INTERNAL_SYSCALL_ERRNO (val) : 0);
++ /* Use the actual TID from the kernel, so that it refers to the
++ current thread even if called after vfork. There is no
++ signal blocking in this case, so that the signal is delivered
++ immediately, before __pthread_kill_internal returns: a signal
++ sent to the thread itself needs to be delivered
++ synchronously. (It is unclear if Linux guarantees the
++ delivery of all pending signals after unblocking in the code
++ below. POSIX only guarantees delivery of a single signal,
++ which may not be the right one.) */
++ pid_t tid = INTERNAL_SYSCALL_CALL (gettid);
++ int ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), tid, signo);
++ return INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
+ }
++
++ /* Block all signals, as required by pd->exit_lock. */
++ sigset_t old_mask;
++ __libc_signal_block_all (&old_mask);
++ __libc_lock_lock (pd->exit_lock);
++
++ int ret;
++ if (pd->exiting)
++ /* The thread is about to exit (or has exited). Sending the
++ signal is either not observable (the target thread has already
++ blocked signals at this point), or it will fail, or it might be
++ delivered to a new, unrelated thread that has reused the TID.
++ So do not actually send the signal. */
++ ret = no_tid;
+ else
+- val = ESRCH;
++ {
++ ret = INTERNAL_SYSCALL_CALL (tgkill, __getpid (), pd->tid, signo);
++ ret = INTERNAL_SYSCALL_ERROR_P (ret) ? INTERNAL_SYSCALL_ERRNO (ret) : 0;
++ }
++
++ __libc_lock_unlock (pd->exit_lock);
++ __libc_signal_restore_set (&old_mask);
+
+- return val;
++ return ret;
++}
++
++int
++__pthread_kill_internal (pthread_t threadid, int signo)
++{
++ /* Do not report an error in the no-tid case because the threadid
++ argument is still valid (the thread ID lifetime has not ended),
++ and ESRCH (for example) would be misleading. */
++ return __pthread_kill_implementation (threadid, signo, 0);
+ }
+
+ int
+@@ -61,6 +88,7 @@ __pthread_kill (pthread_t threadid, int signo)
+
+ return __pthread_kill_internal (threadid, signo);
+ }
++
+ /* Some architectures (for instance arm) might pull raise through libgcc, so
+ avoid the symbol version if it ends up being used on ld.so. */
+ #if !IS_IN(rtld)
+@@ -68,6 +96,17 @@ libc_hidden_def (__pthread_kill)
+ versioned_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_34);
+
+ # if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34)
+-compat_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_0);
++/* Variant which returns ESRCH in the no-TID case, for backwards
++ compatibility. */
++int
++attribute_compat_text_section
++__pthread_kill_esrch (pthread_t threadid, int signo)
++{
++ if (__is_internal_signal (signo))
++ return EINVAL;
++
++ return __pthread_kill_implementation (threadid, signo, ESRCH);
++}
++compat_symbol (libc, __pthread_kill_esrch, pthread_kill, GLIBC_2_0);
+ # endif
+ #endif
+diff --git a/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf b/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf
+new file mode 100644
+index 0000000000..5b0c6a4199
+--- /dev/null
++++ b/nss/tst-nss-files-hosts-long.root/etc/nsswitch.conf
+@@ -0,0 +1 @@
++hosts: files
+diff --git a/posix/Makefile b/posix/Makefile
+index 059efb3cd2..09460a28e8 100644
+--- a/posix/Makefile
++++ b/posix/Makefile
+@@ -107,7 +107,8 @@ tests := test-errno tstgetopt testfnm runtests runptests \
+ tst-sysconf-empty-chroot tst-glob_symlinks tst-fexecve \
+ tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \
+ bug-regex38 tst-regcomp-truncated tst-spawn-chdir \
+- tst-wordexp-nocmd tst-execveat tst-spawn5
++ tst-wordexp-nocmd tst-execveat tst-spawn5 \
++ tst-sched_getaffinity
+
+ # Test for the glob symbol version that was replaced in glibc 2.27.
+ ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes)
+diff --git a/posix/bits/unistd.h b/posix/bits/unistd.h
+index f0831386c7..622adeb2b2 100644
+--- a/posix/bits/unistd.h
++++ b/posix/bits/unistd.h
+@@ -199,10 +199,9 @@ __NTH (readlinkat (int __fd, const char *__restrict __path,
+ #endif
+
+ extern char *__getcwd_chk (char *__buf, size_t __size, size_t __buflen)
+- __THROW __wur __attr_access ((__write_only__, 1, 2));
++ __THROW __wur;
+ extern char *__REDIRECT_NTH (__getcwd_alias,
+- (char *__buf, size_t __size), getcwd)
+- __wur __attr_access ((__write_only__, 1, 2));
++ (char *__buf, size_t __size), getcwd) __wur;
+ extern char *__REDIRECT_NTH (__getcwd_chk_warn,
+ (char *__buf, size_t __size, size_t __buflen),
+ __getcwd_chk)
+diff --git a/posix/fork.c b/posix/fork.c
+index c471f7b15f..021691b9b7 100644
+--- a/posix/fork.c
++++ b/posix/fork.c
+@@ -99,6 +99,9 @@ __libc_fork (void)
+ /* Reset the lock the dynamic loader uses to protect its data. */
+ __rtld_lock_initialize (GL(dl_load_lock));
+
++ /* Reset the lock protecting dynamic TLS related data. */
++ __rtld_lock_initialize (GL(dl_load_tls_lock));
++
+ reclaim_stacks ();
+
+ /* Run the handlers registered for the child. */
+diff --git a/posix/tst-sched_getaffinity.c b/posix/tst-sched_getaffinity.c
+new file mode 100644
+index 0000000000..db9d517a96
+--- /dev/null
++++ b/posix/tst-sched_getaffinity.c
+@@ -0,0 +1,48 @@
++/* Tests for sched_getaffinity with large buffers.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++#include <array_length.h>
++#include <sched.h>
++#include <support/check.h>
++
++/* NB: this test may fail on system with more than 32k cpus. */
++
++static int
++do_test (void)
++{
++ /* The values are larger than the default cpu_set_t. */
++ const int bufsize[] = { 1<<11, 1<<12, 1<<13, 1<<14, 1<<15, 1<<16, 1<<17 };
++ int cpucount[array_length (bufsize)];
++
++ for (int i = 0; i < array_length (bufsize); i++)
++ {
++ cpu_set_t *cpuset = CPU_ALLOC (bufsize[i]);
++ TEST_VERIFY (cpuset != NULL);
++ size_t size = CPU_ALLOC_SIZE (bufsize[i]);
++ TEST_COMPARE (sched_getaffinity (0, size, cpuset), 0);
++ cpucount[i] = CPU_COUNT_S (size, cpuset);
++ CPU_FREE (cpuset);
++ }
++
++ for (int i = 0; i < array_length (cpucount) - 1; i++)
++ TEST_COMPARE (cpucount[i], cpucount[i + 1]);
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/posix/tst-spawn5.c b/posix/tst-spawn5.c
+index ac66738004..a95199af6b 100644
+--- a/posix/tst-spawn5.c
++++ b/posix/tst-spawn5.c
+@@ -47,17 +47,6 @@ static int initial_argv_count;
+
+ #define NFDS 100
+
+-static int
+-open_multiple_temp_files (void)
+-{
+- /* Check if the temporary file descriptor has no no gaps. */
+- int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
+- for (int i = 1; i <= NFDS; i++)
+- TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600),
+- lowfd + i);
+- return lowfd;
+-}
+-
+ static int
+ parse_fd (const char *str)
+ {
+@@ -185,7 +174,7 @@ spawn_closefrom_test (posix_spawn_file_actions_t *fa, int lowfd, int highfd,
+ static void
+ do_test_closefrom (void)
+ {
+- int lowfd = open_multiple_temp_files ();
++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
+ const int half_fd = lowfd + NFDS / 2;
+
+ /* Close half of the descriptors and check result. */
+diff --git a/posix/unistd.h b/posix/unistd.h
+index 3dca65732f..8224c5fbc9 100644
+--- a/posix/unistd.h
++++ b/posix/unistd.h
+@@ -528,8 +528,7 @@ extern int fchdir (int __fd) __THROW __wur;
+ an array is allocated with `malloc'; the array is SIZE
+ bytes long, unless SIZE == 0, in which case it is as
+ big as necessary. */
+-extern char *getcwd (char *__buf, size_t __size) __THROW __wur
+- __attr_access ((__write_only__, 1, 2));
++extern char *getcwd (char *__buf, size_t __size) __THROW __wur;
+
+ #ifdef __USE_GNU
+ /* Return a malloc'd string containing the current directory name.
+diff --git a/rt/Makefile b/rt/Makefile
+index 113cea03a5..910e775995 100644
+--- a/rt/Makefile
++++ b/rt/Makefile
+@@ -74,6 +74,7 @@ tests := tst-shm tst-timer tst-timer2 \
+ tst-aio7 tst-aio8 tst-aio9 tst-aio10 \
+ tst-mqueue1 tst-mqueue2 tst-mqueue3 tst-mqueue4 \
+ tst-mqueue5 tst-mqueue6 tst-mqueue7 tst-mqueue8 tst-mqueue9 \
++ tst-bz28213 \
+ tst-timer3 tst-timer4 tst-timer5 \
+ tst-cpuclock2 tst-cputimer1 tst-cputimer2 tst-cputimer3 \
+ tst-shm-cancel \
+diff --git a/rt/tst-bz28213.c b/rt/tst-bz28213.c
+new file mode 100644
+index 0000000000..0c096b5a0a
+--- /dev/null
++++ b/rt/tst-bz28213.c
+@@ -0,0 +1,101 @@
++/* Bug 28213: test for NULL pointer dereference in mq_notify.
++ Copyright (C) The GNU Toolchain Authors.
++ 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
++ <https://www.gnu.org/licenses/>. */
++
++#include <errno.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <unistd.h>
++#include <mqueue.h>
++#include <signal.h>
++#include <stdlib.h>
++#include <string.h>
++#include <support/check.h>
++
++static mqd_t m = -1;
++static const char msg[] = "hello";
++
++static void
++check_bz28213_cb (union sigval sv)
++{
++ char buf[sizeof (msg)];
++
++ (void) sv;
++
++ TEST_VERIFY_EXIT ((size_t) mq_receive (m, buf, sizeof (buf), NULL)
++ == sizeof (buf));
++ TEST_VERIFY_EXIT (memcmp (buf, msg, sizeof (buf)) == 0);
++
++ exit (0);
++}
++
++static void
++check_bz28213 (void)
++{
++ struct sigevent sev;
++
++ memset (&sev, '\0', sizeof (sev));
++ sev.sigev_notify = SIGEV_THREAD;
++ sev.sigev_notify_function = check_bz28213_cb;
++
++ /* Step 1: Register & unregister notifier.
++ Helper thread should receive NOTIFY_REMOVED notification.
++ In a vulnerable version of glibc, NULL pointer dereference follows. */
++ TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0);
++ TEST_VERIFY_EXIT (mq_notify (m, NULL) == 0);
++
++ /* Step 2: Once again, register notification.
++ Try to send one message.
++ Test is considered successful, if the callback does exit (0). */
++ TEST_VERIFY_EXIT (mq_notify (m, &sev) == 0);
++ TEST_VERIFY_EXIT (mq_send (m, msg, sizeof (msg), 1) == 0);
++
++ /* Wait... */
++ pause ();
++}
++
++static int
++do_test (void)
++{
++ static const char m_name[] = "/bz28213_queue";
++ struct mq_attr m_attr;
++
++ memset (&m_attr, '\0', sizeof (m_attr));
++ m_attr.mq_maxmsg = 1;
++ m_attr.mq_msgsize = sizeof (msg);
++
++ m = mq_open (m_name,
++ O_RDWR | O_CREAT | O_EXCL,
++ 0600,
++ &m_attr);
++
++ if (m < 0)
++ {
++ if (errno == ENOSYS)
++ FAIL_UNSUPPORTED ("POSIX message queues are not implemented\n");
++ FAIL_EXIT1 ("Failed to create POSIX message queue: %m\n");
++ }
++
++ TEST_VERIFY_EXIT (mq_unlink (m_name) == 0);
++
++ check_bz28213 ();
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/scripts/build-many-glibcs.py b/scripts/build-many-glibcs.py
+index 5a77af90a6..86537fa800 100755
+--- a/scripts/build-many-glibcs.py
++++ b/scripts/build-many-glibcs.py
+@@ -782,7 +782,7 @@ class Context(object):
+ 'gcc': 'vcs-11',
+ 'glibc': 'vcs-mainline',
+ 'gmp': '6.2.1',
+- 'linux': '5.13',
++ 'linux': '5.14',
+ 'mpc': '1.2.1',
+ 'mpfr': '4.1.0',
+ 'mig': 'vcs-mainline',
+diff --git a/support/Makefile b/support/Makefile
+index a462781718..2a0731796f 100644
+--- a/support/Makefile
++++ b/support/Makefile
+@@ -66,6 +66,7 @@ libsupport-routines = \
+ support_path_support_time64 \
+ support_process_state \
+ support_ptrace \
++ support-open-dev-null-range \
+ support_openpty \
+ support_paths \
+ support_quote_blob \
+@@ -82,9 +83,10 @@ libsupport-routines = \
+ support_test_compare_blob \
+ support_test_compare_failure \
+ support_test_compare_string \
+- support_write_file_string \
+ support_test_main \
+ support_test_verify_impl \
++ support_wait_for_thread_exit \
++ support_write_file_string \
+ temp_file \
+ timespec \
+ timespec-time64 \
+@@ -264,6 +266,7 @@ tests = \
+ tst-support_capture_subprocess \
+ tst-support_descriptors \
+ tst-support_format_dns_packet \
++ tst-support-open-dev-null-range \
+ tst-support-process_state \
+ tst-support_quote_blob \
+ tst-support_quote_string \
+diff --git a/support/support-open-dev-null-range.c b/support/support-open-dev-null-range.c
+new file mode 100644
+index 0000000000..66a8504105
+--- /dev/null
++++ b/support/support-open-dev-null-range.c
+@@ -0,0 +1,134 @@
++/* Return a range of open file descriptors.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++#include <errno.h>
++#include <fcntl.h>
++#include <support/support.h>
++#include <support/check.h>
++#include <support/xunistd.h>
++#include <stdlib.h>
++#include <sys/resource.h>
++
++static void
++increase_nofile (void)
++{
++ struct rlimit rl;
++ if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
++ FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
++
++ rl.rlim_cur += 128;
++
++ if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
++ FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
++}
++
++static int
++open_dev_null (int flags, mode_t mode)
++{
++ int fd = open64 ("/dev/null", flags, mode);
++ if (fd >= 0)
++ return fd;
++
++ if (fd < 0 && errno != EMFILE)
++ FAIL_EXIT1 ("open64 (\"/dev/null\", 0x%x, 0%o): %m", flags, mode);
++
++ increase_nofile ();
++
++ return xopen ("/dev/null", flags, mode);
++}
++
++struct range
++{
++ int lowfd;
++ size_t len;
++};
++
++struct range_list
++{
++ size_t total;
++ size_t used;
++ struct range *ranges;
++};
++
++static void
++range_init (struct range_list *r)
++{
++ r->total = 8;
++ r->used = 0;
++ r->ranges = xmalloc (r->total * sizeof (struct range));
++}
++
++static void
++range_add (struct range_list *r, int lowfd, size_t len)
++{
++ if (r->used == r->total)
++ {
++ r->total *= 2;
++ r->ranges = xrealloc (r->ranges, r->total * sizeof (struct range));
++ }
++ r->ranges[r->used].lowfd = lowfd;
++ r->ranges[r->used].len = len;
++ r->used++;
++}
++
++static void
++range_close (struct range_list *r)
++{
++ for (size_t i = 0; i < r->used; i++)
++ {
++ int minfd = r->ranges[i].lowfd;
++ int maxfd = r->ranges[i].lowfd + r->ranges[i].len;
++ for (int fd = minfd; fd < maxfd; fd++)
++ xclose (fd);
++ }
++ free (r->ranges);
++}
++
++int
++support_open_dev_null_range (int num, int flags, mode_t mode)
++{
++ /* We keep track of the ranges that hit an already opened descriptor, so
++ we close them after we get a working range. */
++ struct range_list rl;
++ range_init (&rl);
++
++ int lowfd = open_dev_null (flags, mode);
++ int prevfd = lowfd;
++ while (true)
++ {
++ int i = 1;
++ for (; i < num; i++)
++ {
++ int fd = open_dev_null (flags, mode);
++ if (fd != lowfd + i)
++ {
++ range_add (&rl, lowfd, prevfd - lowfd + 1);
++
++ prevfd = lowfd = fd;
++ break;
++ }
++ prevfd = fd;
++ }
++ if (i == num)
++ break;
++ }
++
++ range_close (&rl);
++
++ return lowfd;
++}
+diff --git a/support/support.h b/support/support.h
+index 834dba9097..c219e0d9d1 100644
+--- a/support/support.h
++++ b/support/support.h
+@@ -174,6 +174,10 @@ timer_t support_create_timer (uint64_t sec, long int nsec, bool repeat,
+ /* Disable the timer TIMER. */
+ void support_delete_timer (timer_t timer);
+
++/* Wait until all threads except the current thread have exited (as
++ far as the kernel is concerned). */
++void support_wait_for_thread_exit (void);
++
+ struct support_stack
+ {
+ void *stack;
+@@ -193,6 +197,14 @@ struct support_stack support_stack_alloc (size_t size);
+ /* Deallocate the STACK. */
+ void support_stack_free (struct support_stack *stack);
+
++
++/* Create a range of NUM opened '/dev/null' file descriptors using FLAGS and
++ MODE. The function takes care of restarting the open range if a file
++ descriptor is found within the specified range and also increases
++ RLIMIT_NOFILE if required.
++ The returned value is the lowest file descriptor number. */
++int support_open_dev_null_range (int num, int flags, mode_t mode);
++
+ __END_DECLS
+
+ #endif /* SUPPORT_H */
+diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c
+index 27bfd19c93..0bacf6dbc2 100644
+--- a/support/support_capture_subprocess.c
++++ b/support/support_capture_subprocess.c
+@@ -170,6 +170,7 @@ copy_and_spawn_sgid (char *child_id, gid_t gid)
+ support_subprogram because we only want the program exit status, not the
+ contents. */
+ ret = 0;
++ infd = outfd = -1;
+
+ char * const args[] = {execname, child_id, NULL};
+
+diff --git a/support/support_wait_for_thread_exit.c b/support/support_wait_for_thread_exit.c
+new file mode 100644
+index 0000000000..5e3be421a7
+--- /dev/null
++++ b/support/support_wait_for_thread_exit.c
+@@ -0,0 +1,75 @@
++/* Wait until all threads except the current thread has exited.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++#include <dirent.h>
++#include <errno.h>
++#include <string.h>
++#include <support/check.h>
++#include <support/support.h>
++#include <unistd.h>
++
++void
++support_wait_for_thread_exit (void)
++{
++#ifdef __linux__
++ DIR *proc_self_task = opendir ("/proc/self/task");
++ TEST_VERIFY_EXIT (proc_self_task != NULL);
++
++ while (true)
++ {
++ errno = 0;
++ struct dirent *e = readdir (proc_self_task);
++ if (e == NULL && errno != 0)
++ FAIL_EXIT1 ("readdir: %m");
++ if (e == NULL)
++ {
++ /* Only the main thread remains. Testing may continue. */
++ closedir (proc_self_task);
++ return;
++ }
++
++ /* In some kernels, "0" entries denote a thread that has just
++ exited. */
++ if (strcmp (e->d_name, ".") == 0 || strcmp (e->d_name, "..") == 0
++ || strcmp (e->d_name, "0") == 0)
++ continue;
++
++ int task_tid = atoi (e->d_name);
++ if (task_tid <= 0)
++ FAIL_EXIT1 ("Invalid /proc/self/task entry: %s", e->d_name);
++
++ if (task_tid == gettid ())
++ /* The current thread. Keep scanning for other
++ threads. */
++ continue;
++
++ /* task_tid does not refer to this thread here, i.e., there is
++ another running thread. */
++
++ /* Small timeout to give the thread a chance to exit. */
++ usleep (50 * 1000);
++
++ /* Start scanning the directory from the start. */
++ rewinddir (proc_self_task);
++ }
++#else
++ /* Use a large timeout because we cannot verify that the thread has
++ exited. */
++ usleep (5 * 1000 * 1000);
++#endif
++}
+diff --git a/support/tst-support-open-dev-null-range.c b/support/tst-support-open-dev-null-range.c
+new file mode 100644
+index 0000000000..8e29def1ce
+--- /dev/null
++++ b/support/tst-support-open-dev-null-range.c
+@@ -0,0 +1,155 @@
++/* Tests for support_open_dev_null_range.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++#include <errno.h>
++#include <dirent.h>
++#include <fcntl.h>
++#include <limits.h>
++#include <support/check.h>
++#include <support/support.h>
++#include <support/xunistd.h>
++#include <sys/resource.h>
++#include <stdlib.h>
++
++#ifndef PATH_MAX
++# define PATH_MAX 1024
++#endif
++
++#include <stdio.h>
++
++static void
++check_path (int fd)
++{
++ char *proc_fd_path = xasprintf ("/proc/self/fd/%d", fd);
++ char file_path[PATH_MAX];
++ ssize_t file_path_length
++ = readlink (proc_fd_path, file_path, sizeof (file_path));
++ free (proc_fd_path);
++ if (file_path_length < 0)
++ FAIL_EXIT1 ("readlink (%s, %p, %zu)", proc_fd_path, file_path,
++ sizeof (file_path));
++ file_path[file_path_length] = '\0';
++ TEST_COMPARE_STRING (file_path, "/dev/null");
++}
++
++static int
++number_of_opened_files (void)
++{
++ DIR *fds = opendir ("/proc/self/fd");
++ if (fds == NULL)
++ FAIL_EXIT1 ("opendir (\"/proc/self/fd\"): %m");
++
++ int r = 0;
++ while (true)
++ {
++ errno = 0;
++ struct dirent64 *e = readdir64 (fds);
++ if (e == NULL)
++ {
++ if (errno != 0)
++ FAIL_EXIT1 ("readdir: %m");
++ break;
++ }
++
++ if (e->d_name[0] == '.')
++ continue;
++
++ char *endptr;
++ long int fd = strtol (e->d_name, &endptr, 10);
++ if (*endptr != '\0' || fd < 0 || fd > INT_MAX)
++ FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s",
++ e->d_name);
++
++ /* Skip the descriptor which is used to enumerate the
++ descriptors. */
++ if (fd == dirfd (fds))
++ continue;
++
++ r = r + 1;
++ }
++
++ closedir (fds);
++
++ return r;
++}
++
++static int
++do_test (void)
++{
++ const int nfds1 = 8;
++ int lowfd = support_open_dev_null_range (nfds1, O_RDONLY, 0600);
++ for (int i = 0; i < nfds1; i++)
++ {
++ TEST_VERIFY (fcntl (lowfd + i, F_GETFL) > -1);
++ check_path (lowfd + i);
++ }
++
++ /* create some gaps. */
++ xclose (lowfd + 1);
++ xclose (lowfd + 5);
++ xclose (lowfd + 6);
++
++ const int nfds2 = 16;
++ int lowfd2 = support_open_dev_null_range (nfds2, O_RDONLY, 0600);
++ for (int i = 0; i < nfds2; i++)
++ {
++ TEST_VERIFY (fcntl (lowfd2 + i, F_GETFL) > -1);
++ check_path (lowfd2 + i);
++ }
++
++ /* Decrease the maximum number of files. */
++ {
++ struct rlimit rl;
++ if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
++ FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
++
++ rl.rlim_cur = number_of_opened_files ();
++
++ if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
++ FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
++ }
++
++ const int nfds3 = 16;
++ int lowfd3 = support_open_dev_null_range (nfds3, O_RDONLY, 0600);
++ for (int i = 0; i < nfds3; i++)
++ {
++ TEST_VERIFY (fcntl (lowfd3 + i, F_GETFL) > -1);
++ check_path (lowfd3 + i);
++ }
++
++ /* create a lot of gaps to trigger the range extension. */
++ xclose (lowfd3 + 1);
++ xclose (lowfd3 + 3);
++ xclose (lowfd3 + 5);
++ xclose (lowfd3 + 7);
++ xclose (lowfd3 + 9);
++ xclose (lowfd3 + 11);
++ xclose (lowfd3 + 13);
++
++ const int nfds4 = 16;
++ int lowfd4 = support_open_dev_null_range (nfds4, O_RDONLY, 0600);
++ for (int i = 0; i < nfds4; i++)
++ {
++ TEST_VERIFY (fcntl (lowfd4 + i, F_GETFL) > -1);
++ check_path (lowfd4 + i);
++ }
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/sysdeps/generic/dl-relocate-ld.h b/sysdeps/generic/dl-relocate-ld.h
+new file mode 100644
+index 0000000000..cfb86c2d6a
+--- /dev/null
++++ b/sysdeps/generic/dl-relocate-ld.h
+@@ -0,0 +1,25 @@
++/* Check if dynamic section should be relocated. Generic version.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++#ifndef _DL_RELOCATE_LD_H
++#define _DL_RELOCATE_LD_H
++
++/* The dynamic section is writable. */
++#define DL_RO_DYN_SECTION 0
++
++#endif /* _DL_RELOCATE_LD_H */
+diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h
+index 9c15259236..fcbbf69748 100644
+--- a/sysdeps/generic/ldsodefs.h
++++ b/sysdeps/generic/ldsodefs.h
+@@ -69,17 +69,24 @@ __BEGIN_DECLS
+ `ElfW(TYPE)' is used in place of `Elf32_TYPE' or `Elf64_TYPE'. */
+ #define ELFW(type) _ElfW (ELF, __ELF_NATIVE_CLASS, type)
+
++/* Return true if dynamic section in the shared library L should be
++ relocated. */
++
++static inline bool
++dl_relocate_ld (const struct link_map *l)
++{
++ /* Don't relocate dynamic section if it is readonly */
++ return !(l->l_ld_readonly || DL_RO_DYN_SECTION);
++}
++
+ /* All references to the value of l_info[DT_PLTGOT],
+ l_info[DT_STRTAB], l_info[DT_SYMTAB], l_info[DT_RELA],
+ l_info[DT_REL], l_info[DT_JMPREL], and l_info[VERSYMIDX (DT_VERSYM)]
+ have to be accessed via the D_PTR macro. The macro is needed since for
+ most architectures the entry is already relocated - but for some not
+ and we need to relocate at access time. */
+-#ifdef DL_RO_DYN_SECTION
+-# define D_PTR(map, i) ((map)->i->d_un.d_ptr + (map)->l_addr)
+-#else
+-# define D_PTR(map, i) (map)->i->d_un.d_ptr
+-#endif
++#define D_PTR(map, i) \
++ ((map)->i->d_un.d_ptr + (dl_relocate_ld (map) ? 0 : (map)->l_addr))
+
+ /* Result of the lookup functions and how to retrieve the base address. */
+ typedef struct link_map *lookup_t;
+@@ -372,6 +379,13 @@ struct rtld_global
+ list of loaded objects while an object is added to or removed
+ from that list. */
+ __rtld_lock_define_recursive (EXTERN, _dl_load_write_lock)
++ /* This lock protects global and module specific TLS related data.
++ E.g. it is held in dlopen and dlclose when GL(dl_tls_generation),
++ GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are
++ accessed and when TLS related relocations are processed for a
++ module. It was introduced to keep pthread_create accessing TLS
++ state that is being set up. */
++ __rtld_lock_define_recursive (EXTERN, _dl_load_tls_lock)
+
+ /* Incremented whenever something may have been added to dl_loaded. */
+ EXTERN unsigned long long _dl_load_adds;
+@@ -1261,7 +1275,7 @@ extern int _dl_scope_free (void *) attribute_hidden;
+
+ /* Add module to slot information data. If DO_ADD is false, only the
+ required memory is allocated. Must be called with GL
+- (dl_load_lock) acquired. If the function has already been called
++ (dl_load_tls_lock) acquired. If the function has already been called
+ for the link map L with !do_add, then this function will not raise
+ an exception, otherwise it is possible that it encounters a memory
+ allocation failure. */
+diff --git a/sysdeps/mach/getsysstats.c b/sysdeps/mach/getsysstats.c
+index 1267f39da2..cc8023f979 100644
+--- a/sysdeps/mach/getsysstats.c
++++ b/sysdeps/mach/getsysstats.c
+@@ -62,6 +62,12 @@ __get_nprocs (void)
+ libc_hidden_def (__get_nprocs)
+ weak_alias (__get_nprocs, get_nprocs)
+
++int
++__get_nprocs_sched (void)
++{
++ return __get_nprocs ();
++}
++
+ /* Return the number of physical pages on the system. */
+ long int
+ __get_phys_pages (void)
+diff --git a/sysdeps/mips/dl-relocate-ld.h b/sysdeps/mips/dl-relocate-ld.h
+new file mode 100644
+index 0000000000..376ad75dd1
+--- /dev/null
++++ b/sysdeps/mips/dl-relocate-ld.h
+@@ -0,0 +1,25 @@
++/* Check if dynamic section should be relocated. MIPS version.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++#ifndef _DL_RELOCATE_LD_H
++#define _DL_RELOCATE_LD_H
++
++/* The dynamic section is readonly. */
++#define DL_RO_DYN_SECTION 1
++
++#endif /* _DL_RELOCATE_LD_H */
+diff --git a/sysdeps/mips/ldsodefs.h b/sysdeps/mips/ldsodefs.h
+index 4db7c60e38..36fd09a8bd 100644
+--- a/sysdeps/mips/ldsodefs.h
++++ b/sysdeps/mips/ldsodefs.h
+@@ -75,10 +75,6 @@ struct La_mips_64_retval;
+ struct La_mips_64_retval *, \
+ const char *);
+
+-/* The MIPS ABI specifies that the dynamic section has to be read-only. */
+-
+-#define DL_RO_DYN_SECTION 1
+-
+ #include_next <ldsodefs.h>
+
+ /* The 64-bit MIPS ELF ABI uses an unusual reloc format. Each
+diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
+index f1b7f2bdc6..43146e91c9 100644
+--- a/sysdeps/nptl/pthread.h
++++ b/sysdeps/nptl/pthread.h
+@@ -933,7 +933,7 @@ extern int pthread_mutexattr_getrobust (const pthread_mutexattr_t *__attr,
+ # ifdef __USE_GNU
+ # ifdef __REDIRECT_NTH
+ extern int __REDIRECT_NTH (pthread_mutexattr_getrobust_np,
+- (pthread_mutex_t *, int *),
++ (pthread_mutexattr_t *, int *),
+ pthread_mutexattr_getrobust) __nonnull ((1))
+ __attribute_deprecated_msg__ ("\
+ pthread_mutexattr_getrobust_np is deprecated, use pthread_mutexattr_getrobust");
+@@ -949,7 +949,7 @@ extern int pthread_mutexattr_setrobust (pthread_mutexattr_t *__attr,
+ # ifdef __USE_GNU
+ # ifdef __REDIRECT_NTH
+ extern int __REDIRECT_NTH (pthread_mutexattr_setrobust_np,
+- (pthread_mutex_t *, int),
++ (pthread_mutexattr_t *, int),
+ pthread_mutexattr_setrobust) __nonnull ((1))
+ __attribute_deprecated_msg__ ("\
+ pthread_mutexattr_setrobust_np is deprecated, use pthread_mutexattr_setrobust");
+diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
+index 838a68f022..43dfc6739e 100644
+--- a/sysdeps/posix/getaddrinfo.c
++++ b/sysdeps/posix/getaddrinfo.c
+@@ -2008,6 +2008,7 @@ gaiconf_init (void)
+ l = l->next;
+ }
+ free_prefixlist (labellist);
++ labellist = NULL;
+
+ /* Sort the entries so that the most specific ones are at
+ the beginning. */
+@@ -2046,6 +2047,7 @@ gaiconf_init (void)
+ l = l->next;
+ }
+ free_prefixlist (precedencelist);
++ precedencelist = NULL;
+
+ /* Sort the entries so that the most specific ones are at
+ the beginning. */
+diff --git a/sysdeps/powerpc/powerpc64/sysdep.h b/sysdeps/powerpc/powerpc64/sysdep.h
+index 589f7c8d18..cfcfa69f91 100644
+--- a/sysdeps/powerpc/powerpc64/sysdep.h
++++ b/sysdeps/powerpc/powerpc64/sysdep.h
+@@ -275,12 +275,14 @@ LT_LABELSUFFIX(name,_name_end): ; \
+ /* Allocate frame and save register */
+ #define NVOLREG_SAVE \
+ stdu r1,-SCV_FRAME_SIZE(r1); \
++ cfi_adjust_cfa_offset(SCV_FRAME_SIZE); \
+ std r31,SCV_FRAME_NVOLREG_SAVE(r1); \
+- cfi_adjust_cfa_offset(SCV_FRAME_SIZE);
++ cfi_rel_offset(r31,SCV_FRAME_NVOLREG_SAVE);
+
+ /* Restore register and destroy frame */
+ #define NVOLREG_RESTORE \
+ ld r31,SCV_FRAME_NVOLREG_SAVE(r1); \
++ cfi_restore(r31); \
+ addi r1,r1,SCV_FRAME_SIZE; \
+ cfi_adjust_cfa_offset(-SCV_FRAME_SIZE);
+
+@@ -331,13 +333,13 @@ LT_LABELSUFFIX(name,_name_end): ; \
+
+ #define DO_CALL_SCV \
+ mflr r9; \
+- std r9,FRAME_LR_SAVE(r1); \
+- cfi_offset(lr,FRAME_LR_SAVE); \
++ std r9,SCV_FRAME_SIZE+FRAME_LR_SAVE(r1); \
++ cfi_rel_offset(lr,SCV_FRAME_SIZE+FRAME_LR_SAVE); \
+ .machine "push"; \
+ .machine "power9"; \
+ scv 0; \
+ .machine "pop"; \
+- ld r9,FRAME_LR_SAVE(r1); \
++ ld r9,SCV_FRAME_SIZE+FRAME_LR_SAVE(r1); \
+ mtlr r9; \
+ cfi_restore(lr);
+
+diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile
+index 42f9fc5072..c657101696 100644
+--- a/sysdeps/pthread/Makefile
++++ b/sysdeps/pthread/Makefile
+@@ -89,7 +89,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
+ tst-join8 tst-join9 tst-join10 tst-join11 tst-join12 tst-join13 \
+ tst-join14 tst-join15 \
+ tst-key1 tst-key2 tst-key3 tst-key4 \
+- tst-kill1 tst-kill2 tst-kill3 tst-kill4 tst-kill5 tst-kill6 \
++ tst-kill1 tst-kill2 tst-kill3 tst-kill5 tst-kill6 \
+ tst-locale1 tst-locale2 \
+ tst-memstream \
+ tst-mutex-errorcheck tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 \
+@@ -118,6 +118,14 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
+ tst-unload \
+ tst-unwind-thread \
+ tst-pt-vfork1 tst-pt-vfork2 tst-vfork1x tst-vfork2x \
++ tst-pthread-exit-signal \
++ tst-pthread-setuid-loop \
++ tst-pthread_cancel-exited \
++ tst-pthread_cancel-select-loop \
++ tst-pthread-raise-blocked-self \
++ tst-pthread_kill-exited \
++ tst-pthread_kill-exiting \
++ # tests
+
+ tests-time64 := \
+ tst-abstime-time64 \
+@@ -145,15 +153,17 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx6 tst-cancelx8 tst-cancelx9 \
+ tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3
+
+ ifeq ($(build-shared),yes)
+-tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1
++tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1 tst-create1
+ tests-nolibpthread += tst-fini1
+ endif
+
+ modules-names += tst-atfork2mod tst-tls4moda tst-tls4modb \
+- tst-_res1mod1 tst-_res1mod2 tst-fini1mod
++ tst-_res1mod1 tst-_res1mod2 tst-fini1mod \
++ tst-create1mod
+ test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names)))
+
+ tst-atfork2mod.so-no-z-defs = yes
++tst-create1mod.so-no-z-defs = yes
+
+ ifeq ($(build-shared),yes)
+ # Build all the modules even when not actually running test programs.
+@@ -272,4 +282,8 @@ LDFLAGS-tst-join7mod.so = -Wl,-soname,tst-join7mod.so
+
+ CFLAGS-tst-unwind-thread.c += -funwind-tables
+
++LDFLAGS-tst-create1 = -Wl,-export-dynamic
++$(objpfx)tst-create1: $(shared-thread-library)
++$(objpfx)tst-create1.out: $(objpfx)tst-create1mod.so
++
+ endif
+diff --git a/sysdeps/pthread/tst-create1.c b/sysdeps/pthread/tst-create1.c
+new file mode 100644
+index 0000000000..763ded8d79
+--- /dev/null
++++ b/sysdeps/pthread/tst-create1.c
+@@ -0,0 +1,123 @@
++/* Verify that pthread_create does not deadlock when ctors take locks.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++#include <stdio.h>
++#include <support/xdlfcn.h>
++#include <support/xthread.h>
++
++/*
++Check if ctor and pthread_create deadlocks in
++
++thread 1: dlopen -> ctor -> lock(user_lock)
++thread 2: lock(user_lock) -> pthread_create
++
++or in
++
++thread 1: dlclose -> dtor -> lock(user_lock)
++thread 2: lock(user_lock) -> pthread_create
++*/
++
++static pthread_barrier_t bar_ctor;
++static pthread_barrier_t bar_ctor_finish;
++static pthread_barrier_t bar_dtor;
++static pthread_mutex_t user_lock = PTHREAD_MUTEX_INITIALIZER;
++
++void
++ctor (void)
++{
++ xpthread_barrier_wait (&bar_ctor);
++ dprintf (1, "thread 1: in ctor: started.\n");
++ xpthread_mutex_lock (&user_lock);
++ dprintf (1, "thread 1: in ctor: locked user_lock.\n");
++ xpthread_mutex_unlock (&user_lock);
++ dprintf (1, "thread 1: in ctor: unlocked user_lock.\n");
++ dprintf (1, "thread 1: in ctor: done.\n");
++ xpthread_barrier_wait (&bar_ctor_finish);
++}
++
++void
++dtor (void)
++{
++ xpthread_barrier_wait (&bar_dtor);
++ dprintf (1, "thread 1: in dtor: started.\n");
++ xpthread_mutex_lock (&user_lock);
++ dprintf (1, "thread 1: in dtor: locked user_lock.\n");
++ xpthread_mutex_unlock (&user_lock);
++ dprintf (1, "thread 1: in dtor: unlocked user_lock.\n");
++ dprintf (1, "thread 1: in dtor: done.\n");
++}
++
++static void *
++thread3 (void *a)
++{
++ dprintf (1, "thread 3: started.\n");
++ dprintf (1, "thread 3: done.\n");
++ return 0;
++}
++
++static void *
++thread2 (void *a)
++{
++ pthread_t t3;
++ dprintf (1, "thread 2: started.\n");
++
++ xpthread_mutex_lock (&user_lock);
++ dprintf (1, "thread 2: locked user_lock.\n");
++ xpthread_barrier_wait (&bar_ctor);
++ t3 = xpthread_create (0, thread3, 0);
++ xpthread_mutex_unlock (&user_lock);
++ dprintf (1, "thread 2: unlocked user_lock.\n");
++ xpthread_join (t3);
++ xpthread_barrier_wait (&bar_ctor_finish);
++
++ xpthread_mutex_lock (&user_lock);
++ dprintf (1, "thread 2: locked user_lock.\n");
++ xpthread_barrier_wait (&bar_dtor);
++ t3 = xpthread_create (0, thread3, 0);
++ xpthread_mutex_unlock (&user_lock);
++ dprintf (1, "thread 2: unlocked user_lock.\n");
++ xpthread_join (t3);
++
++ dprintf (1, "thread 2: done.\n");
++ return 0;
++}
++
++static void
++thread1 (void)
++{
++ dprintf (1, "thread 1: started.\n");
++ xpthread_barrier_init (&bar_ctor, NULL, 2);
++ xpthread_barrier_init (&bar_ctor_finish, NULL, 2);
++ xpthread_barrier_init (&bar_dtor, NULL, 2);
++ pthread_t t2 = xpthread_create (0, thread2, 0);
++ void *p = xdlopen ("tst-create1mod.so", RTLD_NOW | RTLD_GLOBAL);
++ dprintf (1, "thread 1: dlopen done.\n");
++ xdlclose (p);
++ dprintf (1, "thread 1: dlclose done.\n");
++ xpthread_join (t2);
++ dprintf (1, "thread 1: done.\n");
++}
++
++static int
++do_test (void)
++{
++ thread1 ();
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/sysdeps/pthread/tst-create1mod.c b/sysdeps/pthread/tst-create1mod.c
+new file mode 100644
+index 0000000000..62c9006961
+--- /dev/null
++++ b/sysdeps/pthread/tst-create1mod.c
+@@ -0,0 +1,41 @@
++/* Verify that pthread_create does not deadlock when ctors take locks.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++#include <stdio.h>
++
++/* Require TLS setup for the module. */
++__thread int tlsvar;
++
++void ctor (void);
++void dtor (void);
++
++static void __attribute__ ((constructor))
++do_init (void)
++{
++ dprintf (1, "constructor started: %d.\n", tlsvar++);
++ ctor ();
++ dprintf (1, "constructor done: %d.\n", tlsvar++);
++}
++
++static void __attribute__ ((destructor))
++do_end (void)
++{
++ dprintf (1, "destructor started: %d.\n", tlsvar++);
++ dtor ();
++ dprintf (1, "destructor done: %d.\n", tlsvar++);
++}
+diff --git a/sysdeps/pthread/tst-kill4.c b/sysdeps/pthread/tst-kill4.c
+deleted file mode 100644
+index 9563939792..0000000000
+--- a/sysdeps/pthread/tst-kill4.c
++++ /dev/null
+@@ -1,90 +0,0 @@
+-/* Copyright (C) 2003-2021 Free Software Foundation, Inc.
+- This file is part of the GNU C Library.
+- Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
+-
+- 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
+- <https://www.gnu.org/licenses/>. */
+-
+-#include <errno.h>
+-#include <pthread.h>
+-#include <signal.h>
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <unistd.h>
+-
+-
+-static void *
+-tf (void *a)
+-{
+- return NULL;
+-}
+-
+-
+-int
+-do_test (void)
+-{
+- pthread_attr_t at;
+- if (pthread_attr_init (&at) != 0)
+- {
+- puts ("attr_create failed");
+- exit (1);
+- }
+-
+- /* Limit thread stack size, because if it is too large, pthread_join
+- will free it immediately rather than put it into stack cache. */
+- if (pthread_attr_setstacksize (&at, 2 * 1024 * 1024) != 0)
+- {
+- puts ("setstacksize failed");
+- exit (1);
+- }
+-
+- pthread_t th;
+- if (pthread_create (&th, &at, tf, NULL) != 0)
+- {
+- puts ("create failed");
+- exit (1);
+- }
+-
+- pthread_attr_destroy (&at);
+-
+- if (pthread_join (th, NULL) != 0)
+- {
+- puts ("join failed");
+- exit (1);
+- }
+-
+- /* The following only works because we assume here something about
+- the implementation. Namely, that the memory allocated for the
+- thread descriptor is not going away, that the TID field is
+- cleared and therefore the signal is sent to process 0, and that
+- we can savely assume there is no other process with this ID at
+- that time. */
+- int e = pthread_kill (th, 0);
+- if (e == 0)
+- {
+- puts ("pthread_kill succeeded");
+- exit (1);
+- }
+- if (e != ESRCH)
+- {
+- puts ("pthread_kill didn't return ESRCH");
+- exit (1);
+- }
+-
+- return 0;
+-}
+-
+-
+-#define TEST_FUNCTION do_test ()
+-#include "../test-skeleton.c"
+diff --git a/sysdeps/pthread/tst-pthread-exit-signal.c b/sysdeps/pthread/tst-pthread-exit-signal.c
+new file mode 100644
+index 0000000000..b4526fe663
+--- /dev/null
++++ b/sysdeps/pthread/tst-pthread-exit-signal.c
+@@ -0,0 +1,45 @@
++/* Test that pending signals are not delivered on thread exit (bug 28607).
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++/* Due to bug 28607, pthread_kill (or pthread_cancel) restored the
++ signal mask during during thread exit, triggering the delivery of a
++ blocked pending signal (SIGUSR1 in this test). */
++
++#include <support/xthread.h>
++#include <support/xsignal.h>
++
++static void *
++threadfunc (void *closure)
++{
++ sigset_t sigmask;
++ sigfillset (&sigmask);
++ xpthread_sigmask (SIG_SETMASK, &sigmask, NULL);
++ xpthread_kill (pthread_self (), SIGUSR1);
++ pthread_exit (NULL);
++ return NULL;
++}
++
++static int
++do_test (void)
++{
++ pthread_t thr = xpthread_create (NULL, threadfunc, NULL);
++ xpthread_join (thr);
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/sysdeps/pthread/tst-pthread-raise-blocked-self.c b/sysdeps/pthread/tst-pthread-raise-blocked-self.c
+new file mode 100644
+index 0000000000..128e1a6071
+--- /dev/null
++++ b/sysdeps/pthread/tst-pthread-raise-blocked-self.c
+@@ -0,0 +1,92 @@
++/* Test that raise sends signal to current thread even if blocked.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++#include <signal.h>
++#include <support/check.h>
++#include <support/xsignal.h>
++#include <support/xthread.h>
++#include <pthread.h>
++#include <unistd.h>
++
++/* Used to create a dummy thread ID distinct from all other thread
++ IDs. */
++static void *
++noop (void *ignored)
++{
++ return NULL;
++}
++
++static volatile pthread_t signal_thread;
++
++static void
++signal_handler (int signo)
++{
++ signal_thread = pthread_self ();
++}
++
++/* Used to ensure that waiting_thread has launched and can accept
++ signals. */
++static pthread_barrier_t barrier;
++
++static void *
++waiting_thread (void *ignored)
++{
++ xpthread_barrier_wait (&barrier);
++ pause ();
++ return NULL;
++}
++
++static int
++do_test (void)
++{
++ xsignal (SIGUSR1, signal_handler);
++ xpthread_barrier_init (&barrier, NULL, 2);
++
++ /* Distinct thread ID value to */
++ pthread_t dummy = xpthread_create (NULL, noop, NULL);
++ signal_thread = dummy;
++
++ pthread_t helper = xpthread_create (NULL, waiting_thread, NULL);
++
++ /* Make sure that the thread is running. */
++ xpthread_barrier_wait (&barrier);
++
++ /* Block signals on this thread. */
++ sigset_t set;
++ sigfillset (&set);
++ xpthread_sigmask (SIG_BLOCK, &set, NULL);
++
++ /* Send the signal to this thread. It must not be delivered. */
++ raise (SIGUSR1);
++ TEST_VERIFY (signal_thread == dummy);
++
++ /* Wait a bit to give a chance for signal delivery (increases
++ chances of failure with bug 28407). */
++ usleep (50 * 1000);
++
++ /* Unblocking should cause synchronous delivery of the signal. */
++ xpthread_sigmask (SIG_UNBLOCK, &set, NULL);
++ TEST_VERIFY (signal_thread == pthread_self ());
++
++ xpthread_cancel (helper);
++ xpthread_join (helper);
++ xpthread_join (dummy);
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/sysdeps/pthread/tst-pthread-setuid-loop.c b/sysdeps/pthread/tst-pthread-setuid-loop.c
+new file mode 100644
+index 0000000000..fda2a49b7f
+--- /dev/null
++++ b/sysdeps/pthread/tst-pthread-setuid-loop.c
+@@ -0,0 +1,61 @@
++/* Test that setuid, pthread_create, thread exit do not deadlock (bug 28361).
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++#include <support/check.h>
++#include <support/xthread.h>
++#include <unistd.h>
++
++/* How many threads to launch during each iteration. */
++enum { threads = 4 };
++
++/* How many iterations to perform. This value seems to reproduce
++ bug 28361 in a bout one in three runs. */
++enum { iterations = 5000 };
++
++/* Cache of the real user ID used by setuid_thread. */
++static uid_t uid;
++
++/* Start routine for the threads. */
++static void *
++setuid_thread (void *closure)
++{
++ TEST_COMPARE (setuid (uid), 0);
++ return NULL;
++}
++
++static int
++do_test (void)
++{
++ /* The setxid machinery is still invoked even if the UID is
++ unchanged. (The kernel might reset other credentials as part of
++ the system call.) */
++ uid = getuid ();
++
++ for (int i = 0; i < iterations; ++i)
++ {
++ pthread_t thread_ids[threads];
++ for (int j = 0; j < threads; ++j)
++ thread_ids[j] = xpthread_create (NULL, setuid_thread, NULL);
++ for (int j = 0; j < threads; ++j)
++ xpthread_join (thread_ids[j]);
++ }
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/sysdeps/pthread/tst-pthread_cancel-exited.c b/sysdeps/pthread/tst-pthread_cancel-exited.c
+new file mode 100644
+index 0000000000..811c9bee07
+--- /dev/null
++++ b/sysdeps/pthread/tst-pthread_cancel-exited.c
+@@ -0,0 +1,45 @@
++/* Test that pthread_kill succeeds for an exited thread.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++/* This test verifies that pthread_kill returns 0 (and not ESRCH) for
++ a thread that has exited on the kernel side. */
++
++#include <stddef.h>
++#include <support/support.h>
++#include <support/xthread.h>
++
++static void *
++noop_thread (void *closure)
++{
++ return NULL;
++}
++
++static int
++do_test (void)
++{
++ pthread_t thr = xpthread_create (NULL, noop_thread, NULL);
++
++ support_wait_for_thread_exit ();
++
++ xpthread_cancel (thr);
++ xpthread_join (thr);
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/sysdeps/pthread/tst-pthread_cancel-select-loop.c b/sysdeps/pthread/tst-pthread_cancel-select-loop.c
+new file mode 100644
+index 0000000000..a62087589c
+--- /dev/null
++++ b/sysdeps/pthread/tst-pthread_cancel-select-loop.c
+@@ -0,0 +1,87 @@
++/* Test that pthread_cancel succeeds during thread exit.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++/* This test tries to trigger an internal race condition in
++ pthread_cancel, where the cancellation signal is sent after the
++ thread has begun the cancellation process. This can result in a
++ spurious ESRCH error. For the original bug 12889, the window is
++ quite small, so the bug was not reproduced in every run. */
++
++#include <stdbool.h>
++#include <stddef.h>
++#include <support/check.h>
++#include <support/xthread.h>
++#include <support/xunistd.h>
++#include <sys/select.h>
++#include <unistd.h>
++
++/* Set to true by timeout_thread_function when the test should
++ terminate. */
++static bool timeout;
++
++static void *
++timeout_thread_function (void *unused)
++{
++ usleep (5 * 1000 * 1000);
++ __atomic_store_n (&timeout, true, __ATOMIC_RELAXED);
++ return NULL;
++}
++
++/* Used for blocking the select function below. */
++static int pipe_fds[2];
++
++static void *
++canceled_thread_function (void *unused)
++{
++ while (true)
++ {
++ fd_set rfs;
++ fd_set wfs;
++ fd_set efs;
++ FD_ZERO (&rfs);
++ FD_ZERO (&wfs);
++ FD_ZERO (&efs);
++ FD_SET (pipe_fds[0], &rfs);
++
++ /* If the cancellation request is recognized early, the thread
++ begins exiting while the cancellation signal arrives. */
++ select (FD_SETSIZE, &rfs, &wfs, &efs, NULL);
++ }
++ return NULL;
++}
++
++static int
++do_test (void)
++{
++ xpipe (pipe_fds);
++ pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL);
++
++ while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED))
++ {
++ pthread_t thr = xpthread_create (NULL, canceled_thread_function, NULL);
++ xpthread_cancel (thr);
++ TEST_VERIFY (xpthread_join (thr) == PTHREAD_CANCELED);
++ }
++
++ xpthread_join (thr_timeout);
++ xclose (pipe_fds[0]);
++ xclose (pipe_fds[1]);
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/sysdeps/pthread/tst-pthread_kill-exited.c b/sysdeps/pthread/tst-pthread_kill-exited.c
+new file mode 100644
+index 0000000000..a2fddad526
+--- /dev/null
++++ b/sysdeps/pthread/tst-pthread_kill-exited.c
+@@ -0,0 +1,63 @@
++/* Test that pthread_kill succeeds for an exited thread.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++/* This test verifies that the default pthread_kill returns 0 (and not
++ ESRCH) for a thread that has exited on the kernel side. */
++
++#include <errno.h>
++#include <pthread.h>
++#include <shlib-compat.h>
++#include <signal.h>
++#include <stddef.h>
++#include <support/check.h>
++#include <support/support.h>
++#include <support/xthread.h>
++
++static void *
++noop_thread (void *closure)
++{
++ return NULL;
++}
++
++#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC
++extern __typeof (pthread_kill) compat_pthread_kill;
++compat_symbol_reference (libpthread, compat_pthread_kill, pthread_kill,
++ GLIBC_2_0);
++#endif
++
++static int
++do_test (void)
++{
++ pthread_t thr = xpthread_create (NULL, noop_thread, NULL);
++
++ support_wait_for_thread_exit ();
++
++ /* NB: Always uses the default symbol due to separate compilation. */
++ xpthread_kill (thr, SIGUSR1);
++
++#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC
++ /* Old binaries need the non-conforming ESRCH error code. */
++ TEST_COMPARE (compat_pthread_kill (thr, SIGUSR1), ESRCH);
++#endif
++
++ xpthread_join (thr);
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/sysdeps/pthread/tst-pthread_kill-exiting.c b/sysdeps/pthread/tst-pthread_kill-exiting.c
+new file mode 100644
+index 0000000000..f803e94f11
+--- /dev/null
++++ b/sysdeps/pthread/tst-pthread_kill-exiting.c
+@@ -0,0 +1,123 @@
++/* Test that pthread_kill succeeds during thread exit.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++/* This test verifies that pthread_kill for a thread that is exiting
++ succeeds (with or without actually delivering the signal). */
++
++#include <array_length.h>
++#include <stdbool.h>
++#include <stddef.h>
++#include <support/xsignal.h>
++#include <support/xthread.h>
++#include <unistd.h>
++
++/* Set to true by timeout_thread_function when the test should
++ terminate. */
++static bool timeout;
++
++static void *
++timeout_thread_function (void *unused)
++{
++ usleep (1000 * 1000);
++ __atomic_store_n (&timeout, true, __ATOMIC_RELAXED);
++ return NULL;
++}
++
++/* Used to synchronize the sending threads with the target thread and
++ main thread. */
++static pthread_barrier_t barrier_1;
++static pthread_barrier_t barrier_2;
++
++/* The target thread to which signals are to be sent. */
++static pthread_t target_thread;
++
++/* Set by the main thread to true after timeout has been set to
++ true. */
++static bool exiting;
++
++static void *
++sender_thread_function (void *unused)
++{
++ while (true)
++ {
++ /* Wait until target_thread has been initialized. The target
++ thread and main thread participate in this barrier. */
++ xpthread_barrier_wait (&barrier_1);
++
++ if (exiting)
++ break;
++
++ xpthread_kill (target_thread, SIGUSR1);
++
++ /* Communicate that the signal has been sent. The main thread
++ participates in this barrier. */
++ xpthread_barrier_wait (&barrier_2);
++ }
++ return NULL;
++}
++
++static void *
++target_thread_function (void *unused)
++{
++ target_thread = pthread_self ();
++ xpthread_barrier_wait (&barrier_1);
++ return NULL;
++}
++
++static int
++do_test (void)
++{
++ xsignal (SIGUSR1, SIG_IGN);
++
++ pthread_t thr_timeout = xpthread_create (NULL, timeout_thread_function, NULL);
++
++ pthread_t threads[4];
++ xpthread_barrier_init (&barrier_1, NULL, array_length (threads) + 2);
++ xpthread_barrier_init (&barrier_2, NULL, array_length (threads) + 1);
++
++ for (int i = 0; i < array_length (threads); ++i)
++ threads[i] = xpthread_create (NULL, sender_thread_function, NULL);
++
++ while (!__atomic_load_n (&timeout, __ATOMIC_RELAXED))
++ {
++ xpthread_create (NULL, target_thread_function, NULL);
++
++ /* Wait for the target thread to be set up and signal sending to
++ start. */
++ xpthread_barrier_wait (&barrier_1);
++
++ /* Wait for signal sending to complete. */
++ xpthread_barrier_wait (&barrier_2);
++
++ xpthread_join (target_thread);
++ }
++
++ exiting = true;
++
++ /* Signal the sending threads to exit. */
++ xpthread_create (NULL, target_thread_function, NULL);
++ xpthread_barrier_wait (&barrier_1);
++
++ for (int i = 0; i < array_length (threads); ++i)
++ xpthread_join (threads[i]);
++ xpthread_join (thr_timeout);
++
++ return 0;
++}
++
++#include <support/test-driver.c>
+diff --git a/sysdeps/riscv/dl-relocate-ld.h b/sysdeps/riscv/dl-relocate-ld.h
+new file mode 100644
+index 0000000000..2ab2b8ac6c
+--- /dev/null
++++ b/sysdeps/riscv/dl-relocate-ld.h
+@@ -0,0 +1,25 @@
++/* Check if dynamic section should be relocated. RISC-V version.
++ Copyright (C) 2021 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
++ <https://www.gnu.org/licenses/>. */
++
++#ifndef _DL_RELOCATE_LD_H
++#define _DL_RELOCATE_LD_H
++
++/* The dynamic section is readonly for ABI compatibility. */
++#define DL_RO_DYN_SECTION 1
++
++#endif /* _DL_RELOCATE_LD_H */
+diff --git a/sysdeps/riscv/ldsodefs.h b/sysdeps/riscv/ldsodefs.h
+index 0c696714a7..8947ffe4b5 100644
+--- a/sysdeps/riscv/ldsodefs.h
++++ b/sysdeps/riscv/ldsodefs.h
+@@ -38,11 +38,6 @@ struct La_riscv_retval;
+ struct La_riscv_retval *, \
+ const char *);
+
+-/* Although the RISC-V ABI does not specify that the dynamic section has
+- to be read-only, it needs to be kept for ABI compatibility. */
+-
+-#define DL_RO_DYN_SECTION 1
+-
+ #include_next <ldsodefs.h>
+
+ #endif
+diff --git a/sysdeps/s390/dl-procinfo.c b/sysdeps/s390/dl-procinfo.c
+index c174e27b35..155f0bd99e 100644
+--- a/sysdeps/s390/dl-procinfo.c
++++ b/sysdeps/s390/dl-procinfo.c
+@@ -46,13 +46,13 @@
+ #if !defined PROCINFO_DECL && defined SHARED
+ ._dl_s390_cap_flags
+ #else
+-PROCINFO_CLASS const char _dl_s390_cap_flags[21][9]
++PROCINFO_CLASS const char _dl_s390_cap_flags[23][9]
+ #endif
+ #ifndef PROCINFO_DECL
+ = {
+ "esan3", "zarch", "stfle", "msa", "ldisp", "eimm", "dfp", "edat", "etf3eh",
+ "highgprs", "te", "vx", "vxd", "vxe", "gs", "vxe2", "vxp", "sort", "dflt",
+- "vxp2", "nnpa"
++ "vxp2", "nnpa", "pcimio", "sie"
+ }
+ #endif
+ #if !defined SHARED || defined PROCINFO_DECL
+diff --git a/sysdeps/s390/dl-procinfo.h b/sysdeps/s390/dl-procinfo.h
+index 2d9c305808..e4e3e334a5 100644
+--- a/sysdeps/s390/dl-procinfo.h
++++ b/sysdeps/s390/dl-procinfo.h
+@@ -21,7 +21,7 @@
+ #define _DL_PROCINFO_H 1
+ #include <ldsodefs.h>
+
+-#define _DL_HWCAP_COUNT 21
++#define _DL_HWCAP_COUNT 23
+
+ #define _DL_PLATFORMS_COUNT 10
+
+@@ -63,6 +63,8 @@ enum
+ HWCAP_S390_DFLT = 1 << 18,
+ HWCAP_S390_VXRS_PDE2 = 1 << 19,
+ HWCAP_S390_NNPA = 1 << 20,
++ HWCAP_S390_PCI_MIO = 1 << 21,
++ HWCAP_S390_SIE = 1 << 22,
+ };
+
+ #define HWCAP_IMPORTANT (HWCAP_S390_ZARCH | HWCAP_S390_LDISP \
+diff --git a/sysdeps/s390/memmem-arch13.S b/sysdeps/s390/memmem-arch13.S
+index c5c8d8c97e..58df8cdb14 100644
+--- a/sysdeps/s390/memmem-arch13.S
++++ b/sysdeps/s390/memmem-arch13.S
+@@ -41,7 +41,7 @@ ENTRY(MEMMEM_ARCH13)
+ # error The arch13 variant of memmem needs the z13 variant of memmem!
+ # endif
+ clgfi %r5,9
+- jh MEMMEM_Z13
++ jgh MEMMEM_Z13
+
+ aghik %r0,%r5,-1 /* vll needs highest index. */
+ bc 4,0(%r14) /* cc==1: return if needle-len == 0. */
+diff --git a/sysdeps/s390/strstr-arch13.S b/sysdeps/s390/strstr-arch13.S
+index c7183e627c..222a6de91a 100644
+--- a/sysdeps/s390/strstr-arch13.S
++++ b/sysdeps/s390/strstr-arch13.S
+@@ -49,7 +49,7 @@ ENTRY(STRSTR_ARCH13)
+ # error The arch13 variant of strstr needs the z13 variant of strstr!
+ # endif
+ clgfi %r4,9
+- jh STRSTR_Z13
++ jgh STRSTR_Z13
+
+ /* In case of a partial match, the vstrs instruction returns the index
+ of the partial match in a vector-register. Then we have to
+diff --git a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
+index e9eb707d0a..bedab1abba 100644
+--- a/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/aarch64/arch-syscall.h
+@@ -126,6 +126,7 @@
+ #define __NR_mbind 235
+ #define __NR_membarrier 283
+ #define __NR_memfd_create 279
++#define __NR_memfd_secret 447
+ #define __NR_migrate_pages 238
+ #define __NR_mincore 232
+ #define __NR_mkdirat 34
+@@ -187,6 +188,7 @@
+ #define __NR_pwritev 70
+ #define __NR_pwritev2 287
+ #define __NR_quotactl 60
++#define __NR_quotactl_fd 443
+ #define __NR_read 63
+ #define __NR_readahead 213
+ #define __NR_readlinkat 78
+diff --git a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
+index bd6b7d4003..91354ed9e2 100644
+--- a/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/alpha/arch-syscall.h
+@@ -337,6 +337,7 @@
+ #define __NR_pwritev2 521
+ #define __NR_query_module 347
+ #define __NR_quotactl 148
++#define __NR_quotactl_fd 553
+ #define __NR_read 3
+ #define __NR_readahead 379
+ #define __NR_readlink 58
+diff --git a/sysdeps/unix/sysv/linux/arc/arch-syscall.h b/sysdeps/unix/sysv/linux/arc/arch-syscall.h
+index 10650549c1..ff5c7eb36d 100644
+--- a/sysdeps/unix/sysv/linux/arc/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/arc/arch-syscall.h
+@@ -190,6 +190,7 @@
+ #define __NR_pwritev 70
+ #define __NR_pwritev2 287
+ #define __NR_quotactl 60
++#define __NR_quotactl_fd 443
+ #define __NR_read 63
+ #define __NR_readahead 213
+ #define __NR_readlinkat 78
+diff --git a/sysdeps/unix/sysv/linux/arm/arch-syscall.h b/sysdeps/unix/sysv/linux/arm/arch-syscall.h
+index 85c9b236ce..5772333cee 100644
+--- a/sysdeps/unix/sysv/linux/arm/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/arm/arch-syscall.h
+@@ -244,6 +244,7 @@
+ #define __NR_pwritev 362
+ #define __NR_pwritev2 393
+ #define __NR_quotactl 131
++#define __NR_quotactl_fd 443
+ #define __NR_read 3
+ #define __NR_readahead 225
+ #define __NR_readlink 85
+diff --git a/sysdeps/unix/sysv/linux/bits/mman-linux.h b/sysdeps/unix/sysv/linux/bits/mman-linux.h
+index 3b1ae418e0..31451c28d9 100644
+--- a/sysdeps/unix/sysv/linux/bits/mman-linux.h
++++ b/sysdeps/unix/sysv/linux/bits/mman-linux.h
+@@ -89,6 +89,10 @@
+ # define MADV_KEEPONFORK 19 /* Undo MADV_WIPEONFORK. */
+ # define MADV_COLD 20 /* Deactivate these pages. */
+ # define MADV_PAGEOUT 21 /* Reclaim these pages. */
++# define MADV_POPULATE_READ 22 /* Populate (prefault) page tables
++ readable. */
++# define MADV_POPULATE_WRITE 23 /* Populate (prefault) page tables
++ writable. */
+ # define MADV_HWPOISON 100 /* Poison a page for testing. */
+ #endif
+
+diff --git a/sysdeps/unix/sysv/linux/bits/timex.h b/sysdeps/unix/sysv/linux/bits/timex.h
+index ee37694e8f..4a5db6deca 100644
+--- a/sysdeps/unix/sysv/linux/bits/timex.h
++++ b/sysdeps/unix/sysv/linux/bits/timex.h
+@@ -25,7 +25,7 @@
+
+ struct timex
+ {
+-# ifdef __USE_TIME_BITS64
++# if defined __USE_TIME_BITS64 || (__TIMESIZE == 64 && __WORDSIZE == 32)
+ unsigned int modes; /* mode selector */
+ int :32; /* pad */
+ long long offset; /* time offset (usec) */
+diff --git a/sysdeps/unix/sysv/linux/csky/arch-syscall.h b/sysdeps/unix/sysv/linux/csky/arch-syscall.h
+index 24b0d1f94e..4af6d6202f 100644
+--- a/sysdeps/unix/sysv/linux/csky/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/csky/arch-syscall.h
+@@ -199,6 +199,7 @@
+ #define __NR_pwritev 70
+ #define __NR_pwritev2 287
+ #define __NR_quotactl 60
++#define __NR_quotactl_fd 443
+ #define __NR_read 63
+ #define __NR_readahead 213
+ #define __NR_readlinkat 78
+diff --git a/sysdeps/unix/sysv/linux/getsysstats.c b/sysdeps/unix/sysv/linux/getsysstats.c
+index 1391e360b8..7fc6521942 100644
+--- a/sysdeps/unix/sysv/linux/getsysstats.c
++++ b/sysdeps/unix/sysv/linux/getsysstats.c
+@@ -18,6 +18,8 @@
+ <https://www.gnu.org/licenses/>. */
+
+ #include <array_length.h>
++#include <assert.h>
++#include <ctype.h>
+ #include <dirent.h>
+ #include <errno.h>
+ #include <ldsodefs.h>
+@@ -29,61 +31,170 @@
+ #include <sys/sysinfo.h>
+ #include <sysdep.h>
+
+-/* Compute the population count of the entire array. */
+-static int
+-__get_nprocs_count (const unsigned long int *array, size_t length)
++int
++__get_nprocs_sched (void)
+ {
+- int count = 0;
+- for (size_t i = 0; i < length; ++i)
+- if (__builtin_add_overflow (count, __builtin_popcountl (array[i]),
+- &count))
+- return INT_MAX;
+- return count;
++ enum
++ {
++ max_num_cpus = 32768,
++ cpu_bits_size = CPU_ALLOC_SIZE (32768)
++ };
++
++ /* This cannot use malloc because it is used on malloc initialization. */
++ __cpu_mask cpu_bits[cpu_bits_size / sizeof (__cpu_mask)];
++ int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, cpu_bits_size,
++ cpu_bits);
++ if (r > 0)
++ return CPU_COUNT_S (cpu_bits_size, (cpu_set_t*) cpu_bits);
++ else if (r == -EINVAL)
++ /* The input buffer is still not enough to store the number of cpus. This
++ is an arbitrary values assuming such systems should be rare and there
++ is no offline cpus. */
++ return max_num_cpus;
++ /* Some other error. 2 is conservative (not a uniprocessor system, so
++ atomics are needed). */
++ return 2;
++}
++
++static char *
++next_line (int fd, char *const buffer, char **cp, char **re,
++ char *const buffer_end)
++{
++ char *res = *cp;
++ char *nl = memchr (*cp, '\n', *re - *cp);
++ if (nl == NULL)
++ {
++ if (*cp != buffer)
++ {
++ if (*re == buffer_end)
++ {
++ memmove (buffer, *cp, *re - *cp);
++ *re = buffer + (*re - *cp);
++ *cp = buffer;
++
++ ssize_t n = __read_nocancel (fd, *re, buffer_end - *re);
++ if (n < 0)
++ return NULL;
++
++ *re += n;
++
++ nl = memchr (*cp, '\n', *re - *cp);
++ while (nl == NULL && *re == buffer_end)
++ {
++ /* Truncate too long lines. */
++ *re = buffer + 3 * (buffer_end - buffer) / 4;
++ n = __read_nocancel (fd, *re, buffer_end - *re);
++ if (n < 0)
++ return NULL;
++
++ nl = memchr (*re, '\n', n);
++ **re = '\n';
++ *re += n;
++ }
++ }
++ else
++ nl = memchr (*cp, '\n', *re - *cp);
++
++ res = *cp;
++ }
++
++ if (nl == NULL)
++ nl = *re - 1;
++ }
++
++ *cp = nl + 1;
++ assert (*cp <= *re);
++
++ return res == *re ? NULL : res;
+ }
+
+-/* __get_nprocs with a large buffer. */
+ static int
+-__get_nprocs_large (void)
++get_nproc_stat (char *buffer, size_t buffer_size)
+ {
+- /* This code cannot use scratch_buffer because it is used during
+- malloc initialization. */
+- size_t pagesize = GLRO (dl_pagesize);
+- unsigned long int *page = __mmap (0, pagesize, PROT_READ | PROT_WRITE,
+- MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+- if (page == MAP_FAILED)
+- return 2;
+- int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0, pagesize, page);
+- int count;
+- if (r > 0)
+- count = __get_nprocs_count (page, pagesize / sizeof (unsigned long int));
+- else if (r == -EINVAL)
+- /* One page is still not enough to store the bits. A more-or-less
+- arbitrary value. This assumes t hat such large systems never
+- happen in practice. */
+- count = GLRO (dl_pagesize) * CHAR_BIT;
+- else
+- count = 2;
+- __munmap (page, GLRO (dl_pagesize));
+- return count;
++ char *buffer_end = buffer + buffer_size;
++ char *cp = buffer_end;
++ char *re = buffer_end;
++
++ /* Default to an SMP system in case we cannot obtain an accurate
++ number. */
++ int result = 2;
++
++ const int flags = O_RDONLY | O_CLOEXEC;
++ int fd = __open_nocancel ("/proc/stat", flags);
++ if (fd != -1)
++ {
++ result = 0;
++
++ char *l;
++ while ((l = next_line (fd, buffer, &cp, &re, buffer_end)) != NULL)
++ /* The current format of /proc/stat has all the cpu* entries
++ at the front. We assume here that stays this way. */
++ if (strncmp (l, "cpu", 3) != 0)
++ break;
++ else if (isdigit (l[3]))
++ ++result;
++
++ __close_nocancel_nostatus (fd);
++ }
++
++ return result;
+ }
+
+ int
+ __get_nprocs (void)
+ {
+- /* Fast path for most systems. The kernel expects a buffer size
+- that is a multiple of 8. */
+- unsigned long int small_buffer[1024 / CHAR_BIT / sizeof (unsigned long int)];
+- int r = INTERNAL_SYSCALL_CALL (sched_getaffinity, 0,
+- sizeof (small_buffer), small_buffer);
+- if (r > 0)
+- return __get_nprocs_count (small_buffer, r / sizeof (unsigned long int));
+- else if (r == -EINVAL)
+- /* The kernel requests a larger buffer to store the data. */
+- return __get_nprocs_large ();
+- else
+- /* Some other error. 2 is conservative (not a uniprocessor
+- system, so atomics are needed). */
+- return 2;
++ enum { buffer_size = 1024 };
++ char buffer[buffer_size];
++ char *buffer_end = buffer + buffer_size;
++ char *cp = buffer_end;
++ char *re = buffer_end;
++
++ const int flags = O_RDONLY | O_CLOEXEC;
++ /* This file contains comma-separated ranges. */
++ int fd = __open_nocancel ("/sys/devices/system/cpu/online", flags);
++ char *l;
++ int result = 0;
++ if (fd != -1)
++ {
++ l = next_line (fd, buffer, &cp, &re, buffer_end);
++ if (l != NULL)
++ do
++ {
++ char *endp;
++ unsigned long int n = strtoul (l, &endp, 10);
++ if (l == endp)
++ {
++ result = 0;
++ break;
++ }
++
++ unsigned long int m = n;
++ if (*endp == '-')
++ {
++ l = endp + 1;
++ m = strtoul (l, &endp, 10);
++ if (l == endp)
++ {
++ result = 0;
++ break;
++ }
++ }
++
++ result += m - n + 1;
++
++ l = endp;
++ if (l < re && *l == ',')
++ ++l;
++ }
++ while (l < re && *l != '\n');
++
++ __close_nocancel_nostatus (fd);
++
++ if (result > 0)
++ return result;
++ }
++
++ return get_nproc_stat (buffer, buffer_size);
+ }
+ libc_hidden_def (__get_nprocs)
+ weak_alias (__get_nprocs, get_nprocs)
+@@ -117,7 +228,9 @@ __get_nprocs_conf (void)
+ return count;
+ }
+
+- return 1;
++ enum { buffer_size = 1024 };
++ char buffer[buffer_size];
++ return get_nproc_stat (buffer, buffer_size);
+ }
+ libc_hidden_def (__get_nprocs_conf)
+ weak_alias (__get_nprocs_conf, get_nprocs_conf)
+diff --git a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
+index feb70abc3e..b07fc8549d 100644
+--- a/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/hppa/arch-syscall.h
+@@ -231,6 +231,7 @@
+ #define __NR_pwritev 316
+ #define __NR_pwritev2 348
+ #define __NR_quotactl 131
++#define __NR_quotactl_fd 443
+ #define __NR_read 3
+ #define __NR_readahead 207
+ #define __NR_readlink 85
+diff --git a/sysdeps/unix/sysv/linux/i386/arch-syscall.h b/sysdeps/unix/sysv/linux/i386/arch-syscall.h
+index 3b1894a79b..6e4264698b 100644
+--- a/sysdeps/unix/sysv/linux/i386/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/i386/arch-syscall.h
+@@ -183,6 +183,7 @@
+ #define __NR_mbind 274
+ #define __NR_membarrier 375
+ #define __NR_memfd_create 356
++#define __NR_memfd_secret 447
+ #define __NR_migrate_pages 294
+ #define __NR_mincore 218
+ #define __NR_mkdir 39
+@@ -266,6 +267,7 @@
+ #define __NR_pwritev2 379
+ #define __NR_query_module 167
+ #define __NR_quotactl 131
++#define __NR_quotactl_fd 443
+ #define __NR_read 3
+ #define __NR_readahead 225
+ #define __NR_readdir 89
+diff --git a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h
+index fb388a5fa4..1ca706d721 100644
+--- a/sysdeps/unix/sysv/linux/ia64/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/ia64/arch-syscall.h
+@@ -218,6 +218,7 @@
+ #define __NR_pwritev 1320
+ #define __NR_pwritev2 1349
+ #define __NR_quotactl 1137
++#define __NR_quotactl_fd 1467
+ #define __NR_read 1026
+ #define __NR_readahead 1216
+ #define __NR_readlink 1092
+diff --git a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
+index 7bc8c4af92..2f10f71f90 100644
+--- a/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/m68k/arch-syscall.h
+@@ -254,6 +254,7 @@
+ #define __NR_pwritev2 378
+ #define __NR_query_module 167
+ #define __NR_quotactl 131
++#define __NR_quotactl_fd 443
+ #define __NR_read 3
+ #define __NR_readahead 240
+ #define __NR_readdir 89
+diff --git a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
+index cf560d3af4..0607a4dfa6 100644
+--- a/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/microblaze/arch-syscall.h
+@@ -266,6 +266,7 @@
+ #define __NR_pwritev2 394
+ #define __NR_query_module 167
+ #define __NR_quotactl 131
++#define __NR_quotactl_fd 443
+ #define __NR_read 3
+ #define __NR_readahead 225
+ #define __NR_readdir 89
+diff --git a/sysdeps/unix/sysv/linux/mips/fxstat.c b/sysdeps/unix/sysv/linux/mips/fxstat.c
+index 11511d30b3..4a6016ff12 100644
+--- a/sysdeps/unix/sysv/linux/mips/fxstat.c
++++ b/sysdeps/unix/sysv/linux/mips/fxstat.c
+@@ -35,7 +35,9 @@ __fxstat (int vers, int fd, struct stat *buf)
+ {
+ struct kernel_stat kbuf;
+ int r = INTERNAL_SYSCALL_CALL (fstat, fd, &kbuf);
+- return r ?: __xstat_conv (vers, &kbuf, buf);
++ if (r == 0)
++ return __xstat_conv (vers, &kbuf, buf);
++ return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
+ }
+ }
+ }
+diff --git a/sysdeps/unix/sysv/linux/mips/lxstat.c b/sysdeps/unix/sysv/linux/mips/lxstat.c
+index 871fb6c6c5..54f990a250 100644
+--- a/sysdeps/unix/sysv/linux/mips/lxstat.c
++++ b/sysdeps/unix/sysv/linux/mips/lxstat.c
+@@ -35,7 +35,9 @@ __lxstat (int vers, const char *name, struct stat *buf)
+ {
+ struct kernel_stat kbuf;
+ int r = INTERNAL_SYSCALL_CALL (lstat, name, &kbuf);
+- return r ?: __xstat_conv (vers, &kbuf, buf);
++ if (r == 0)
++ return __xstat_conv (vers, &kbuf, buf);
++ return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
+ }
+ }
+ }
+diff --git a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
+index f346460f48..0055eec0b1 100644
+--- a/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/mips/mips32/arch-syscall.h
+@@ -251,6 +251,7 @@
+ #define __NR_pwritev2 4362
+ #define __NR_query_module 4187
+ #define __NR_quotactl 4131
++#define __NR_quotactl_fd 4443
+ #define __NR_read 4003
+ #define __NR_readahead 4223
+ #define __NR_readdir 4089
+diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
+index 38ed84997a..8e8e9f91cc 100644
+--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/arch-syscall.h
+@@ -232,6 +232,7 @@
+ #define __NR_pwritev2 6326
+ #define __NR_query_module 6171
+ #define __NR_quotactl 6172
++#define __NR_quotactl_fd 6443
+ #define __NR_read 6000
+ #define __NR_readahead 6179
+ #define __NR_readlink 6087
+diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
+index e6a10c8421..ebd1545f80 100644
+--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/arch-syscall.h
+@@ -219,6 +219,7 @@
+ #define __NR_pwritev2 5322
+ #define __NR_query_module 5171
+ #define __NR_quotactl 5172
++#define __NR_quotactl_fd 5443
+ #define __NR_read 5000
+ #define __NR_readahead 5179
+ #define __NR_readlink 5087
+diff --git a/sysdeps/unix/sysv/linux/mips/xstat.c b/sysdeps/unix/sysv/linux/mips/xstat.c
+index 9d810b6f65..86f4dc31a8 100644
+--- a/sysdeps/unix/sysv/linux/mips/xstat.c
++++ b/sysdeps/unix/sysv/linux/mips/xstat.c
+@@ -35,7 +35,9 @@ __xstat (int vers, const char *name, struct stat *buf)
+ {
+ struct kernel_stat kbuf;
+ int r = INTERNAL_SYSCALL_CALL (stat, name, &kbuf);
+- return r ?: __xstat_conv (vers, &kbuf, buf);
++ if (r == 0)
++ return __xstat_conv (vers, &kbuf, buf);
++ return INLINE_SYSCALL_ERROR_RETURN_VALUE (-r);
+ }
+ }
+ }
+diff --git a/sysdeps/unix/sysv/linux/mq_notify.c b/sysdeps/unix/sysv/linux/mq_notify.c
+index 9799dcdaa4..eccae2e4c6 100644
+--- a/sysdeps/unix/sysv/linux/mq_notify.c
++++ b/sysdeps/unix/sysv/linux/mq_notify.c
+@@ -131,7 +131,7 @@ helper_thread (void *arg)
+ to wait until it is done with it. */
+ (void) __pthread_barrier_wait (&notify_barrier);
+ }
+- else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED)
++ else if (data.raw[NOTIFY_COOKIE_LEN - 1] == NOTIFY_REMOVED && data.attr != NULL)
+ {
+ /* The only state we keep is the copy of the thread attributes. */
+ __pthread_attr_destroy (data.attr);
+diff --git a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
+index 5314890289..2b530b1f88 100644
+--- a/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/nios2/arch-syscall.h
+@@ -198,6 +198,7 @@
+ #define __NR_pwritev 70
+ #define __NR_pwritev2 287
+ #define __NR_quotactl 60
++#define __NR_quotactl_fd 443
+ #define __NR_read 63
+ #define __NR_readahead 213
+ #define __NR_readlinkat 78
+diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
+index b5b0758532..a32984a9c1 100644
+--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/arch-syscall.h
+@@ -260,6 +260,7 @@
+ #define __NR_pwritev2 381
+ #define __NR_query_module 166
+ #define __NR_quotactl 131
++#define __NR_quotactl_fd 443
+ #define __NR_read 3
+ #define __NR_readahead 191
+ #define __NR_readdir 89
+diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
+index c77435ca61..b01e464fb9 100644
+--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/arch-syscall.h
+@@ -243,6 +243,7 @@
+ #define __NR_pwritev2 381
+ #define __NR_query_module 166
+ #define __NR_quotactl 131
++#define __NR_quotactl_fd 443
+ #define __NR_read 3
+ #define __NR_readahead 191
+ #define __NR_readdir 89
+diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
+index 70854bb9e3..24d0a2c455 100644
+--- a/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/riscv/rv32/arch-syscall.h
+@@ -179,6 +179,7 @@
+ #define __NR_pwritev 70
+ #define __NR_pwritev2 287
+ #define __NR_quotactl 60
++#define __NR_quotactl_fd 443
+ #define __NR_read 63
+ #define __NR_readahead 213
+ #define __NR_readlinkat 78
+diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
+index 83b9f31aba..e526c89ae7 100644
+--- a/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/riscv/rv64/arch-syscall.h
+@@ -187,6 +187,7 @@
+ #define __NR_pwritev 70
+ #define __NR_pwritev2 287
+ #define __NR_quotactl 60
++#define __NR_quotactl_fd 443
+ #define __NR_read 63
+ #define __NR_readahead 213
+ #define __NR_readlinkat 78
+diff --git a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
+index e9bd3684db..00e73a3e3b 100644
+--- a/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
++++ b/sysdeps/unix/sysv/linux/s390/bits/hwcap.h
+@@ -22,6 +22,11 @@
+
+ /*
+ * The following must match the kernels asm/elf.h.
++ * Note: The kernel commit 511ad531afd4090625def4d9aba1f5227bd44b8e
++ * "s390/hwcaps: shorten HWCAP defines" has shortened the prefix of the macros
++ * from "HWCAP_S390_" to "HWCAP_". For compatibility reasons, we do not
++ * change the prefix in public glibc header file.
++ *
+ * Note that these are *not* the same as the STORE FACILITY LIST bits.
+ */
+ #define HWCAP_S390_ESAN3 1
+@@ -48,3 +53,5 @@
+ #define HWCAP_S390_DFLT 262144
+ #define HWCAP_S390_VXRS_PDE2 524288
+ #define HWCAP_S390_NNPA 1048576
++#define HWCAP_S390_PCI_MIO 2097152
++#define HWCAP_S390_SIE 4194304
+diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
+index b224c4aad4..d4c7b101b6 100644
+--- a/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/s390/s390-32/arch-syscall.h
+@@ -251,6 +251,7 @@
+ #define __NR_pwritev2 377
+ #define __NR_query_module 167
+ #define __NR_quotactl 131
++#define __NR_quotactl_fd 443
+ #define __NR_read 3
+ #define __NR_readahead 222
+ #define __NR_readdir 89
+diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
+index 59864af125..bd8c78d705 100644
+--- a/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/s390/s390-64/arch-syscall.h
+@@ -221,6 +221,7 @@
+ #define __NR_pwritev2 377
+ #define __NR_query_module 167
+ #define __NR_quotactl 131
++#define __NR_quotactl_fd 443
+ #define __NR_read 3
+ #define __NR_readahead 222
+ #define __NR_readdir 89
+diff --git a/sysdeps/unix/sysv/linux/sh/arch-syscall.h b/sysdeps/unix/sysv/linux/sh/arch-syscall.h
+index 23612c9092..3b6ac3d084 100644
+--- a/sysdeps/unix/sysv/linux/sh/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/sh/arch-syscall.h
+@@ -246,6 +246,7 @@
+ #define __NR_pwritev 334
+ #define __NR_pwritev2 382
+ #define __NR_quotactl 131
++#define __NR_quotactl_fd 443
+ #define __NR_read 3
+ #define __NR_readahead 225
+ #define __NR_readdir 89
+diff --git a/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h b/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h
+index b481b4f9f8..45db6b6ffb 100644
+--- a/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h
++++ b/sysdeps/unix/sysv/linux/sparc/bits/struct_stat.h
+@@ -28,32 +28,35 @@
+
+ struct stat
+ {
++#ifdef __USE_TIME_BITS64
++# include <bits/struct_stat_time64_helper.h>
++#else
+ __dev_t st_dev; /* Device. */
+-#if __WORDSIZE == 64 || !defined __USE_FILE_OFFSET64
++# if __WORDSIZE == 64 || !defined __USE_FILE_OFFSET64
+ unsigned short int __pad1;
+ __ino_t st_ino; /* File serial number. */
+-#else
++# else
+ __ino64_t st_ino; /* File serial number. */
+-#endif
++# endif
+ __mode_t st_mode; /* File mode. */
+ __nlink_t st_nlink; /* Link count. */
+ __uid_t st_uid; /* User ID of the file's owner. */
+ __gid_t st_gid; /* Group ID of the file's group.*/
+ __dev_t st_rdev; /* Device number, if device. */
+ unsigned short int __pad2;
+-#ifndef __USE_FILE_OFFSET64
++# ifndef __USE_FILE_OFFSET64
+ __off_t st_size; /* Size of file, in bytes. */
+-#else
++# else
+ __off64_t st_size; /* Size of file, in bytes. */
+-#endif
++# endif
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
+
+-#ifndef __USE_FILE_OFFSET64
++# ifndef __USE_FILE_OFFSET64
+ __blkcnt_t st_blocks; /* Number 512-byte blocks allocated. */
+-#else
++# else
+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
+-#endif
+-#ifdef __USE_XOPEN2K8
++# endif
++# ifdef __USE_XOPEN2K8
+ /* Nanosecond resolution timestamps are stored in a format
+ equivalent to 'struct timespec'. This is the type used
+ whenever possible but the Unix namespace rules do not allow the
+@@ -63,28 +66,32 @@ struct stat
+ struct timespec st_atim; /* Time of last access. */
+ struct timespec st_mtim; /* Time of last modification. */
+ struct timespec st_ctim; /* Time of last status change. */
+-# define st_atime st_atim.tv_sec /* Backward compatibility. */
+-# define st_mtime st_mtim.tv_sec
+-# define st_ctime st_ctim.tv_sec
+-#else
++# define st_atime st_atim.tv_sec /* Backward compatibility. */
++# define st_mtime st_mtim.tv_sec
++# define st_ctime st_ctim.tv_sec
++# else
+ __time_t st_atime; /* Time of last access. */
+ unsigned long int st_atimensec; /* Nscecs of last access. */
+ __time_t st_mtime; /* Time of last modification. */
+ unsigned long int st_mtimensec; /* Nsecs of last modification. */
+ __time_t st_ctime; /* Time of last status change. */
+ unsigned long int st_ctimensec; /* Nsecs of last status change. */
+-#endif
++# endif
+ unsigned long int __glibc_reserved4;
+ unsigned long int __glibc_reserved5;
++#endif /* __USE_TIME_BITS64 */
+ };
+
+ #ifdef __USE_LARGEFILE64
+ struct stat64
+ {
++# ifdef __USE_TIME_BITS64
++# include <bits/struct_stat_time64_helper.h>
++# else
+ __dev_t st_dev; /* Device. */
+-# if __WORDSIZE == 64
++# if __WORDSIZE == 64
+ unsigned short int __pad1;
+-# endif
++# endif
+ __ino64_t st_ino; /* File serial number. */
+ __mode_t st_mode; /* File mode. */
+ __nlink_t st_nlink; /* Link count. */
+@@ -96,7 +103,7 @@ struct stat64
+ __blksize_t st_blksize; /* Optimal block size for I/O. */
+
+ __blkcnt64_t st_blocks; /* Number 512-byte blocks allocated. */
+-# ifdef __USE_XOPEN2K8
++# ifdef __USE_XOPEN2K8
+ /* Nanosecond resolution timestamps are stored in a format
+ equivalent to 'struct timespec'. This is the type used
+ whenever possible but the Unix namespace rules do not allow the
+@@ -106,19 +113,20 @@ struct stat64
+ struct timespec st_atim; /* Time of last access. */
+ struct timespec st_mtim; /* Time of last modification. */
+ struct timespec st_ctim; /* Time of last status change. */
+-# define st_atime st_atim.tv_sec /* Backward compatibility. */
+-# define st_mtime st_mtim.tv_sec
+-# define st_ctime st_ctim.tv_sec
+-# else
++# define st_atime st_atim.tv_sec /* Backward compatibility. */
++# define st_mtime st_mtim.tv_sec
++# define st_ctime st_ctim.tv_sec
++# else
+ __time_t st_atime; /* Time of last access. */
+ unsigned long int st_atimensec; /* Nscecs of last access. */
+ __time_t st_mtime; /* Time of last modification. */
+ unsigned long int st_mtimensec; /* Nsecs of last modification. */
+ __time_t st_ctime; /* Time of last status change. */
+ unsigned long int st_ctimensec; /* Nsecs of last status change. */
+-# endif
++# endif
+ unsigned long int __glibc_reserved4;
+ unsigned long int __glibc_reserved5;
++# endif /* __USE_TIME_BITS64 */
+ };
+ #endif
+
+diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
+index 380cddb2d8..35221a707e 100644
+--- a/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/sparc/sparc32/arch-syscall.h
+@@ -252,6 +252,7 @@
+ #define __NR_pwritev2 359
+ #define __NR_query_module 184
+ #define __NR_quotactl 165
++#define __NR_quotactl_fd 443
+ #define __NR_read 3
+ #define __NR_readahead 205
+ #define __NR_readdir 204
+diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
+index 2175eeb6ed..5ba2b20509 100644
+--- a/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/sparc/sparc64/arch-syscall.h
+@@ -231,6 +231,7 @@
+ #define __NR_pwritev2 359
+ #define __NR_query_module 184
+ #define __NR_quotactl 165
++#define __NR_quotactl_fd 443
+ #define __NR_read 3
+ #define __NR_readahead 205
+ #define __NR_readdir 204
+diff --git a/sysdeps/unix/sysv/linux/sys/prctl.h b/sysdeps/unix/sysv/linux/sys/prctl.h
+index db88938b3a..f0e0d2f27f 100644
+--- a/sysdeps/unix/sysv/linux/sys/prctl.h
++++ b/sysdeps/unix/sysv/linux/sys/prctl.h
+@@ -42,7 +42,7 @@ __BEGIN_DECLS
+ extern int prctl (int __option, ...) __THROW;
+ #else
+ # ifdef __REDIRECT
+-extern int __REDIRECT (prctl, (int __option, ...), __prctl_time64) __THROW;
++extern int __REDIRECT_NTH (prctl, (int __option, ...), __prctl_time64);
+ # else
+ extern int __prctl_time64 (int __option,d ...) __THROW;
+ # define ioctl __prctl_time64
+diff --git a/sysdeps/unix/sysv/linux/syscall-names.list b/sysdeps/unix/sysv/linux/syscall-names.list
+index 89c5895b9b..fd98893b0e 100644
+--- a/sysdeps/unix/sysv/linux/syscall-names.list
++++ b/sysdeps/unix/sysv/linux/syscall-names.list
+@@ -21,8 +21,8 @@
+ # This file can list all potential system calls. The names are only
+ # used if the installed kernel headers also provide them.
+
+-# The list of system calls is current as of Linux 5.13.
+-kernel 5.13
++# The list of system calls is current as of Linux 5.14.
++kernel 5.14
+
+ FAST_atomic_update
+ FAST_cmpxchg
+@@ -247,6 +247,7 @@ madvise
+ mbind
+ membarrier
+ memfd_create
++memfd_secret
+ memory_ordering
+ migrate_pages
+ mincore
+@@ -452,6 +453,7 @@ pwritev
+ pwritev2
+ query_module
+ quotactl
++quotactl_fd
+ read
+ readahead
+ readdir
+diff --git a/sysdeps/unix/sysv/linux/tst-close_range.c b/sysdeps/unix/sysv/linux/tst-close_range.c
+index dccb6189c5..f5069d1b8a 100644
+--- a/sysdeps/unix/sysv/linux/tst-close_range.c
++++ b/sysdeps/unix/sysv/linux/tst-close_range.c
+@@ -36,23 +36,12 @@
+
+ #define NFDS 100
+
+-static int
+-open_multiple_temp_files (void)
+-{
+- /* Check if the temporary file descriptor has no no gaps. */
+- int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
+- for (int i = 1; i <= NFDS; i++)
+- TEST_COMPARE (xopen ("/dev/null", O_RDONLY, 0600),
+- lowfd + i);
+- return lowfd;
+-}
+-
+ static void
+ close_range_test_max_upper_limit (void)
+ {
+ struct support_descriptors *descrs = support_descriptors_list ();
+
+- int lowfd = open_multiple_temp_files ();
++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
+
+ {
+ int r = close_range (lowfd, ~0U, 0);
+@@ -68,7 +57,7 @@ close_range_test_max_upper_limit (void)
+ static void
+ close_range_test_common (int lowfd, unsigned int flags)
+ {
+- const int maximum_fd = lowfd + NFDS;
++ const int maximum_fd = lowfd + NFDS - 1;
+ const int half_fd = lowfd + NFDS / 2;
+ const int gap_1 = maximum_fd - 8;
+
+@@ -121,7 +110,7 @@ close_range_test (void)
+ struct support_descriptors *descrs = support_descriptors_list ();
+
+ /* Check if the temporary file descriptor has no no gaps. */
+- int lowfd = open_multiple_temp_files ();
++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
+
+ close_range_test_common (lowfd, 0);
+
+@@ -146,7 +135,7 @@ close_range_test_subprocess (void)
+ struct support_descriptors *descrs = support_descriptors_list ();
+
+ /* Check if the temporary file descriptor has no no gaps. */
+- int lowfd = open_multiple_temp_files ();
++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
+
+ struct support_stack stack = support_stack_alloc (4096);
+
+@@ -184,7 +173,7 @@ close_range_unshare_test (void)
+ struct support_descriptors *descrs1 = support_descriptors_list ();
+
+ /* Check if the temporary file descriptor has no no gaps. */
+- int lowfd = open_multiple_temp_files ();
++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
+
+ struct support_descriptors *descrs2 = support_descriptors_list ();
+
+@@ -200,7 +189,7 @@ close_range_unshare_test (void)
+
+ support_stack_free (&stack);
+
+- for (int i = 0; i < NFDS; i++)
++ for (int i = lowfd; i < lowfd + NFDS; i++)
+ TEST_VERIFY (fcntl (i, F_GETFL) > -1);
+
+ support_descriptors_check (descrs2);
+@@ -226,9 +215,9 @@ static void
+ close_range_cloexec_test (void)
+ {
+ /* Check if the temporary file descriptor has no no gaps. */
+- const int lowfd = open_multiple_temp_files ();
++ int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
+
+- const int maximum_fd = lowfd + NFDS;
++ const int maximum_fd = lowfd + NFDS - 1;
+ const int half_fd = lowfd + NFDS / 2;
+ const int gap_1 = maximum_fd - 8;
+
+@@ -251,13 +240,13 @@ close_range_cloexec_test (void)
+ /* Create some gaps, close up to a threshold, and check result. */
+ static int gap_close[] = { 57, 78, 81, 82, 84, 90 };
+ for (int i = 0; i < array_length (gap_close); i++)
+- xclose (gap_close[i]);
++ xclose (lowfd + gap_close[i]);
+
+ TEST_COMPARE (close_range (half_fd + 1, gap_1, CLOSE_RANGE_CLOEXEC), 0);
+ for (int i = half_fd + 1; i < gap_1; i++)
+ {
+ int flags = fcntl (i, F_GETFD);
+- if (is_in_array (gap_close, array_length (gap_close), i))
++ if (is_in_array (gap_close, array_length (gap_close), i - lowfd))
+ TEST_COMPARE (flags, -1);
+ else
+ {
+diff --git a/sysdeps/unix/sysv/linux/tst-mman-consts.py b/sysdeps/unix/sysv/linux/tst-mman-consts.py
+index ee5b13ee12..810433c238 100644
+--- a/sysdeps/unix/sysv/linux/tst-mman-consts.py
++++ b/sysdeps/unix/sysv/linux/tst-mman-consts.py
+@@ -33,7 +33,7 @@ def main():
+ help='C compiler (including options) to use')
+ args = parser.parse_args()
+ linux_version_headers = glibcsyscalls.linux_kernel_version(args.cc)
+- linux_version_glibc = (5, 13)
++ linux_version_glibc = (5, 14)
+ sys.exit(glibcextract.compare_macro_consts(
+ '#define _GNU_SOURCE 1\n'
+ '#include <sys/mman.h>\n',
+diff --git a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
+index 8e028eb62b..26d6ac68a6 100644
+--- a/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/x86_64/64/arch-syscall.h
+@@ -154,6 +154,7 @@
+ #define __NR_mbind 237
+ #define __NR_membarrier 324
+ #define __NR_memfd_create 319
++#define __NR_memfd_secret 447
+ #define __NR_migrate_pages 256
+ #define __NR_mincore 27
+ #define __NR_mkdir 83
+@@ -224,6 +225,7 @@
+ #define __NR_pwritev2 328
+ #define __NR_query_module 178
+ #define __NR_quotactl 179
++#define __NR_quotactl_fd 443
+ #define __NR_read 0
+ #define __NR_readahead 187
+ #define __NR_readlink 89
+diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
+index 004feb53f1..36847783f6 100644
+--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
++++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
+@@ -148,6 +148,7 @@
+ #define __NR_mbind 1073742061
+ #define __NR_membarrier 1073742148
+ #define __NR_memfd_create 1073742143
++#define __NR_memfd_secret 1073742271
+ #define __NR_migrate_pages 1073742080
+ #define __NR_mincore 1073741851
+ #define __NR_mkdir 1073741907
+@@ -216,6 +217,7 @@
+ #define __NR_pwritev 1073742359
+ #define __NR_pwritev2 1073742371
+ #define __NR_quotactl 1073742003
++#define __NR_quotactl_fd 1073742267
+ #define __NR_read 1073741824
+ #define __NR_readahead 1073742011
+ #define __NR_readlink 1073741913
+diff --git a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S
+index 9f02624375..abde8438d4 100644
+--- a/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S
++++ b/sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S
+@@ -325,7 +325,7 @@ L(movsb):
+ /* Avoid slow backward REP MOVSB. */
+ jb L(more_8x_vec_backward)
+ # if AVOID_SHORT_DISTANCE_REP_MOVSB
+- andl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip)
++ testl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip)
+ jz 3f
+ movq %rdi, %rcx
+ subq %rsi, %rcx
+@@ -333,7 +333,7 @@ L(movsb):
+ # endif
+ 1:
+ # if AVOID_SHORT_DISTANCE_REP_MOVSB
+- andl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip)
++ testl $X86_STRING_CONTROL_AVOID_SHORT_DISTANCE_REP_MOVSB, __x86_string_control(%rip)
+ jz 3f
+ movq %rsi, %rcx
+ subq %rdi, %rcx

Generated by cgit