[PATCH 3/5] Linux: Implement per-thread file system attributes

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Tue Dec 9 18:13:34 GMT 2025



On 09/12/25 14:31, Florian Weimer wrote:
> This commit adds the functions pthread_attr_setperthreadfs_np and
> pthread_attr_getperthreadfs_np.
> 
> The implementation is based on suppressing the CLONE_FS clone flag when
> creating the new thread.  The new flag is sticky and is applied to
> all threads created from a thread with the PTHREAD_PER_THREAD_NP
> attribute.

Should we add auxiliary functions to get the current per-thread file
system attribute, similar to what pthread_setcancelstate does for
the second argument?

>> +If a thread that has been created with the
>> +@code{PTHREAD_PER_THREAD_NP} flag creates further threads, these
>> +threads are implicitly created with the @code{PTHREAD_PER_THREAD_NP}
>> +flag, ignoring the value of this thread creation attribute.

Does it mean that if I create a thread with PTHREAD_PER_THREAD_NP, and
later create a thread with PTHREAD_PER_PROCESS_NP from the newly
created thread, the PTHREAD_PER_PROCESS_NP will be silent ignored? If
so, this seems confusing.

>> +(If this behavior is not desirable, it is possible to call
>> +@samp{unshare (CLONE_FS)} from the new thread instead of creating it
>> +with the @code{PTHREAD_PER_THREAD_NP} flag.)

Requering to call a different API to 'undo' the stick bit setup also
seems confusing. Why this can't be done at thread creation before
calling the user-provded pthread_cancel routine?


