This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] Linux: Implement per-thread file system attributes
- From: Florian Weimer <fweimer at redhat dot com>
- To: Carlos O'Donell <carlos at redhat dot com>
- Cc: libc-alpha at sourceware dot org
- Date: Mon, 01 Jul 2019 18:32:34 +0200
- Subject: Re: [PATCH] Linux: Implement per-thread file system attributes
- References: <87d0jpfius.fsf@oldenburg2.str.redhat.com> <8ad787b8-994e-65e9-4f18-1e0d29605de3@redhat.com> <87v9wpn4ft.fsf@oldenburg2.str.redhat.com> <e80c823e-beb5-3694-44ba-cc92c066c8fe@redhat.com> <87d0ixmyyv.fsf@oldenburg2.str.redhat.com> <1b1730f1-8d90-a0c2-734f-d2f964774cab@redhat.com> <878stlmudy.fsf@oldenburg2.str.redhat.com> <2c86ff9c-6733-6aaf-e0e0-c4eb026d6eb7@redhat.com> <87a7e1ldpq.fsf@oldenburg2.str.redhat.com> <390c0cfc-af36-a9f0-ad55-f3c4693093cf@redhat.com> <87pnmxjwci.fsf@oldenburg2.str.redhat.com> <7cf9d676-394e-0bc6-78cb-0479e61ff56d@redhat.com>
* Carlos O'Donell:
> On 6/28/19 4:20 PM, Florian Weimer wrote:
>> * Carlos O'Donell:
>>
>>> On 6/28/19 3:19 PM, Florian Weimer wrote:
>>>> * Carlos O'Donell:
>>>>
>>>>> On 6/28/19 2:34 PM, Florian Weimer wrote:
>>>>>> * Carlos O'Donell:
>>>>>>
>>>>>>>> if (flag != PTHREAD_PER_THREAD_NP)
>>>>>>>> TEST_COMPARE (flag, PTHREAD_PER_PROCESS_NP);
>>>>>>>
>>>>>>> I don't follow why you can't call this unconditionally?
>>>>>>
>>>>>> This asserts that the flag has one of two values, PTHREAD_PER_THREAD_NP
>>>>>> or PTHREAD_PER_PROCESS_NP.
>>>>>
>>>>> I still don't follow.
>>>>>
>>>>> Why can't we just use:
>>>>>
>>>>> TEST_COMPARE (flag, PTHREAD_PER_PROCESS_NP);
>>>>>
>>>>> We only expect flag to be PTHREAD_PER_PROCESS_NP.
>>>>
>>>> No, the flag can be both, and the returned boolean changes as the
>>>> result.
>>>
>>> Ah! OK, I missed that bit of logic in the test.
>>
>> Good. I consider this patch finished, then. (I fixed a typo in the
>> manual locally.)
>>
>
> OK for master.
>
> Reviewed-by: Carlos O'Donell <carlos@redhat.com>
I adjusted the pthread_attr_getperthreadfs_np comment, and fixed a race
condition in the test.
Thanks,
Florian
Linux: Implement per-thread file system attributes
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.
2019-06-28 Florian Weimer <fweimer@redhat.com>
Linux: Implement per-thread file system attributes.
* manual/threads.texi (Enabling Per-Thread Properties): New
section.
(Non-POSIX Extensions): Reference it.
* nptl/Makefile (routines): Add pthread_attr_setperthreadfs_np,
pthread_attr_getperthreadfs_np.
(tests): Add tst-pthread-perthreadfs,
tst-pthread-perthreadfs-chroot.
* nptl/Versions (GLIBC_2.30): Export
pthread_attr_setperthreadfs_np, pthread_attr_getperthreadfs_np.
* nptl/pthread_attr_setperthreadfs_np.c: New file
* nptl/pthread_attr_getperthreadfs_np.c: Likewise.
* nptl/pthread_create.c (__pthread_create_2_1): Use
ATTR_FLAGS_IGNORED_ATTR and ATTR_FLAGS_INHERITED to compute the
flags for the new thread.
* nptl/tst-pthread-perthreadfs.c: Likewise.
* nptl/tst-pthread-perthreadfs-chroot.c: Likewise.
* sysdeps/nptl/internaltypes.h (ATTR_FLAG_PERTHREADFS)
(ATTR_FLAGS_IGNORED_ATTR, ATTR_FLAGS_INHERITED): Define.
* sysdeps/unix/sysv/linux/createthread.c (create_thread): Use it.
* sysdeps/nptl/pthread.h
(PTHREAD_PER_PROCESS_NP, PTHREAD_PER_THREAD_NP): Define.
(pthread_attr_setperthreadfs_np, pthread_attr_getperthreadfs_np):
Declare.
* sysdeps/unix/sysv/linux/hppa/pthread.h
(PTHREAD_PER_PROCESS_NP, PTHREAD_PER_THREAD_NP): Define.
(pthread_attr_setperthreadfs_np, pthread_attr_getperthreadfs_np):
Declare.
* support/Makefile (libsupport-routines): Add xchdir, xfchdir.
* support/xunistd.h (xchdir, xfchdir): Declare.
* support/xchdir.c: New file.
* support/xfchdir.c: Likewise.
* sysdeps/unix/sysv/linux/aarch64/libc.abilist (GLIBC_2.30): Add
pthread_attr_setperthreadfs_np, pthread_attr_getperthreadfs_np.
* sysdeps/unix/sysv/linux/alpha/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/arm/libc.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/csky/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/hppa/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/i386/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/ia64/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/microblaze/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/nios2/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
(GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/sh/libc.abilist (GLIBC_2.30): Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist (GLIBC_2.30):
Likewise.
* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist (GLIBC_2.30):
Likewise.
diff --git a/NEWS b/NEWS
index 6c7de105ac..e63b69b930 100644
--- a/NEWS
+++ b/NEWS
@@ -40,6 +40,11 @@ Major new features:
FUNCTION-NAME, version SYMBOL-VERSION not defined in file DSO-NAME with
link time reference, is gone.
+* 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:
* The copy_file_range function fails with ENOSYS if the kernel does not
diff --git a/manual/threads.texi b/manual/threads.texi
index 87fda7d8e7..827ecb0929 100644
--- a/manual/threads.texi
+++ b/manual/threads.texi
@@ -625,6 +625,7 @@ the standard.
@menu
* Default Thread Attributes:: Setting default attributes for
threads in a process.
+* Enabling Per-Thread Properties:: Additional per-thread properties.
@end menu
@node Default Thread Attributes
@@ -669,6 +670,100 @@ The system does not have sufficient memory.
@end table
@end deftypefun
+@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
+
@c FIXME these are undocumented:
@c pthread_atfork
@c pthread_attr_destroy
diff --git a/nptl/Makefile b/nptl/Makefile
index de312b3477..1374838339 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -30,7 +30,8 @@ extra-libs-others := $(extra-libs)
routines = alloca_cutoff forward libc-lowlevellock libc-cancellation \
libc-cleanup libc_pthread_init libc_multiple_threads \
register-atfork pthread_atfork pthread_self thrd_current \
- thrd_equal thrd_sleep thrd_yield
+ thrd_equal thrd_sleep thrd_yield \
+ pthread_attr_setperthreadfs_np pthread_attr_getperthreadfs_np
shared-only-routines = forward
static-only-routines = pthread_atfork
@@ -321,7 +322,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \
tst-rwlock-pwn \
tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall \
- tst-unwind-thread
+ tst-unwind-thread \
+ tst-pthread-perthreadfs tst-pthread-perthreadfs-chroot
tests-internal := tst-rwlock19 tst-rwlock20 \
tst-sem11 tst-sem12 tst-sem13 \
diff --git a/nptl/Versions b/nptl/Versions
index e7f691da7a..817fec04f3 100644
--- a/nptl/Versions
+++ b/nptl/Versions
@@ -32,6 +32,10 @@ libc {
GLIBC_2.28 {
thrd_current; thrd_equal; thrd_sleep; thrd_yield;
}
+ GLIBC_2.30 {
+ pthread_attr_setperthreadfs_np;
+ pthread_attr_getperthreadfs_np;
+ }
GLIBC_PRIVATE {
__libc_alloca_cutoff;
# Internal libc interface to libpthread
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) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <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) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <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 18b7bbe765..0002fa7299 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -693,8 +693,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));
/* Initialize the field for the ID of the thread which is waiting
for us. This is a self-reference in case the thread is created
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) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+/* This 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) 2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <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/support/Makefile b/support/Makefile
index 56c1ed43bb..774b0a692a 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -80,6 +80,7 @@ libsupport-routines = \
xasprintf \
xbind \
xcalloc \
+ xchdir \
xchroot \
xclock_gettime \
xclose \
@@ -88,6 +89,7 @@ libsupport-routines = \
xdlfcn \
xdlmopen \
xdup2 \
+ xfchdir \
xfclose \
xfopen \
xfork \
diff --git a/support/xchdir.c b/support/xchdir.c
new file mode 100644
index 0000000000..a2f728f5df
--- /dev/null
+++ b/support/xchdir.c
@@ -0,0 +1,28 @@
+/* chdir with error checking.
+ Copyright (C) 2017-2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <sys/stat.h>
+
+void
+xchdir (const char *path)
+{
+ if (chdir (path) != 0)
+ FAIL_EXIT1 ("chdir (\"%s\"): %m", path);
+}
diff --git a/support/xfchdir.c b/support/xfchdir.c
new file mode 100644
index 0000000000..76c5f655bb
--- /dev/null
+++ b/support/xfchdir.c
@@ -0,0 +1,28 @@
+/* fchdir with error checking.
+ Copyright (C) 2017-2019 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <sys/stat.h>
+
+void
+xfchdir (int fd)
+{
+ if (fchdir (fd) != 0)
+ FAIL_EXIT1 ("fchdir (%d): %m", fd);
+}
diff --git a/support/xunistd.h b/support/xunistd.h
index 338eb86a1b..b470d99be1 100644
--- a/support/xunistd.h
+++ b/support/xunistd.h
@@ -38,6 +38,8 @@ int xopen (const char *path, int flags, mode_t);
void xstat (const char *path, struct stat64 *);
void xfstat (int fd, struct stat64 *);
void xmkdir (const char *path, mode_t);
+void xchdir (const char *path);
+void xfchdir (int);
void xchroot (const char *path);
void xunlink (const char *path);
long xsysconf (int name);
diff --git a/sysdeps/nptl/internaltypes.h b/sysdeps/nptl/internaltypes.h
index 53d037e0f1..5ad56908b5 100644
--- a/sysdeps/nptl/internaltypes.h
+++ b/sysdeps/nptl/internaltypes.h
@@ -48,6 +48,18 @@ struct pthread_attr
#define ATTR_FLAG_OLDATTR 0x0010
#define ATTR_FLAG_SCHED_SET 0x0020
#define ATTR_FLAG_POLICY_SET 0x0040
+#define ATTR_FLAG_PERTHREADFS 0x0080
+
+/* 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
/* Mutex attribute data structure. */
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index 704a3c48d6..4b6a90f131 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -181,7 +181,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} } }
@@ -406,6 +415,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 a4c31932cb..2635e16f5e 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2143,5 +2143,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index fe85a35620..12227b9800 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2218,6 +2218,8 @@ GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index bc3df8dcea..6d09148e1d 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -128,6 +128,8 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 _Exit F
diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c
index 579bd94743..177e14e9ae 100644
--- a/sysdeps/unix/sysv/linux/createthread.c
+++ b/sysdeps/unix/sysv/linux/createthread.c
@@ -66,7 +66,9 @@ 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
@@ -90,11 +92,13 @@ 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);
diff --git a/sysdeps/unix/sysv/linux/csky/libc.abilist b/sysdeps/unix/sysv/linux/csky/libc.abilist
index 9b3cee65bb..5ee091972b 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2087,5 +2087,7 @@ GLIBC_2.29 xprt_register F
GLIBC_2.29 xprt_unregister F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 75edece94a..844eaf539b 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2039,6 +2039,8 @@ GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/hppa/pthread.h b/sysdeps/unix/sysv/linux/hppa/pthread.h
index 45e706c037..43ffca5551 100644
--- a/sysdeps/unix/sysv/linux/hppa/pthread.h
+++ b/sysdeps/unix/sysv/linux/hppa/pthread.h
@@ -158,6 +158,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} } }
@@ -382,6 +392,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/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index edeaf8e722..efd8cb1685 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2205,6 +2205,8 @@ GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index b5d460eeb2..7f34f4d1e6 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2071,6 +2071,8 @@ GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 05633b3cb8..34d5f6c91a 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -129,6 +129,8 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 _Exit F
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 47eb7b4608..71882c6e23 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2148,6 +2148,8 @@ GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index f7ced487f7..4f605fa67a 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2135,5 +2135,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index e49dc4272e..62790b0a64 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2122,6 +2122,8 @@ GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index daa3b60c5b..eb2ae61601 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2120,6 +2120,8 @@ GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 457ce0b6f2..9cf1462270 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2128,6 +2128,8 @@ GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index 63d5c03bfb..d116e7180e 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2122,6 +2122,8 @@ GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 7fec0c9670..0e8d5bfcc7 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2176,5 +2176,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index 9200a54309..16e66c2fa4 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2178,6 +2178,8 @@ GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index ef7779905f..fff0295a63 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2211,6 +2211,8 @@ GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index 2860df8ebc..808f021335 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2041,6 +2041,8 @@ GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 2229a1dcc0..a894bc49be 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2245,5 +2245,7 @@ GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index 31010e6cf7..e220b0fd0c 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2105,5 +2105,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 576295deff..1567d2ff1d 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2173,6 +2173,8 @@ GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index abf0473683..f9d88d588e 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2077,6 +2077,8 @@ GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index 41977f6e9c..affd74df4c 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -2043,6 +2043,8 @@ GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 3d2f00ca52..c12cc83bb2 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2167,6 +2167,8 @@ GLIBC_2.30 __nldbl_warn F
GLIBC_2.30 __nldbl_warnx F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 _IO_fprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 2f20643e8e..37c9dff44c 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2094,6 +2094,8 @@ GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 59f85d9373..71b7cc4ff9 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2052,6 +2052,8 @@ GLIBC_2.3.4 xdr_quad_t F
GLIBC_2.3.4 xdr_u_quad_t F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F
GLIBC_2.4 __confstr_chk F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 67a4e238d6..573fc2e01c 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2151,5 +2151,7 @@ GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
GLIBC_2.30 getdents64 F
GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
GLIBC_2.30 tgkill F
GLIBC_2.30 twalk_r F