> ---
>  NEWS                                          |   5 +
>  manual/threads.texi                           |  95 ++++++
>  nptl/Makefile                                 |   4 +
>  nptl/Versions                                 |   2 +
>  nptl/pthread_attr_getperthreadfs_np.c         |  32 ++
>  nptl/pthread_attr_setperthreadfs_np.c         |  39 +++
>  nptl/pthread_create.c                         |  20 +-
>  nptl/tst-pthread-perthreadfs-chroot.c         | 255 ++++++++++++++
>  nptl/tst-pthread-perthreadfs.c                | 322 ++++++++++++++++++
>  sysdeps/nptl/internaltypes.h                  |  12 +
>  sysdeps/nptl/pthread.h                        |  26 +-
>  sysdeps/unix/sysv/linux/aarch64/libc.abilist  |   2 +
>  sysdeps/unix/sysv/linux/alpha/libc.abilist    |   2 +
>  sysdeps/unix/sysv/linux/arc/libc.abilist      |   2 +
>  sysdeps/unix/sysv/linux/arm/be/libc.abilist   |   2 +
>  sysdeps/unix/sysv/linux/arm/le/libc.abilist   |   2 +
>  sysdeps/unix/sysv/linux/csky/libc.abilist     |   2 +
>  sysdeps/unix/sysv/linux/hppa/libc.abilist     |   2 +
>  sysdeps/unix/sysv/linux/i386/libc.abilist     |   2 +
>  .../sysv/linux/loongarch/lp64/libc.abilist    |   2 +
>  .../sysv/linux/m68k/coldfire/libc.abilist     |   2 +
>  .../unix/sysv/linux/m68k/m680x0/libc.abilist  |   2 +
>  .../sysv/linux/microblaze/be/libc.abilist     |   2 +
>  .../sysv/linux/microblaze/le/libc.abilist     |   2 +
>  .../sysv/linux/mips/mips32/fpu/libc.abilist   |   2 +
>  .../sysv/linux/mips/mips32/nofpu/libc.abilist |   2 +
>  .../sysv/linux/mips/mips64/n32/libc.abilist   |   2 +
>  .../sysv/linux/mips/mips64/n64/libc.abilist   |   2 +
>  sysdeps/unix/sysv/linux/or1k/libc.abilist     |   2 +
>  .../linux/powerpc/powerpc32/fpu/libc.abilist  |   2 +
>  .../powerpc/powerpc32/nofpu/libc.abilist      |   2 +
>  .../linux/powerpc/powerpc64/be/libc.abilist   |   2 +
>  .../linux/powerpc/powerpc64/le/libc.abilist   |   2 +
>  .../unix/sysv/linux/riscv/rv32/libc.abilist   |   2 +
>  .../unix/sysv/linux/riscv/rv64/libc.abilist   |   2 +
>  .../unix/sysv/linux/s390/s390-32/libc.abilist |   2 +
>  .../unix/sysv/linux/s390/s390-64/libc.abilist |   2 +
>  sysdeps/unix/sysv/linux/sh/be/libc.abilist    |   2 +
>  sysdeps/unix/sysv/linux/sh/le/libc.abilist    |   2 +
>  .../sysv/linux/sparc/sparc32/libc.abilist     |   2 +
>  .../sysv/linux/sparc/sparc64/libc.abilist     |   2 +
>  .../unix/sysv/linux/x86_64/64/libc.abilist    |   2 +
>  .../unix/sysv/linux/x86_64/x32/libc.abilist   |   2 +
>  43 files changed, 867 insertions(+), 9 deletions(-)
>  create mode 100644 nptl/pthread_attr_getperthreadfs_np.c
>  create mode 100644 nptl/pthread_attr_setperthreadfs_np.c
>  create mode 100644 nptl/tst-pthread-perthreadfs-chroot.c
>  create mode 100644 nptl/tst-pthread-perthreadfs.c
> 
> diff --git a/NEWS b/NEWS
> index 6964ca074e..1bd9f8b795 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -58,6 +58,11 @@ Major new features:
>    openat and provides a superset of its functionality.  It is supported only
>    in LFS mode and it is a cancellable entrypoint.
>  
> +* On Linux, it is now possible to create threads with per-thread current
> +  directory, umask, and file system root.  The functions
> +  pthread_attr_setperthreadfs_np and pthread_attr_getperthreadfs_np have
> +  been added in support of that.
> +
>  Deprecated and removed features, and other changes affecting compatibility:
>  
>  * Support for dumped heaps has been removed - malloc_set_state() now always
> diff --git a/manual/threads.texi b/manual/threads.texi
> index b9d12479ca..8df694cc43 100644
> --- a/manual/threads.texi
> +++ b/manual/threads.texi
> @@ -1145,6 +1145,7 @@ the standard.
>  * Default Thread Attributes::             Setting default attributes for
>  					  threads in a process.
>  * Initial Thread Signal Mask::            Setting the initial mask of threads.
> +* Enabling Per-Thread Properties::        Additional per-thread properties.
>  * Thread CPU Affinity::			  Limiting which CPUs can run a thread.
>  * Joining Threads::                       Wait for a thread to terminate.
>  * Thread Names::			  Changing the name of a thread.
> @@ -1266,6 +1267,100 @@ signal mask and use @code{pthread_sigmask} to apply it to the thread.
>  If the signal mask was copied to a heap allocation, the copy should be
>  freed.
>  
> +@node Enabling Per-Thread Properties
> +@subsubsection Enabling Additional Per-Thread Properties
> +
> +POSIX mandates that the current directory, file system root, umask
> +value, and the current user and group IDs are process-global
> +properties.  For example, if a thread calls the @code{chdir} function
> +to change to a different directory, all threads are eventually
> +affected by this change.  @Theglibc{} implements an extension which
> +allows threads to be created which do not share these properties with
> +the rest of the process.
> +
> +The desired behavior is specified at the time the thread is created,
> +using the thread attribute.  The following constants are used to
> +update the attribute:
> +
> +@vtable @code
> +@item PTHREAD_PER_PROCESS_NP
> +@standards{GNU, pthread.h}
> +This property in question is globally shared across the entire process.
> +This is the default.
> +
> +@item PTHREAD_PER_THREAD_NP
> +@standards{GNU, pthread.h}
> +This property in question is thread-specific.
> +@end vtable
> +
> +The @code{PTHREAD_PER_THREAD_NP} flag is sticky, in the sense that all
> +threads created by a thread created with this flag have per-thread
> +properties, even if they are created with the matching thread
> +attribute set to the @code{PTHREAD_PER_PROCESS_NP} flag.  If an
> +application wants to create new threads sharing properties with the
> +main thread, it should create a service thread early (perhaps from an
> +ELF constructor) and create these threads using this service thread.
> +
> +Per-thread properties can be set and examined for an attribute using
> +the functions below.
> +
> +@deftypefun int pthread_attr_setperthreadfs_np (pthread_attr_t *@var{attr}, int @var{scope})
> +@standards{GNU, pthread.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +Change whether the following properties related to file system access
> +are made thread-specific when a new thread is created using the
> +attribute @var{attr}:
> +
> +@itemize @bullet
> +@item
> +@cindex current directory as a per-thread property
> +@cindex per-thread current directory
> +@cindex thread-specific current directory
> +current directory (as changed by @code{chdir} and related functions)
> +
> +@item
> +@cindex @code{chroot} as a per-thread property
> +@cindex per-thread @code{chroot}
> +@cindex thread-specific @code{chroot}
> +file system root (as changed by @code{chroot})
> +
> +@item
> +@cindex umask as a per-thread property
> +@cindex per-thread @code{umask}
> +@cindex thread-specific @code{umask}
> +umask value (as changed by the function of the same name)
> +@end itemize
> +
> +This function returns zero on success.  @var{scope} must be one of the
> +constants @code{PTHREAD_PER_PROCESS_NP} or
> +@code{PTHREAD_PER_THREAD_NP}, otherwise the function returns
> +@code{EINVAL}.
> +
> +If @var{scope} is @code{PTHREAD_PER_THREAD_NP}, the attribute will
> +cause the properties listed above to be specific to the thread.  The
> +initial values of these properties are copied from the creating
> +thread, at thread creation time.
> +
> +If a thread that has been created with the
> +@code{PTHREAD_PER_THREAD_NP} flag creates further threads, these
> +threads are implicitly created with the @code{PTHREAD_PER_THREAD_NP}
> +flag, ignoring the value of this thread creation attribute.
> +(If this behavior is not desirable, it is possible to call
> +@samp{unshare (CLONE_FS)} from the new thread instead of creating it
> +with the @code{PTHREAD_PER_THREAD_NP} flag.)
> +
> +This function is a GNU extension and specific to Linux.
> +@end deftypefun
> +
> +@deftypefun int pthread_attr_getperthreadfs_np (pthread_attr_t *restrict @var{attr}, int *restrict @var{scope})
> +@standards{GNU, pthread.h}
> +@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
> +Obtain the per-thread status of the file system properties in
> +@var{attr} and store it in the location @var{scope}.
> +
> +This function is a GNU extension and specific to Linux.
> +@end deftypefun
> +
>  @node Thread CPU Affinity
>  @subsubsection Thread CPU Affinity
>  
> diff --git a/nptl/Makefile b/nptl/Makefile
> index 81d6a5482c..05c6c32a76 100644
> --- a/nptl/Makefile
> +++ b/nptl/Makefile
> @@ -65,6 +65,7 @@ routines = \
>    pthread_attr_getdetachstate \
>    pthread_attr_getguardsize \
>    pthread_attr_getinheritsched \
> +  pthread_attr_getperthreadfs_np \
>    pthread_attr_getschedparam \
>    pthread_attr_getschedpolicy \
>    pthread_attr_getscope \
> @@ -77,6 +78,7 @@ routines = \
>    pthread_attr_setdetachstate \
>    pthread_attr_setguardsize \
>    pthread_attr_setinheritsched \
> +  pthread_attr_setperthreadfs_np \
>    pthread_attr_setschedparam \
>    pthread_attr_setschedpolicy \
>    pthread_attr_setscope \
> @@ -317,6 +319,8 @@ tests = \
>    tst-pthread-gdb-attach-static \
>    tst-pthread-getcpuclockid-invalid \
>    tst-pthread-key1-static \
> +  tst-pthread-perthreadfs \
> +  tst-pthread-perthreadfs-chroot \
>    tst-pthread-timedlock-lockloop \
>    tst-pthread_exit-nothreads \
>    tst-pthread_exit-nothreads-static \
> diff --git a/nptl/Versions b/nptl/Versions
> index b813b675b9..c4ff312468 100644
> --- a/nptl/Versions
> +++ b/nptl/Versions
> @@ -382,6 +382,8 @@ libc {
>      pthread_gettid_np;
>    }
>    GLIBC_2.43 {
> +    pthread_attr_setperthreadfs_np;
> +    pthread_attr_getperthreadfs_np;
>    }
>    GLIBC_PRIVATE {
>      __libc_alloca_cutoff;
> diff --git a/nptl/pthread_attr_getperthreadfs_np.c b/nptl/pthread_attr_getperthreadfs_np.c
> new file mode 100644
> index 0000000000..f5ff348cac
> --- /dev/null
> +++ b/nptl/pthread_attr_getperthreadfs_np.c
> @@ -0,0 +1,32 @@
> +/* Read the private file system flag in thread attributes.
> +   Copyright (C) 2025 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <pthread.h>
> +#include <internaltypes.h>
> +
> +int
> +pthread_attr_getperthreadfs_np (const pthread_attr_t *__restrict attr,
> +                                int *__restrict scope)
> +{
> +  struct pthread_attr *iattr = (struct pthread_attr *) attr;
> +  if (iattr->flags & ATTR_FLAG_PERTHREADFS)
> +    *scope = PTHREAD_PER_THREAD_NP;
> +  else
> +    *scope = PTHREAD_PER_PROCESS_NP;
> +  return 0;
> +}
> diff --git a/nptl/pthread_attr_setperthreadfs_np.c b/nptl/pthread_attr_setperthreadfs_np.c
> new file mode 100644
> index 0000000000..2d274cb144
> --- /dev/null
> +++ b/nptl/pthread_attr_setperthreadfs_np.c
> @@ -0,0 +1,39 @@
> +/* Change the private file system flag in thread attributes.
> +   Copyright (C) 2025 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <pthread.h>
> +#include <internaltypes.h>
> +#include <errno.h>
> +
> +int
> +pthread_attr_setperthreadfs_np (pthread_attr_t *attr, int scope)
> +{
> +  struct pthread_attr *iattr = (struct pthread_attr *) attr;
> +  switch (scope)
> +    {
> +    case PTHREAD_PER_PROCESS_NP:
> +      iattr->flags &= ~ATTR_FLAG_PERTHREADFS;
> +      return 0;
> +      break;
> +    case PTHREAD_PER_THREAD_NP:
> +      iattr->flags |= ATTR_FLAG_PERTHREADFS;
> +      return 0;
> +    default:
> +      return EINVAL;
> +    }
> +}
> diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
> index 19e4ec8064..39a4cf825f 100644
> --- a/nptl/pthread_create.c
> +++ b/nptl/pthread_create.c
> @@ -253,7 +253,9 @@ static int create_thread (struct pthread *pd, const struct pthread_attr *attr,
>  
>       CLONE_VM, CLONE_FS, CLONE_FILES
>  	These flags select semantics with shared address space and
> -	file descriptors according to what POSIX requires.
> +	file descriptors according to what POSIX requires.  CLONE_FS
> +	is optional; it can be controlled using the function
> +	pthread_attr_setperthreadfs_np.
>  
>       CLONE_SIGHAND, CLONE_THREAD
>  	This flag selects the POSIX signal semantics and various
> @@ -277,11 +279,13 @@ static int create_thread (struct pthread *pd, const struct pthread_attr *attr,
>  
>       The termination signal is chosen to be zero which means no signal
>       is sent.  */
> -  const int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SYSVSEM
> -			   | CLONE_SIGHAND | CLONE_THREAD
> -			   | CLONE_SETTLS | CLONE_PARENT_SETTID
> -			   | CLONE_CHILD_CLEARTID
> -			   | 0);
> +  int clone_flags = (CLONE_VM | CLONE_FILES | CLONE_SYSVSEM
> +		     | CLONE_SIGHAND | CLONE_THREAD
> +		     | CLONE_SETTLS | CLONE_PARENT_SETTID
> +		     | CLONE_CHILD_CLEARTID
> +		     | 0);
> +  if ((attr->flags & ATTR_FLAG_PERTHREADFS) == 0)
> +    clone_flags |= CLONE_FS;
>  
>    TLS_DEFINE_INIT_TP (tp, pd);
>  
> @@ -695,8 +699,8 @@ __pthread_create_2_1 (pthread_t *newthread, const pthread_attr_t *attr,
>  
>    /* Copy the thread attribute flags.  */
>    struct pthread *self = THREAD_SELF;
> -  pd->flags = ((iattr->flags & ~(ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET))
> -	       | (self->flags & (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)));
> +  pd->flags = ((iattr->flags & ~ATTR_FLAGS_IGNORED_ATTR)
> +	       | (self->flags & ATTR_FLAGS_INHERITED));
>  
>    /* Inherit rseq registration state.  Without seccomp filters, rseq
>       registration will either always fail or always succeed.  */
> diff --git a/nptl/tst-pthread-perthreadfs-chroot.c b/nptl/tst-pthread-perthreadfs-chroot.c
> new file mode 100644
> index 0000000000..094c291baa
> --- /dev/null
> +++ b/nptl/tst-pthread-perthreadfs-chroot.c
> @@ -0,0 +1,255 @@
> +/* Test per-thread file system attributes, chroot version.
> +   Copyright (C) 2025 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +/* This thread is separate from tst-pthread-perthreadfs because it
> +   requires chroot support.  */
> +
> +#include <fcntl.h>
> +#include <pthread.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <support/namespace.h>
> +#include <support/support.h>
> +#include <support/temp_file.h>
> +#include <support/xthread.h>
> +#include <support/xunistd.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +
> +/* Paths for chroot operations.  */
> +static char *chroot_1;
> +static char *chroot_2;
> +static char *chroot_3;
> +
> +/* These paths are used for recognizing chroots.  */
> +static const char *const chroot_1_marker = "/chroot-1-marker";
> +static const char *const chroot_2_marker = "/chroot-2-marker";
> +
> +/* Directory available in the chroot for a second chroot call.  */
> +static const char *const next_chroot = "/next_chroot";
> +
> +/* Return 0 for no chroot, 1 for first chroot, 2 for second chroot, or
> +   -1 for error.  */
> +static int
> +which_chroot (void)
> +{
> +  /* If the full (out-of-chroot) path is present, we are not in a
> +     chroot.  */
> +  if (access (chroot_1, F_OK) == 0)
> +    return 0;
> +  if (access (chroot_1_marker, F_OK) == 0)
> +    return 1;
> +  if (access (chroot_2_marker, F_OK) == 0)
> +    return 2;
> +  return -1;
> +}
> +
> +/* Thread attribute requesting per-thread file system attributes.  */
> +pthread_attr_t attr_perthreadfs;
> +
> +/* Used to synchronize operations among the threads.  This is needed
> +   so that the chroot changes happen in the expected order.  */
> +static pthread_barrier_t barrier;
> +
> +static void *
> +thread_which_chroot_helper (void *closure)
> +{
> +  int *result = closure;
> +  *result = which_chroot ();
> +  return NULL;
> +}
> +
> +static void *
> +thread_which_chroot_helper_perthread (void *closure)
> +{
> +  int *result = closure;
> +  *result = which_chroot ();
> +  if (*result == 0)
> +    /* No /next-chroot available without a first chroot.  */
> +    xchroot (chroot_3);
> +  else
> +    xchroot (next_chroot);
> +  return NULL;
> +}
> +
> +/* Determine the current chroot on another thread.  */
> +static int
> +thread_which_chroot (void)
> +{
> +  int result1;
> +  pthread_t thr = xpthread_create (NULL, thread_which_chroot_helper, &result1);
> +  xpthread_join (thr);
> +  /* Same using per-thread attributes.  They are supposed to be equal.
> +     Also change the chroot to check isolation.  */
> +  int result2;
> +  thr = xpthread_create (&attr_perthreadfs,
> +                         thread_which_chroot_helper_perthread, &result2);
> +  xpthread_join (thr);
> +  TEST_COMPARE (result1, result2);
> +  return result1;
> +}
> +
> +/* Verify that the file system attributes for the current thread are
> +   as expected.  */
> +static void
> +check_attributes (const char *where, int expected_chroot)
> +{
> +  printf ("info: reading file attributes in %s\n", where);
> +  TEST_COMPARE (which_chroot (), expected_chroot);
> +  TEST_COMPARE (thread_which_chroot (), expected_chroot);
> +}
> +
> +/* Thread function launched with per-thread file system
> +   attributes.  */
> +static void *
> +thread_perthreadfs (void *closure)
> +{
> +  puts ("info: changing file attributes in thread_perthreadfs");
> +  xchroot (chroot_1);
> +  check_attributes ("thread_perthreadfs", 1);
> +
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes read in thread_sharedfs here.  */
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes read in main thread here.  */
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes changed in thread_sharedfs here.  */
> +  pthread_barrier_wait (&barrier);
> +
> +  check_attributes ("thread_perthreadfs", 1);
> +
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes read in main thread here.  */
> +  pthread_barrier_wait (&barrier);
> +  return NULL;
> +}
> +
> +/* Thread function launched with shared file system attributes.  */
> +static void *
> +thread_sharedfs (void *closure)
> +{
> +  /* Wait for thread_perthreadfs to update chroot.  */
> +  pthread_barrier_wait (&barrier);
> +
> +  check_attributes ("thread_sharedfs", 0);
> +
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes read in main thread here.  */
> +  pthread_barrier_wait (&barrier);
> +
> +  puts ("info: changing file attributes in thread_sharedfs");
> +  xchroot (chroot_2);
> +  check_attributes ("thread_sharedfs", 2);
> +
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes read in thread_perthreadfs here.  */
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes read in main thread here.  */
> +  pthread_barrier_wait (&barrier);
> +  return NULL;
> +}
> +
> +static int
> +do_test (void)
> +{
> +  support_become_root ();
> +  if (!support_can_chroot ())
> +    FAIL_UNSUPPORTED ("chroot not supported");
> +
> +  /* Used to revert the effect of chroot.  */
> +  int original_chroot_fd = xopen ("/", O_DIRECTORY | O_RDONLY, 0);
> +
> +  TEST_COMPARE (access (chroot_1_marker, F_OK), -1);
> +  TEST_COMPARE (access (chroot_2_marker, F_OK), -1);
> +  TEST_COMPARE (access (next_chroot, F_OK), -1);
> +
> +  chroot_1 = support_create_temp_directory
> +    ("tst-pthread-perthreadfs-chroot-1-");
> +  chroot_2 = support_create_temp_directory
> +    ("tst-pthread-perthreadfs-chroot-2-");
> +  chroot_3 = support_create_temp_directory
> +    ("tst-pthread-perthreadfs-chroot-3-");
> +  {
> +    char *path = xasprintf ("%s%s", chroot_1, chroot_1_marker);
> +    xmkdir (path, 0777);
> +    add_temp_file (path);
> +    free (path);
> +
> +    path = xasprintf ("%s%s", chroot_1, next_chroot);
> +    xmkdir (path, 0777);
> +    add_temp_file (path);
> +    free (path);
> +
> +    path = xasprintf ("%s%s", chroot_2, chroot_2_marker);
> +    xmkdir (path, 0777);
> +    add_temp_file (path);
> +    free (path);
> +
> +    path = xasprintf ("%s%s", chroot_2, next_chroot);
> +    xmkdir (path, 0777);
> +    add_temp_file (path);
> +    free (path);
> +  }
> +  TEST_COMPARE (which_chroot (), 0);
> +
> +  xpthread_barrier_init (&barrier, NULL, 3);
> +  xpthread_attr_init (&attr_perthreadfs);
> +  TEST_COMPARE (pthread_attr_setperthreadfs_np (&attr_perthreadfs,
> +                                                PTHREAD_PER_THREAD_NP), 0);
> +
> +  pthread_t thr1 = xpthread_create (&attr_perthreadfs,
> +                                    thread_perthreadfs, NULL);
> +  pthread_t thr2 = xpthread_create (NULL, thread_sharedfs, NULL);
> +
> +  /* Wait for thread_perthreadfs to update chroot.  */
> +  xpthread_barrier_wait (&barrier);
> +  /* File attributes read thread_sharedfs here.  */
> +  xpthread_barrier_wait (&barrier);
> +
> +  check_attributes ("main thread", 0);
> +
> +  xpthread_barrier_wait (&barrier);
> +  /* File attributes changed thread_sharedfs here.  */
> +  xpthread_barrier_wait (&barrier);
> +  /* File attributes read in thread_perthreadfs here.  */
> +  xpthread_barrier_wait (&barrier);
> +
> +  check_attributes ("main thread", 2);
> +
> +  xpthread_barrier_wait (&barrier);
> +
> +  xpthread_join (thr2);
> +  xpthread_join (thr1);
> +
> +  xpthread_attr_destroy (&attr_perthreadfs);
> +  xpthread_barrier_destroy (&barrier);
> +
> +  free (chroot_3);
> +  free (chroot_2);
> +  free (chroot_1);
> +
> +  xfchdir (original_chroot_fd);
> +  xclose (original_chroot_fd);
> +  xchroot (".");
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/nptl/tst-pthread-perthreadfs.c b/nptl/tst-pthread-perthreadfs.c
> new file mode 100644
> index 0000000000..bb30449808
> --- /dev/null
> +++ b/nptl/tst-pthread-perthreadfs.c
> @@ -0,0 +1,322 @@
> +/* Test per-thread file system attributes.
> +   Copyright (C) 2025 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#include <errno.h>
> +#include <pthread.h>
> +#include <stdbool.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <support/check.h>
> +#include <support/temp_file.h>
> +#include <support/xthread.h>
> +#include <support/xunistd.h>
> +#include <sys/stat.h>
> +#include <unistd.h>
> +
> +/* Original values in the parent process.  */
> +static char *original_cwd;
> +static mode_t original_umask;
> +
> +/* New values for the attributes, distinct from the old.  */
> +static char *new_cwd_1;
> +static char *new_cwd_2;
> +static mode_t new_umask_1;
> +static mode_t new_umask_2;
> +
> +/* Thread attribute requesting per-thread file system attributes.  */
> +pthread_attr_t attr_perthreadfs;
> +
> +/* Used to synchronize operations among the threads.  This is needed
> +   so that the attribute changes happen in the expected order, and
> +   that get_umask_unlocked can be used safely.  */
> +static pthread_barrier_t barrier;
> +
> +/* Return true if the thread has per-thread file system attributes.
> +   Note: This function calls pthread_getattr_np on THR, so the caller
> +   has to ensure that the thread is still running (and not merely
> +   joinable).  */
> +static bool
> +perthread_flag (pthread_t thr)
> +{
> +  pthread_attr_t attr;
> +  int ret = pthread_getattr_np (thr, &attr);
> +  if (ret != 0)
> +    {
> +      errno = ret;
> +      FAIL_EXIT1 ("pthread_getattr_np: %m");
> +    }
> +  int flag = -1;
> +  pthread_attr_getperthreadfs_np (&attr, &flag);
> +  if (flag != PTHREAD_PER_THREAD_NP)
> +    TEST_COMPARE (flag, PTHREAD_PER_PROCESS_NP);
> +  xpthread_attr_destroy (&attr);
> +  return flag == PTHREAD_PER_THREAD_NP;
> +}
> +
> +/* Linux does not have getumask, so use synchronization and the umask
> +   system call to read the value.  */
> +static mode_t
> +get_umask_unlocked (void)
> +{
> +  mode_t mask = umask (0);
> +  TEST_COMPARE (umask (mask), 0);
> +  return mask;
> +}
> +
> +static void *
> +thread_get_pwd_helper (void *closure)
> +{
> +  char *result = get_current_dir_name ();
> +  if (closure != NULL)
> +    xchdir (closure);
> +  return result;
> +}
> +
> +/* Obtain the current directory on another thread.  */
> +static char *
> +thread_get_pwd (void)
> +{
> +  pthread_t thr = xpthread_create (NULL, thread_get_pwd_helper, NULL);
> +  char *path1 = xpthread_join (thr);
> +  /* Same using per-thread attributes.  They are supposed to be equal.
> +     Also change the current directory to check isolation.  */
> +  thr = xpthread_create (&attr_perthreadfs,
> +                         thread_get_pwd_helper, (char *) "/");
> +  char *path2 = xpthread_join (thr);
> +  TEST_COMPARE_STRING (path1, path2);
> +  free (path2);
> +  return path1;
> +}
> +
> +static void *
> +thread_get_umask_helper (void *closure)
> +{
> +  mode_t *pmask = closure;
> +  *pmask = get_umask_unlocked ();
> +  return NULL;
> +}
> +
> +static void *
> +thread_get_umask_helper_perthread (void *closure)
> +{
> +  mode_t *pmask = closure;
> +  *pmask = get_umask_unlocked ();
> +  /* Check isolation.  This bit pattern is not used anywhere else.  */
> +  TEST_COMPARE (umask (*pmask ^ 0101), *pmask);
> +  return NULL;
> +}
> +
> +/* Obtain the current umask on another thread.  */
> +static mode_t
> +thread_get_umask_unlocked (void)
> +{
> +  mode_t mask1;
> +  pthread_t thr = xpthread_create (NULL, thread_get_umask_helper, &mask1);
> +  xpthread_join (thr);
> +  mode_t mask2;
> +  thr = xpthread_create (&attr_perthreadfs,
> +                         thread_get_umask_helper_perthread, &mask2);
> +  xpthread_join (thr);
> +  TEST_COMPARE (mask1, mask2);
> +  return mask1;
> +}
> +
> +/* Verify that the file system attributes for the current thread are
> +   as expected.  */
> +static void
> +check_attributes (const char *where, mode_t expected_umask,
> +                  const char *expected_cwd)
> +{
> +  printf ("info: reading file attributes in %s\n", where);
> +  TEST_COMPARE (get_umask_unlocked (), expected_umask);
> +  TEST_COMPARE (thread_get_umask_unlocked (), expected_umask);
> +  char *cwd = get_current_dir_name ();
> +  TEST_COMPARE_STRING (cwd, expected_cwd);
> +  free (cwd);
> +  cwd = thread_get_pwd ();
> +  TEST_COMPARE_STRING (cwd, expected_cwd);
> +  free (cwd);
> +}
> +
> +/* Thread function launched with per-thread file system
> +   attributes.  */
> +static void *
> +thread_perthreadfs (void *closure)
> +{
> +  puts ("info: changing file attributes in thread_perthreadfs");
> +  TEST_VERIFY (perthread_flag (pthread_self ()));
> +  xchdir (new_cwd_1);
> +  TEST_COMPARE (umask (new_umask_1), original_umask);
> +  check_attributes ("thread_perthreadfs", new_umask_1, new_cwd_1);
> +
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes read in thread_sharedfs here.  */
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes read in main thread here.  */
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes changed in thread_sharedfs here.  */
> +  pthread_barrier_wait (&barrier);
> +
> +  check_attributes ("thread_perthreadfs", new_umask_1, new_cwd_1);
> +
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes read in main thread here.  */
> +  pthread_barrier_wait (&barrier);
> +  return NULL;
> +}
> +
> +/* Launched with PTHREAD_PER_THREAD_NP, but runs the actual test on a
> +   PTHREAD_PER_PROCESS_NP thread (with a default attribute).  */
> +static void *
> +thread_perthreadfs_indirect (void *closure)
> +{
> +  TEST_VERIFY (perthread_flag (pthread_self ()));
> +  /* Use the default NULL attribute here.  Since the per-thread scope
> +     is sticky, it will still result in a per-thread file system
> +     thread.  */
> +  pthread_t thr = xpthread_create (NULL, thread_perthreadfs, closure);
> +  return xpthread_join (thr);
> +}
> +
> +/* Thread function launched with shared file system attributes.  */
> +static void *
> +thread_sharedfs (void *closure)
> +{
> +  TEST_VERIFY (!perthread_flag (pthread_self ()));
> +
> +  /* Wait for thread_perthreadfs to update current directory and
> +     umask.  */
> +  pthread_barrier_wait (&barrier);
> +
> +  check_attributes ("thread_sharedfs", original_umask, original_cwd);
> +
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes read in main thread here.  */
> +  pthread_barrier_wait (&barrier);
> +
> +  puts ("info: changing file attributes in thread_sharedfs");
> +  TEST_COMPARE (umask (new_umask_2), original_umask);
> +  xchdir (new_cwd_2);
> +  check_attributes ("thread_sharedfs", new_umask_2, new_cwd_2);
> +
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes read in thread_perthreadfs here.  */
> +  pthread_barrier_wait (&barrier);
> +  /* File attributes read in main thread here.  */
> +  pthread_barrier_wait (&barrier);
> +  return NULL;
> +}
> +
> +static int
> +do_test (void)
> +{
> +  original_cwd = get_current_dir_name ();
> +  TEST_VERIFY_EXIT (original_cwd != NULL);
> +  original_umask = get_umask_unlocked ();
> +
> +  new_cwd_1 = support_create_temp_directory ("tst-pthread-perthreadfs-1-");
> +  new_cwd_2 = support_create_temp_directory ("tst-pthread-perthreadfs-2-");
> +  /* Arbitrary bit pattern change to obtain distinct values, so that
> +     it is possible to check for actual changes.  */
> +  new_umask_1 = original_umask ^ 0111;
> +  new_umask_2 = original_umask ^ 0222;
> +
> +  TEST_VERIFY (!perthread_flag (pthread_self ()));
> +
> +  xpthread_barrier_init (&barrier, NULL, 3);
> +  xpthread_attr_init (&attr_perthreadfs);
> +  {
> +    /* Test: Default is PTHREAD_PER_PROCESS_NP.  */
> +    int scope = -1;
> +    TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs, &scope),
> +                  0);
> +    TEST_COMPARE (scope, PTHREAD_PER_PROCESS_NP);
> +
> +    /* Test: The getter shows the effect of the setter.  */
> +    TEST_COMPARE (pthread_attr_setperthreadfs_np (&attr_perthreadfs,
> +                                                  PTHREAD_PER_THREAD_NP), 0);
> +    scope = -1;
> +    TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs, &scope),
> +                  0);
> +    TEST_COMPARE (scope, PTHREAD_PER_THREAD_NP);
> +
> +    /* Test: Invalid scope values result in an error, without a
> +       change.  */
> +    TEST_COMPARE (pthread_attr_setperthreadfs_np (&attr_perthreadfs, 2),
> +                  EINVAL);
> +    scope = -1;
> +    TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs, &scope),
> +                  0);
> +    TEST_COMPARE (scope, PTHREAD_PER_THREAD_NP);
> +  }
> +
> +  /* Two test runs, once with perthreadsfs set to
> +     PTHREAD_PER_THREAD_NP directly, once indirectly via inheritance
> +     from the current (overriding the PTHREAD_PER_PROCESS_NP
> +     default).  */
> +  for (int do_indirect = 0; do_indirect < 2;  ++do_indirect)
> +    {
> +      printf ("info: test iteration with do_indirect == %d\n", do_indirect);
> +      pthread_t thr1;
> +      if (do_indirect)
> +        thr1 = xpthread_create (&attr_perthreadfs,
> +                                thread_perthreadfs_indirect, NULL);
> +      else
> +        thr1 = xpthread_create (&attr_perthreadfs, thread_perthreadfs, NULL);
> +      pthread_t thr2 = xpthread_create (NULL, thread_sharedfs, NULL);
> +      /* Both threads wait on the barrier before exiting, so they are
> +         running at his point, and the call to perthread_flag is
> +         safe.  */
> +      TEST_VERIFY (perthread_flag (thr1));
> +      TEST_VERIFY (!perthread_flag (thr2));
> +
> +      /* Wait for thread_perthreadfs to update current directory and
> +         umask.  */
> +      xpthread_barrier_wait (&barrier);
> +      /* File attributes read thread_sharedfs here.  */
> +      xpthread_barrier_wait (&barrier);
> +
> +      check_attributes ("main thread", original_umask, original_cwd);
> +
> +      xpthread_barrier_wait (&barrier);
> +      /* File attributes changed thread_sharedfs here.  */
> +      xpthread_barrier_wait (&barrier);
> +      /* File attributes read in thread_perthreadfs here.  */
> +      xpthread_barrier_wait (&barrier);
> +
> +      check_attributes ("main thread", new_umask_2, new_cwd_2);
> +
> +      xpthread_barrier_wait (&barrier);
> +
> +      xpthread_join (thr2);
> +      xpthread_join (thr1);
> +
> +      xchdir (original_cwd);
> +      umask (original_umask);
> +    }
> +
> +  xpthread_attr_destroy (&attr_perthreadfs);
> +  xpthread_barrier_destroy (&barrier);
> +
> +  free (new_cwd_2);
> +  free (new_cwd_1);
> +  free (original_cwd);
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/sysdeps/nptl/internaltypes.h b/sysdeps/nptl/internaltypes.h
> index 9169453cc9..f291421dc2 100644
> --- a/sysdeps/nptl/internaltypes.h
> +++ b/sysdeps/nptl/internaltypes.h
> @@ -51,6 +51,18 @@ struct pthread_attr
>  #define ATTR_FLAG_SCHED_SET		0x0020
>  #define ATTR_FLAG_POLICY_SET		0x0040
>  #define ATTR_FLAG_DO_RSEQ		0x0080
> +#define ATTR_FLAG_PERTHREADFS		0x0100
> +
> +/* These flags are not copied from the thread attribute at
> +   pthread_create time.  */
> +#define ATTR_FLAGS_IGNORED_ATTR \
> +  (ATTR_FLAG_SCHED_SET | ATTR_FLAG_POLICY_SET)
> +
> +/* These flags are inherited from the current thread during
> +   pthread_create even if they are not specified in the thread
> +   attribute.  */
> +#define ATTR_FLAGS_INHERITED \
> +  ATTR_FLAG_PERTHREADFS
>  
>  /* Used to allocate a pthread_attr_t object which is also accessed
>     internally.  */
> diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
> index 92957a620d..d2280ddc73 100644
> --- a/sysdeps/nptl/pthread.h
> +++ b/sysdeps/nptl/pthread.h
> @@ -149,7 +149,16 @@ enum
>  #define PTHREAD_PROCESS_SHARED  PTHREAD_PROCESS_SHARED
>  };
>  
> -
> +#ifdef __USE_GNU
> +/* Thread-private or process-global flag.  */
> +enum
> +{
> + PTHREAD_PER_PROCESS_NP,
> +# define PTHREAD_PER_PROCESS_NP PTHREAD_PER_PROCESS_NP
> + PTHREAD_PER_THREAD_NP
> +# define PTHREAD_PER_THREAD_NP PTHREAD_PER_THREAD_NP
> +};
> +#endif /* __USE_GNU */
>  
>  /* Conditional variable handling.  */
>  #define PTHREAD_COND_INITIALIZER { { {0}, {0}, {0, 0}, 0, 0, {0, 0}, 0, 0 } }
> @@ -403,6 +412,21 @@ extern int pthread_attr_getaffinity_np (const pthread_attr_t *__attr,
>  					cpu_set_t *__cpuset)
>       __THROW __nonnull ((1, 3));
>  
> +
> +/* Control the flag in ATTR whether the thread has its own current
> +   directory, file system root, and umask attribute.  SCOPE must be
> +   PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP.  By default, new
> +   threads share these attributes with their creating thread
> +   (PTHREAD_PER_PROCESS_NP).  */
> +int pthread_attr_setperthreadfs_np (pthread_attr_t *__attr, int __scope)
> +  __THROW __nonnull ((1));
> +
> +/* Get the per-thread/per-process scope of file system attributes from
> +   *ATTR and store it in *SCOPE.  */
> +int pthread_attr_getperthreadfs_np (const pthread_attr_t *__restrict __attr,
> +				    int *__restrict __scope)
> +  __THROW __nonnull ((1, 2));
> +
>  /* Get the default attributes used by pthread_create in this process.  */
>  extern int pthread_getattr_default_np (pthread_attr_t *__attr)
>       __THROW __nonnull ((1));
> diff --git a/sysdeps/unix/sysv/linux/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> index 3156688add..abc893d3c2 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
> @@ -2774,4 +2774,6 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> index 8af5b0b581..08ac8d8e1b 100644
> --- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
> @@ -3121,6 +3121,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/arc/libc.abilist b/sysdeps/unix/sysv/linux/arc/libc.abilist
> index 35fcef2cc4..69f616cead 100644
> --- a/sysdeps/unix/sysv/linux/arc/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arc/libc.abilist
> @@ -2535,4 +2535,6 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/arm/be/libc.abilist b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> index a6c6b951bf..9d1678320e 100644
> --- a/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/be/libc.abilist
> @@ -2827,6 +2827,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/arm/le/libc.abilist b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> index e76015fe66..4f3b5affe9 100644
> --- a/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/arm/le/libc.abilist
> @@ -2824,6 +2824,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
> index 1fb7cdcad5..4775926d0d 100644
> --- a/sysdeps/unix/sysv/linux/csky/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
> @@ -2811,4 +2811,6 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> index 0710ccecf9..d3b8ac7de6 100644
> --- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
> @@ -2848,6 +2848,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
> index 3afe3a88eb..7bf6d848df 100644
> --- a/sysdeps/unix/sysv/linux/i386/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
> @@ -3031,6 +3031,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> index c2b3a66d3a..4438857731 100644
> --- a/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/loongarch/lp64/libc.abilist
> @@ -2295,4 +2295,6 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> index d6855131e8..1ec5185e2a 100644
> --- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
> @@ -2807,6 +2807,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> index 4e3fe9c42f..d091f52f10 100644
> --- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
> @@ -2974,6 +2974,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> index 29f0c5f954..eda99f79cc 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/be/libc.abilist
> @@ -2860,4 +2860,6 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> index 2ef62838f7..28d85c9a69 100644
> --- a/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/microblaze/le/libc.abilist
> @@ -2857,4 +2857,6 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> index 031e8961ac..52c206e514 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
> @@ -2937,6 +2937,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> index 8dc99d81b4..fa6b7532bd 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
> @@ -2935,6 +2935,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> index 054c5b6391..c2a0b18359 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
> @@ -2943,6 +2943,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> index 13f0148bc0..8c0e99fb18 100644
> --- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
> @@ -2845,6 +2845,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/or1k/libc.abilist b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> index e7ffe07dd8..1158bb10d6 100644
> --- a/sysdeps/unix/sysv/linux/or1k/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/or1k/libc.abilist
> @@ -2285,4 +2285,6 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> index dea4b20f05..bf9faed11f 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
> @@ -3164,6 +3164,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> index b45e127463..7dbe21ba65 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
> @@ -3209,6 +3209,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> index 942cf6a027..8e8a179363 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
> @@ -2918,6 +2918,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> index 65d78e5076..04fa4568bb 100644
> --- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
> @@ -2994,4 +2994,6 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> index dcab30d72e..78d4f1f22f 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv32/libc.abilist
> @@ -2538,4 +2538,6 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> index 796ef35e26..ae0f2ccac9 100644
> --- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
> @@ -2738,4 +2738,6 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> index 9bd9f5eb78..7b7c81a68b 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
> @@ -3162,6 +3162,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> index 8f2350ee0b..7c81be27f4 100644
> --- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
> @@ -2955,6 +2955,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/sh/be/libc.abilist b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> index 7aa98c5aed..f04f22b538 100644
> --- a/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/be/libc.abilist
> @@ -2854,6 +2854,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/sh/le/libc.abilist b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> index 6bd4f8f63a..ec831f0ad5 100644
> --- a/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sh/le/libc.abilist
> @@ -2851,6 +2851,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> index b52cab2a35..4f40e294fe 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
> @@ -3185,6 +3185,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> index ff99cd4f21..da128a940a 100644
> --- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
> @@ -2821,6 +2821,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> index 306cd627fd..3f32a83378 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
> @@ -2770,6 +2770,8 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F
>  GLIBC_2.5 __readlinkat_chk F
>  GLIBC_2.5 inet6_opt_append F
> diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> index 8b9c448742..8105eaadba 100644
> --- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> +++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
> @@ -2789,4 +2789,6 @@ GLIBC_2.43 memalignment F
>  GLIBC_2.43 memset_explicit F
>  GLIBC_2.43 mseal F
>  GLIBC_2.43 openat2 F
> +GLIBC_2.43 pthread_attr_getperthreadfs_np F
> +GLIBC_2.43 pthread_attr_setperthreadfs_np F
>  GLIBC_2.43 umaxabs F



More information about the Libc-alpha mailing list