public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] Linux: Implement per-thread file system attributes
@ 2018-11-30 12:03 Florian Weimer
  2018-12-05 13:21 ` Florian Weimer
  2018-12-13  9:18 ` Florian Weimer
  0 siblings, 2 replies; 24+ messages in thread
From: Florian Weimer @ 2018-11-30 12:03 UTC (permalink / raw)
  To: libc-alpha

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.

2018-11-30  Florian Weimer  <fweimer@redhat.com>

	Linux: Implement per-thread file system attributes.
	* 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.29): 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/tst-pthread-perthreadfs.c: Likewise.
	* nptl/tst-pthread-perthreadfs-chroot.c: Likewise.
	* sysdeps/nptl/internaltypes.h (ATTR_FLAG_PERTHREADFS): Define.
	* sysdeps/unix/sysv/linux/createthread.c (create_thread): Use it.
	* sysdeps/nptl/pthread.h (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.29): Add
	pthread_attr_setperthreadfs_np, pthread_attr_getperthreadfs_np.
	* sysdeps/unix/sysv/linux/alpha/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/arm/libc.abilist (GLIBC_2.29): Likewise.
	* sysdeps/unix/sysv/linux/hppa/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/i386/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/ia64/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
	(GLIBC_2.29): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
	(GLIBC_2.29): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
	(GLIBC_2.29): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
	(GLIBC_2.29): Likewise.
	* sysdeps/unix/sysv/linux/nios2/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
	(GLIBC_2.29): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
	(GLIBC_2.29): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
	(GLIBC_2.29): Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
	(GLIBC_2.29): Likewise.
	* sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/sh/libc.abilist (GLIBC_2.29): Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libc.abilist (GLIBC_2.29):
	Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist (GLIBC_2.29):
	Likewise.

diff --git a/NEWS b/NEWS
index 1098be1afb..6acd6e1921 100644
--- a/NEWS
+++ b/NEWS
@@ -35,6 +35,11 @@ Major new features:
   different directory.  This is a GNU extension and similar to the
   Solaris function of the same name.
 
+* 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 glibc.tune tunable namespace has been renamed to glibc.cpu and the
diff --git a/nptl/Makefile b/nptl/Makefile
index 982e43adfa..02346b2f92 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
 
@@ -318,7 +319,8 @@ tests = tst-attr1 tst-attr2 tst-attr3 tst-default-attr \
 	tst-minstack-throw \
 	tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \
 	tst-cnd-timedwait tst-thrd-detach tst-mtx-basic tst-thrd-sleep \
-	tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock
+	tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \
+	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..ba71f85411 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.29 {
+    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..f285fe8516
--- /dev/null
+++ b/nptl/pthread_attr_getperthreadfs_np.c
@@ -0,0 +1,27 @@
+/* Read the private file system flag in thread attributes.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <pthread.h>
+#include <internaltypes.h>
+
+int
+pthread_attr_getperthreadfs_np (const pthread_attr_t *attr)
+{
+  struct pthread_attr *iattr = (struct pthread_attr *) attr;
+  return (iattr->flags & ATTR_FLAG_PERTHREADFS) != 0;
+}
diff --git a/nptl/pthread_attr_setperthreadfs_np.c b/nptl/pthread_attr_setperthreadfs_np.c
new file mode 100644
index 0000000000..6ce982a8bb
--- /dev/null
+++ b/nptl/pthread_attr_setperthreadfs_np.c
@@ -0,0 +1,30 @@
+/* Change the private file system flag in thread attributes.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <pthread.h>
+#include <internaltypes.h>
+
+void
+pthread_attr_setperthreadfs_np (pthread_attr_t *attr, int enabled)
+{
+  struct pthread_attr *iattr = (struct pthread_attr *) attr;
+  if (enabled)
+    iattr->flags |= ATTR_FLAG_PERTHREADFS;
+  else
+    iattr->flags &= ~ATTR_FLAG_PERTHREADFS;
+}
diff --git a/nptl/tst-pthread-perthreadfs-chroot.c b/nptl/tst-pthread-perthreadfs-chroot.c
new file mode 100644
index 0000000000..77494c2bcc
--- /dev/null
+++ b/nptl/tst-pthread-perthreadfs-chroot.c
@@ -0,0 +1,256 @@
+/* Test per-thread file system attributes, chroot version.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#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_getperthreadfs_np (&attr_perthreadfs), 0);
+  pthread_attr_setperthreadfs_np (&attr_perthreadfs, true);
+  TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs), 1);
+  /* The flag is normalized to 1.  */
+  pthread_attr_setperthreadfs_np (&attr_perthreadfs, 2);
+  TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs), 1);
+
+  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..d11dc63a1f
--- /dev/null
+++ b/nptl/tst-pthread-perthreadfs.c
@@ -0,0 +1,243 @@
+/* Test per-thread file system attributes.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#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;
+
+/* 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");
+  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;
+}
+
+/* Thread function launched with shared file system attributes.  */
+static void *
+thread_sharedfs (void *closure)
+{
+  /* 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;
+
+  xpthread_barrier_init (&barrier, NULL, 3);
+  xpthread_attr_init (&attr_perthreadfs);
+  TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs), 0);
+  pthread_attr_setperthreadfs_np (&attr_perthreadfs, true);
+  TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs), 1);
+  /* The flag is normalized to 1.  */
+  pthread_attr_setperthreadfs_np (&attr_perthreadfs, 2);
+  TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs), 1);
+
+  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 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);
+
+  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 a2536980d1..dd75df5cb8 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -75,12 +75,14 @@ libsupport-routines = \
   xasprintf \
   xbind \
   xcalloc \
+  xchdir \
   xchroot \
   xclose \
   xconnect \
   xcopy_file_range \
   xdlfcn \
   xdup2 \
+  xfchdir \
   xfclose \
   xfopen \
   xfork \
diff --git a/support/xchdir.c b/support/xchdir.c
new file mode 100644
index 0000000000..5f9f001ce0
--- /dev/null
+++ b/support/xchdir.c
@@ -0,0 +1,28 @@
+/* chdir with error checking.
+   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#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..75fadeb865
--- /dev/null
+++ b/support/xfchdir.c
@@ -0,0 +1,28 @@
+/* fchdir with error checking.
+   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#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 f99f362cb4..13dfa2c0e5 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 b78ad99a88..30396cc448 100644
--- a/sysdeps/nptl/internaltypes.h
+++ b/sysdeps/nptl/internaltypes.h
@@ -48,6 +48,7 @@ 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
 
 
 /* Mutex attribute data structure.  */
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index df049abf74..8efcff278e 100644
--- a/sysdeps/nptl/pthread.h
+++ b/sysdeps/nptl/pthread.h
@@ -406,6 +406,18 @@ 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.  By default, new
+   threads share these attributes with their creating thread.  */
+void pthread_attr_setperthreadfs_np (pthread_attr_t *__attr, int __enabled)
+  __THROW __nonnull ((1));
+
+/* Return 1 if ATTR enables private file system attributes, or 0 if
+   not.  See pthread_attr_setperthreadfs_np.  */
+int pthread_attr_getperthreadfs_np (const pthread_attr_t *__attr)
+  __THROW __nonnull ((1));
+
 /* 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 e66c741d04..59e897b59e 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2139,3 +2139,5 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 8df162fe99..4ea64a9af9 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2034,6 +2034,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index 43c804f9dc..1074323ac7 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -124,6 +124,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c
index 5879e51bd2..8de97746dc 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 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/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 88b01c2e75..3a2c85a8d8 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1881,6 +1881,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index 6d02f31612..9896c9d9f4 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2046,6 +2046,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 4249712611..febdc06b39 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1915,6 +1915,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index d47b808862..61e077b7fd 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -125,6 +125,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index d5e38308be..807382fa46 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1990,6 +1990,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 8596b84399..313ec63271 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2131,3 +2131,5 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 88e0f896d5..d277f4210e 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1968,6 +1968,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
index aff7462c34..4237bad588 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1966,6 +1966,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
index 71d82444aa..0c200c15f2 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1974,6 +1974,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
index de6c53d293..aceab1b162 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1969,6 +1969,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index e724bab9fb..e402a05d86 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2172,3 +2172,5 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index e9ecbccb71..976fa6c45a 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1994,6 +1994,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index da83ea6028..0837cb981e 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1998,6 +1998,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
index 4535b40d15..0f696145a5 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2229,3 +2229,5 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index 65725de4f0..b9a2327410 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -124,6 +124,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 _Exit F
 GLIBC_2.3 _IO_2_1_stderr_ D 0xe0
 GLIBC_2.3 _IO_2_1_stdin_ D 0xe0
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index bbb3c4a8e7..56bbeb0572 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2101,3 +2101,5 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index e85ac2a178..f7a7cc3b7a 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2003,6 +2003,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index d56931022c..5f2bf4126f 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1909,6 +1909,8 @@ GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 __fentry__ F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index ff939a15c4..46d4254812 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1885,6 +1885,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index 64fa9e10a5..be8189851c 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1997,6 +1997,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index db909d1506..d29252f5b8 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1938,6 +1938,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index 3b175f104b..a4088c691c 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1896,6 +1896,8 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F
 GLIBC_2.3 __ctype_b_loc F
 GLIBC_2.3 __ctype_tolower_loc F
 GLIBC_2.3 __ctype_toupper_loc F
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
index 1b57710477..e11f54da10 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2147,3 +2147,5 @@ GLIBC_2.28 thrd_equal F
 GLIBC_2.28 thrd_sleep F
 GLIBC_2.28 thrd_yield F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
+GLIBC_2.29 pthread_attr_getperthreadfs_np F
+GLIBC_2.29 pthread_attr_setperthreadfs_np F

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2018-11-30 12:03 [PATCH] Linux: Implement per-thread file system attributes Florian Weimer
@ 2018-12-05 13:21 ` Florian Weimer
  2018-12-13  9:18 ` Florian Weimer
  1 sibling, 0 replies; 24+ messages in thread
From: Florian Weimer @ 2018-12-05 13:21 UTC (permalink / raw)
  To: libc-alpha

* Florian Weimer:

> 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.

Any comments?  Do we want something like this at all?

Thanks,
Florian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2018-11-30 12:03 [PATCH] Linux: Implement per-thread file system attributes Florian Weimer
  2018-12-05 13:21 ` Florian Weimer
@ 2018-12-13  9:18 ` Florian Weimer
  2019-02-08 12:31   ` Florian Weimer
  1 sibling, 1 reply; 24+ messages in thread
From: Florian Weimer @ 2018-12-13  9:18 UTC (permalink / raw)
  To: libc-alpha; +Cc: Jeremy Allison

* Florian Weimer:

> 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.
>
> 2018-11-30  Florian Weimer  <fweimer@redhat.com>
>
> 	Linux: Implement per-thread file system attributes.

Original patch:

  <https://sourceware.org/ml/libc-alpha/2018-11/msg00866.html>

It turns out that Samba uses something quite similar today: They call
unshare (CLONE_FS) from certain threads to obtain private file system
attributes.  So there is some demand for this functionality.

The main question is whether the interfaces should stick literally to
other POSIX attribute functions and use this instead:

int pthread_attr_setperthreadfs_np (pthread_attr_t *__attr, int __enabled)
  __THROW __nonnull ((1));
int pthread_attr_getperthreadfs_np (const pthread_attr_t *, int *__enabled)
  __THROW __nonnull ((1, 2));

The patch currently has:

void pthread_attr_setperthreadfs_np (pthread_attr_t *__attr, int __enabled)
  __THROW __nonnull ((1));
int pthread_attr_getperthreadfs_np (const pthread_attr_t *__attr)
  __THROW __nonnull ((1));

I have no strong opinion on this matter.

(I will write documentation once the API is approved for inclusion.)

Thanks,
Florian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2018-12-13  9:18 ` Florian Weimer
@ 2019-02-08 12:31   ` Florian Weimer
  0 siblings, 0 replies; 24+ messages in thread
From: Florian Weimer @ 2019-02-08 12:31 UTC (permalink / raw)
  To: libc-alpha; +Cc: Jeremy Allison

* Florian Weimer:

> * Florian Weimer:
>
>> 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.
>>
>> 2018-11-30  Florian Weimer  <fweimer@redhat.com>
>>
>> 	Linux: Implement per-thread file system attributes.
>
> Original patch:
>
>   <https://sourceware.org/ml/libc-alpha/2018-11/msg00866.html>
>
> It turns out that Samba uses something quite similar today: They call
> unshare (CLONE_FS) from certain threads to obtain private file system
> attributes.  So there is some demand for this functionality.
>
> The main question is whether the interfaces should stick literally to
> other POSIX attribute functions and use this instead:
>
> int pthread_attr_setperthreadfs_np (pthread_attr_t *__attr, int __enabled)
>   __THROW __nonnull ((1));
> int pthread_attr_getperthreadfs_np (const pthread_attr_t *, int *__enabled)
>   __THROW __nonnull ((1, 2));
>
> The patch currently has:
>
> void pthread_attr_setperthreadfs_np (pthread_attr_t *__attr, int __enabled)
>   __THROW __nonnull ((1));
> int pthread_attr_getperthreadfs_np (const pthread_attr_t *__attr)
>   __THROW __nonnull ((1));
>
> I have no strong opinion on this matter.
>
> (I will write documentation once the API is approved for inclusion.)

Ping?

If someone could do a conceptual review of the original patch, I can
rebase it to current master for an actual review.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-06-30  5:04                     ` Carlos O'Donell
@ 2019-07-01 16:32                       ` Florian Weimer
  0 siblings, 0 replies; 24+ messages in thread
From: Florian Weimer @ 2019-07-01 16:32 UTC (permalink / raw)
  To: Carlos O'Donell; +Cc: libc-alpha

* 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

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-06-28 20:20                   ` Florian Weimer
@ 2019-06-30  5:04                     ` Carlos O'Donell
  2019-07-01 16:32                       ` Florian Weimer
  0 siblings, 1 reply; 24+ messages in thread
From: Carlos O'Donell @ 2019-06-30  5:04 UTC (permalink / raw)
  To: Florian Weimer; +Cc: libc-alpha

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 rebased the perthreadids patch:
> 
>   <https://sourceware.org/ml/libc-alpha/2019-06/msg00937.html>

Reviewed.

> 
> And also wrote a new combined test:
> 
>   <https://sourceware.org/ml/libc-alpha/2019-06/msg00946.html>

Reviewed.

> 
> Thanks,
> Florian
> 


-- 
Cheers,
Carlos.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-06-28 19:59                 ` Carlos O'Donell
@ 2019-06-28 20:20                   ` Florian Weimer
  2019-06-30  5:04                     ` Carlos O'Donell
  0 siblings, 1 reply; 24+ messages in thread
From: Florian Weimer @ 2019-06-28 20:20 UTC (permalink / raw)
  To: Carlos O'Donell; +Cc: libc-alpha

* 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.)

I rebased the perthreadids patch:

  <https://sourceware.org/ml/libc-alpha/2019-06/msg00937.html>

And also wrote a new combined test:

  <https://sourceware.org/ml/libc-alpha/2019-06/msg00946.html>

Thanks,
Florian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-06-28 19:19               ` Florian Weimer
@ 2019-06-28 19:59                 ` Carlos O'Donell
  2019-06-28 20:20                   ` Florian Weimer
  0 siblings, 1 reply; 24+ messages in thread
From: Carlos O'Donell @ 2019-06-28 19:59 UTC (permalink / raw)
  To: Florian Weimer; +Cc: libc-alpha

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.

-- 
Cheers,
Carlos.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-06-28 19:15             ` Carlos O'Donell
@ 2019-06-28 19:19               ` Florian Weimer
  2019-06-28 19:59                 ` Carlos O'Donell
  0 siblings, 1 reply; 24+ messages in thread
From: Florian Weimer @ 2019-06-28 19:19 UTC (permalink / raw)
  To: Carlos O'Donell; +Cc: libc-alpha

* 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.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-06-28 18:34           ` Florian Weimer
@ 2019-06-28 19:15             ` Carlos O'Donell
  2019-06-28 19:19               ` Florian Weimer
  0 siblings, 1 reply; 24+ messages in thread
From: Carlos O'Donell @ 2019-06-28 19:15 UTC (permalink / raw)
  To: Florian Weimer; +Cc: libc-alpha

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.

If flag is PTHREAD_PER_PROCESS_NP then nothing happens.

If it's not PTHREAD_PER_PROCESS_NP then we record the value
along with a failure, but continue running (and will report
a test failure).

-- 
Cheers,
Carlos.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-06-28 17:09         ` Carlos O'Donell
@ 2019-06-28 18:34           ` Florian Weimer
  2019-06-28 19:15             ` Carlos O'Donell
  0 siblings, 1 reply; 24+ messages in thread
From: Florian Weimer @ 2019-06-28 18:34 UTC (permalink / raw)
  To: Carlos O'Donell; +Cc: libc-alpha

* 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.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-06-28 16:55       ` Florian Weimer
@ 2019-06-28 17:09         ` Carlos O'Donell
  2019-06-28 18:34           ` Florian Weimer
  0 siblings, 1 reply; 24+ messages in thread
From: Carlos O'Donell @ 2019-06-28 17:09 UTC (permalink / raw)
  To: Florian Weimer; +Cc: libc-alpha

On 6/28/19 12:55 PM, Florian Weimer wrote:
> * Carlos O'Donell:
> 
>> The thread_perthreadfs_indirect uses the NULL attribute,
>> and not PTHREAD_PER_PROCESS_NP explicitly, and it's an
>> implementation detail that this happens to be the same 
>> code path e.g. we copy the default global attr, then adjust
>> the scope flags. This might change in the future and it would
>> be nice to catch any breakage in a distinct test for this.
>>
>> The test would be a basic flag test looking to validate the
>> stickyness in a simpler test.
>>
>> The simpler test should have the parent threads permute over
>> [null, per-process, per-thread], and the child iterate over
>> [null, per-process, per-thread], and validate the expected
>> results.
> 
> Is it sufficient to verify that the thread attribute is set correctly,
> or do you want a fully functional test?

It is sufficient to verify that the thread attribute is set correctly.

> If the latter, I will split the indirect flag into direct, indirect with
> default attribute, and indirect with non-default attribute because I
> would have to replicate a lot of the other test functionality to verify
> per-thread separation or the lack thereof.

That sounds reasonable to me if you want to keep the test as a single test.

>>> +/* Return true if the thread has per-thread file system
>>> +   attributes.  */
>>> +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 != 0)
>>> +    TEST_COMPARE (flag, 1);
>>
>> Magic number.
>>
>> Please use some intermediate define to call this out.
>>
>> #define CHECK_PTHREAD_PER_THREAD_FS 1
>>
>> ... and use in place of 1.
>>
>> This way it's grep-able when looking for references to
>> the enumerated value.
> 
> Right, I realized that as well.  I've now got:
> 
> /* Return true if the thread has per-thread file system
>    attributes.  */
> 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);

I don't follow why you can't call this unconditionally?

>   xpthread_attr_destroy (&attr);
>   return flag == PTHREAD_PER_THREAD_NP;

OK.

> }
> 
> Thanks,
> Florian
> 


-- 
Cheers,
Carlos.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-06-28 16:37     ` Carlos O'Donell
@ 2019-06-28 16:55       ` Florian Weimer
  2019-06-28 17:09         ` Carlos O'Donell
  0 siblings, 1 reply; 24+ messages in thread
From: Florian Weimer @ 2019-06-28 16:55 UTC (permalink / raw)
  To: Carlos O'Donell; +Cc: libc-alpha

* Carlos O'Donell:

> The thread_perthreadfs_indirect uses the NULL attribute,
> and not PTHREAD_PER_PROCESS_NP explicitly, and it's an
> implementation detail that this happens to be the same 
> code path e.g. we copy the default global attr, then adjust
> the scope flags. This might change in the future and it would
> be nice to catch any breakage in a distinct test for this.
>
> The test would be a basic flag test looking to validate the
> stickyness in a simpler test.
>
> The simpler test should have the parent threads permute over
> [null, per-process, per-thread], and the child iterate over
> [null, per-process, per-thread], and validate the expected
> results.

Is it sufficient to verify that the thread attribute is set correctly,
or do you want a fully functional test?

If the latter, I will split the indirect flag into direct, indirect with
default attribute, and indirect with non-default attribute because I
would have to replicate a lot of the other test functionality to verify
per-thread separation or the lack thereof.

>> +/* Return true if the thread has per-thread file system
>> +   attributes.  */
>> +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 != 0)
>> +    TEST_COMPARE (flag, 1);
>
> Magic number.
>
> Please use some intermediate define to call this out.
>
> #define CHECK_PTHREAD_PER_THREAD_FS 1
>
> ... and use in place of 1.
>
> This way it's grep-able when looking for references to
> the enumerated value.

Right, I realized that as well.  I've now got:

/* Return true if the thread has per-thread file system
   attributes.  */
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;
}

Thanks,
Florian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-06-28 14:57   ` Florian Weimer
@ 2019-06-28 16:37     ` Carlos O'Donell
  2019-06-28 16:55       ` Florian Weimer
  0 siblings, 1 reply; 24+ messages in thread
From: Carlos O'Donell @ 2019-06-28 16:37 UTC (permalink / raw)
  To: Florian Weimer; +Cc: libc-alpha

On 6/28/19 10:57 AM, Florian Weimer wrote:
> * Carlos O'Donell:
> 
>> Please post v2 with a new test case to cover the inherited flag check.
>> - pthread_attr_getperthreadfs_np.c code change.
>> - comments added to test case.
>> - New test.
>>
>> I would like to see a new test which does:
>> - From main start a thread.
>> - In the new thread set per-thread fs, which is now sticky.
>> - Create an attr with per-process fs, and then start a new thread with that.
>> - In thread 2 use pthread_getattr_np and verify the resulting attr shows
>>   that per-thread fs as indeed sticky and the value seen is per-thread fs.
> 
> Please look at thread_perthreadfs_indirect, it's already there.  I added
> some comments there.
> 
> Do you still think a separate test is needed?

I do.

The thread_perthreadfs_indirect uses the NULL attribute,
and not PTHREAD_PER_PROCESS_NP explicitly, and it's an
implementation detail that this happens to be the same 
code path e.g. we copy the default global attr, then adjust
the scope flags. This might change in the future and it would
be nice to catch any breakage in a distinct test for this.

The test would be a basic flag test looking to validate the
stickyness in a simpler test.

The simpler test should have the parent threads permute over
[null, per-process, per-thread], and the child iterate over
[null, per-process, per-thread], and validate the expected
results.

>>> +int
>>> +pthread_attr_getperthreadfs_np (const pthread_attr_t *__restrict attr,
>>> +                                int *__restrict scope)
>>> +{
>>> +  struct pthread_attr *iattr = (struct pthread_attr *) attr;
>>> +  *scope = (iattr->flags & ATTR_FLAG_PERTHREADFS) != 0;
>>
>> The '!= 0' is a bit mystical, I would rather see someting like this:
>>
>> if (iattr->flags & ATTR_FLAG_PERTHREADFS == 0)
>>   *scope = PTHREAD_PER_PROCESS_NP;
>> else
>>   *socpe = PTHREAD_PER_THREAD_NP;
>>
>> Which makes it similar to the code in pthread_attr_setperthreadfs_np.
>>
>> The compiler should optimize this to the same thing.
> 
> Right, but I'm going to switch to an implicit flag check.
> 
>>> +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;
>>> +
>>> +  xpthread_barrier_init (&barrier, NULL, 3);
>>> +  xpthread_attr_init (&attr_perthreadfs);
>>> +  {
>>
>> Each of these tests should havea 1 comment explaining intent.
>>
>> /* 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: Set and get compares the same.  */
>>
>>> +    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 returns EINVAL.  */
> 
> Thanks, I added comments.
> 
>>> 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.
>>
>> New file? Copyright 2019.
> 
> It's substantially similar to another file, so I picked the year that
> reflected the copy.  (Same for support/xfchdir.c.)
> 
> 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..60c15a8d15 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 directiry 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)

OK. Thanks.

> +    *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..2a8ca58862
> --- /dev/null
> +++ b/nptl/tst-pthread-perthreadfs.c
> @@ -0,0 +1,318 @@
> +/* 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.  */
> +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 != 0)
> +    TEST_COMPARE (flag, 1);

Magic number.

Please use some intermediate define to call this out.

#define CHECK_PTHREAD_PER_THREAD_FS 1

... and use in place of 1.

This way it's grep-able when looking for references to
the enumerated value.

> +  xpthread_attr_destroy (&attr);
> +  return flag;
> +}
> +
> +/* 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);
> +  TEST_VERIFY (perthread_flag (thr));
> +  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);
> +      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..37073e3ce7 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));
> +
> +/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
> +   depending on the state of *ATTR.  */
> +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..b80c84c0b7 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));
> +
> +/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
> +   depending on the state of *ATTR.  */
> +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
> 


-- 
Cheers,
Carlos.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-06-28 12:59 ` Carlos O'Donell
@ 2019-06-28 14:57   ` Florian Weimer
  2019-06-28 16:37     ` Carlos O'Donell
  0 siblings, 1 reply; 24+ messages in thread
From: Florian Weimer @ 2019-06-28 14:57 UTC (permalink / raw)
  To: Carlos O'Donell; +Cc: libc-alpha

* Carlos O'Donell:

> Please post v2 with a new test case to cover the inherited flag check.
> - pthread_attr_getperthreadfs_np.c code change.
> - comments added to test case.
> - New test.
>
> I would like to see a new test which does:
> - From main start a thread.
> - In the new thread set per-thread fs, which is now sticky.
> - Create an attr with per-process fs, and then start a new thread with that.
> - In thread 2 use pthread_getattr_np and verify the resulting attr shows
>   that per-thread fs as indeed sticky and the value seen is per-thread fs.

Please look at thread_perthreadfs_indirect, it's already there.  I added
some comments there.

Do you still think a separate test is needed?

>> +int
>> +pthread_attr_getperthreadfs_np (const pthread_attr_t *__restrict attr,
>> +                                int *__restrict scope)
>> +{
>> +  struct pthread_attr *iattr = (struct pthread_attr *) attr;
>> +  *scope = (iattr->flags & ATTR_FLAG_PERTHREADFS) != 0;
>
> The '!= 0' is a bit mystical, I would rather see someting like this:
>
> if (iattr->flags & ATTR_FLAG_PERTHREADFS == 0)
>   *scope = PTHREAD_PER_PROCESS_NP;
> else
>   *socpe = PTHREAD_PER_THREAD_NP;
>
> Which makes it similar to the code in pthread_attr_setperthreadfs_np.
>
> The compiler should optimize this to the same thing.

Right, but I'm going to switch to an implicit flag check.

>> +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;
>> +
>> +  xpthread_barrier_init (&barrier, NULL, 3);
>> +  xpthread_attr_init (&attr_perthreadfs);
>> +  {
>
> Each of these tests should havea 1 comment explaining intent.
>
> /* 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: Set and get compares the same.  */
>
>> +    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 returns EINVAL.  */

Thanks, I added comments.

>> 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.
>
> New file? Copyright 2019.

It's substantially similar to another file, so I picked the year that
reflected the copy.  (Same for support/xfchdir.c.)

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..60c15a8d15 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 directiry 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..2a8ca58862
--- /dev/null
+++ b/nptl/tst-pthread-perthreadfs.c
@@ -0,0 +1,318 @@
+/* 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.  */
+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 != 0)
+    TEST_COMPARE (flag, 1);
+  xpthread_attr_destroy (&attr);
+  return flag;
+}
+
+/* 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);
+  TEST_VERIFY (perthread_flag (thr));
+  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);
+      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..37073e3ce7 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));
+
+/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
+   depending on the state of *ATTR.  */
+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..b80c84c0b7 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));
+
+/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
+   depending on the state of *ATTR.  */
+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

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-06-07 16:41 Florian Weimer
@ 2019-06-28 12:59 ` Carlos O'Donell
  2019-06-28 14:57   ` Florian Weimer
  0 siblings, 1 reply; 24+ messages in thread
From: Carlos O'Donell @ 2019-06-28 12:59 UTC (permalink / raw)
  To: Florian Weimer, libc-alpha

On 6/7/19 12:41 PM, Florian Weimer wrote:
> [Compared to the previous version, this fixes the hppa build by updating
> its own copy of pthread.h.  It also addresses the rebase conflicts due
> to other new functions.  This is still the version with the “sticky”
> behavior.]
> 
> 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.
> 

Please post v2 with a new test case to cover the inherited flag check.
- pthread_attr_getperthreadfs_np.c code change.
- comments added to test case.
- New test.

I would like to see a new test which does:
- From main start a thread.
- In the new thread set per-thread fs, which is now sticky.
- Create an attr with per-process fs, and then start a new thread with that.
- In thread 2 use pthread_getattr_np and verify the resulting attr shows
  that per-thread fs as indeed sticky and the value seen is per-thread fs.

This test shows things get copied properly from thread-to-thread and are
visible to pthread_getattr_np properly.


> 2019-06-07  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 00f9e855a2..f320675f7c 100644
> --- a/NEWS
> +++ b/NEWS
> @@ -34,6 +34,11 @@ Major new features:
>    pointer subtraction within the allocated object, where results might
>    overflow the ptrdiff_t type.
>  
> +* 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.

OK.

> +
>  Deprecated and removed features, and other changes affecting compatibility:
>  
>  * The functions clock_gettime, clock_getres, clock_settime,
> diff --git a/manual/threads.texi b/manual/threads.texi
> index 87fda7d8e7..60c15a8d15 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.

OK.

>  @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.

OK.

> +
> +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:

OK.

> +
> +@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.

OK.

> +
> +@item PTHREAD_PER_THREAD_NP
> +@standards{GNU, pthread.h}
> +This property in question is thread-specific.

OK.

> +@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.
> +

OK

> +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 directiry 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}.

OK.

> +
> +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.
> +

OK.

> +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.)
> +

OK.

> +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}.
> +

OK.

> +This function is a GNU extension and specific to Linux.
> +@end deftypefun

OK.

> +
>  @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

OK. Two new functions.

>  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

OK. Two new tests.

>  
>  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;

OK.

> +  }
>    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..6670939101
> --- /dev/null
> +++ b/nptl/pthread_attr_getperthreadfs_np.c
> @@ -0,0 +1,29 @@
> +/* Read the private file system flag in thread attributes.
> +   Copyright (C) 2019 Free Software Foundation, Inc.

OK.

> +   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;
> +  *scope = (iattr->flags & ATTR_FLAG_PERTHREADFS) != 0;

The '!= 0' is a bit mystical, I would rather see someting like this:

if (iattr->flags & ATTR_FLAG_PERTHREADFS == 0)
  *scope = PTHREAD_PER_PROCESS_NP;
else
  *socpe = PTHREAD_PER_THREAD_NP;

Which makes it similar to the code in pthread_attr_setperthreadfs_np.

The compiler should optimize this to the same thing.

> +  return 0;

OK.

> +}
> 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.

OK.

> +   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;

OK.

> +      return 0;
> +      break;
> +    case PTHREAD_PER_THREAD_NP:
> +      iattr->flags |= ATTR_FLAG_PERTHREADFS;

OK.

> +      return 0;
> +    default:
> +      return EINVAL;
> +    }
> +}

OK.

> 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));

OK. Simplifies handling of flags we ignore using ATTR_FLAGS_IGNORED_ATTR, and that looks good.

>  
>    /* 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.

OK.

> +   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);

OK.

> +
> +  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);

OK.

> +
> +  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);

OK.

> +
> +  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);
> +

OK.

> +  xpthread_barrier_wait (&barrier);
> +
> +  xpthread_join (thr2);
> +  xpthread_join (thr1);

OK.

> +
> +  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;
> +}

OK.

> +
> +#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..81cf315c97
> --- /dev/null
> +++ b/nptl/tst-pthread-perthreadfs.c
> @@ -0,0 +1,280 @@
> +/* Test per-thread file system attributes.
> +   Copyright (C) 2019 Free Software Foundation, Inc.

OK.

> +   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;
> +
> +/* 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");
> +  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 te PTHREAD_PER_THREAD_NP, but runs the actual test on
> +   a PTHREAD_PER_PROCESS_NP thread.  */
> +static void *
> +thread_perthreadfs_indirect (void *closure)
> +{
> +  return xpthread_join (xpthread_create (NULL, thread_perthreadfs, closure));
> +}
> +
> +/* Thread function launched with shared file system attributes.  */
> +static void *
> +thread_sharedfs (void *closure)
> +{
> +  /* 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;
> +
> +  xpthread_barrier_init (&barrier, NULL, 3);
> +  xpthread_attr_init (&attr_perthreadfs);
> +  {

Each of these tests should havea 1 comment explaining intent.

/* 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: Set and get compares the same.  */

> +    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 returns EINVAL.  */

> +
> +    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);

OK.

> +  }
> +
> +  /* 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).  */

OK.

> +  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);
> +
> +      /* 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 \

OK.

>    xchroot \
>    xclock_gettime \
>    xclose \
> @@ -88,6 +89,7 @@ libsupport-routines = \
>    xdlfcn \
>    xdlmopen \
>    xdup2 \
> +  xfchdir \

OK.

>    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.

New file? Copyright 2019.

> +   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);

OK.

> +}
> 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.

New file? Copyright 2019.

> +   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);

OK.

> +}
> 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);

OK.

>  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

OK.

> +
> +/* 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)

OK.

> +
> +/* 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

OK.

>  
>  
>  /* Mutex attribute data structure.  */
> diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
> index 704a3c48d6..37073e3ce7 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));
> +
> +/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
> +   depending on the state of *ATTR.  */
> +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

OK.

>  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

OK.

>  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

OK.

>  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.

OK.

>  
>       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;

OK.

>  
>    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

OK.

>  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

OK.

>  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..b80c84c0b7 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));

OK.

> +
> +/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
> +   depending on the state of *ATTR.  */
> +int pthread_attr_getperthreadfs_np (const pthread_attr_t *__restrict __attr,
> +				    int *__restrict __scope)
> +  __THROW __nonnull ((1, 2));

OK.

> +
>  /* 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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  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

OK.

>  GLIBC_2.30 tgkill F
>  GLIBC_2.30 twalk_r F
> 


-- 
Cheers,
Carlos.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] Linux: Implement per-thread file system attributes
@ 2019-06-07 16:41 Florian Weimer
  2019-06-28 12:59 ` Carlos O'Donell
  0 siblings, 1 reply; 24+ messages in thread
From: Florian Weimer @ 2019-06-07 16:41 UTC (permalink / raw)
  To: libc-alpha

[Compared to the previous version, this fixes the hppa build by updating
its own copy of pthread.h.  It also addresses the rebase conflicts due
to other new functions.  This is still the version with the “sticky”
behavior.]

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-07  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 00f9e855a2..f320675f7c 100644
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,11 @@ Major new features:
   pointer subtraction within the allocated object, where results might
   overflow the ptrdiff_t type.
 
+* 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 functions clock_gettime, clock_getres, clock_settime,
diff --git a/manual/threads.texi b/manual/threads.texi
index 87fda7d8e7..60c15a8d15 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 directiry 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..6670939101
--- /dev/null
+++ b/nptl/pthread_attr_getperthreadfs_np.c
@@ -0,0 +1,29 @@
+/* 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;
+  *scope = (iattr->flags & ATTR_FLAG_PERTHREADFS) != 0;
+  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..81cf315c97
--- /dev/null
+++ b/nptl/tst-pthread-perthreadfs.c
@@ -0,0 +1,280 @@
+/* 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;
+
+/* 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");
+  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 te PTHREAD_PER_THREAD_NP, but runs the actual test on
+   a PTHREAD_PER_PROCESS_NP thread.  */
+static void *
+thread_perthreadfs_indirect (void *closure)
+{
+  return xpthread_join (xpthread_create (NULL, thread_perthreadfs, closure));
+}
+
+/* Thread function launched with shared file system attributes.  */
+static void *
+thread_sharedfs (void *closure)
+{
+  /* 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;
+
+  xpthread_barrier_init (&barrier, NULL, 3);
+  xpthread_attr_init (&attr_perthreadfs);
+  {
+    int scope = -1;
+    TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs, &scope),
+                  0);
+    TEST_COMPARE (scope, PTHREAD_PER_PROCESS_NP);
+    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_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);
+
+      /* 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..37073e3ce7 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));
+
+/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
+   depending on the state of *ATTR.  */
+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..b80c84c0b7 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));
+
+/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
+   depending on the state of *ATTR.  */
+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

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-04-15 12:40         ` Andreas Schwab
@ 2019-04-15 13:00           ` Florian Weimer
  0 siblings, 0 replies; 24+ messages in thread
From: Florian Weimer @ 2019-04-15 13:00 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: Carlos O'Donell, libc-alpha

* Andreas Schwab:

> On Apr 15 2019, Florian Weimer <fweimer@redhat.com> wrote:
>
>> diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c
>> index 579bd94743..3516077ded 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 using the function
>> +	pthread_attr_setperthreadfs_np.
>
> That sentence lacks a verb.

Thanks, what about this?

      CLONE_VM, CLONE_FS, CLONE_FILES
 	These flags select semantics with shared address space and
 	file descriptors according to what POSIX requires.  CLONE_FS
-	is optional; it can be using the function
+	is optional; it can be controlled using the function
 	pthread_attr_setperthreadfs_np.

Do you have an opinion whether we should go with the sticky or
non-sticky approach?

Thanks,
Florian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-04-15 12:28       ` Florian Weimer
@ 2019-04-15 12:40         ` Andreas Schwab
  2019-04-15 13:00           ` Florian Weimer
  0 siblings, 1 reply; 24+ messages in thread
From: Andreas Schwab @ 2019-04-15 12:40 UTC (permalink / raw)
  To: Florian Weimer; +Cc: Carlos O'Donell, libc-alpha

On Apr 15 2019, Florian Weimer <fweimer@redhat.com> wrote:

> diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c
> index 579bd94743..3516077ded 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 using the function
> +	pthread_attr_setperthreadfs_np.

That sentence lacks a verb.

Andreas.

-- 
Andreas Schwab, SUSE Labs, schwab@suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-04-10 20:17     ` Carlos O'Donell
@ 2019-04-15 12:28       ` Florian Weimer
  2019-04-15 12:40         ` Andreas Schwab
  0 siblings, 1 reply; 24+ messages in thread
From: Florian Weimer @ 2019-04-15 12:28 UTC (permalink / raw)
  To: Carlos O'Donell; +Cc: libc-alpha

* Carlos O'Donell:

> On 4/10/19 1:03 PM, Florian Weimer wrote:
>> * Carlos O'Donell:
>>
>>> Any child created with CLONE_FS will have per-thread properties, that's
>>> clear and easy to understand.
>>>
>>> However, in the case of !CLONE_FS you will have a set of descendants
>>> which all share the same properties (not those of the process itself).
>>>
>>> (a) Is there any desire to want to create a new thread that has the same
>>>      shared properties as that of the process (not that of the parent
>>>      task)?
>>
>> I doubt we'll ever need it.  We could implement it with a separate
>> helper thread with a tiny stack, specifically serving such requests (and
>> which is created the first time per-thread attributes are created).  I
>> don't think we need to implement it right now.
>
> I agree we do not need to implement this right now, and you're right this
> could be done with a helper thread, or a signaling/msg system like setxid
> (which I actually like).

It's something what applications can do without glibc help (if we ignore
dlopen).  The new patch mentions this in the manual.

>> With my TID patches and kcmp with KCMP_FS, it will be possible to test
>> if two running threads share the same file system attributes.
>
> Perfect, and that's already useful because you it solves the use case
> I was thinking about which is mostly "Do my changes affect the
> process?"

Okay, I will update the manual entry once we have the kcmp system call
wrapper.

>>> If (a) was possible, and I don't think it is given the current linux
>>> interfaces, then when you have "PTHREAD_PER_PROCESS_NP" it would really
>>> do what the name says, and attach the thread's fs-attributes to the
>>> process (not the most recent set of descendant children from a parent
>>> task that set this value).
>>
>> I think that would be super-confusing because the net effect will be
>> that pthread_create changes these attributes (in the sense that the new
>> thread starts out with different values).
>
> The solution we have today is also confusing, in that the semantics of
> PTHREAD_PER_PROCESS_NP are changed by the state of the caller.

I thought this some more and came up with the following behavior, which
matches what we will implement for user/group IDs in the follow-up
patch.

>>> A library, with an outside view, can't tell, by accessing the
>>> thread attributes via pthread_getattr_np(), if it shares with
>>> the process or not because PTHREAD_PER_PROCESS_NP will bet set.
>>
>> True, but one of the threads may have called unshare, so you need kernel
>> support anyway.
>
> That's very different from calling pthread_create() which is a known
> API that might not be expected to change the behaviour of future
> pthread_create() invocations.

But it does!  Future pthread_create calls from such a thread will share
resources with that thread only, and not the main thread.

>> We could also make PTHREAD_PER_THREAD_NP sticky in the sense that *all*
>> descendent threads have it set automatically, nom atter what the
>> attribute requests.  This is what we need to implement for user and
>> group IDs, as discussed before.  We could also add a third flag for the
>> non-sticky behavior.
>
> Yes, I like this idea. I think PTHREAD_PER_THREAD_NP should be sticky
> and setting PTHREAD_PER_PROCESS_NP should result in a error,

The error part will make it impossible to use std::thread and the like
from such threads, which I think is undesirable.

The patch below makes the behavior sticky.

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-04-15  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_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 b58e2469d4..a8145e8423 100644
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,11 @@ Major new features:
 
 * The entry for the new Japanese era has been added for ja_JP locale.
 
+* 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 functions clock_gettime, clock_getres, clock_settime,
diff --git a/manual/threads.texi b/manual/threads.texi
index 87fda7d8e7..60c15a8d15 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 directiry 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 f9bc5cc887..d9f2dd42c0 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..6670939101
--- /dev/null
+++ b/nptl/pthread_attr_getperthreadfs_np.c
@@ -0,0 +1,29 @@
+/* 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;
+  *scope = (iattr->flags & ATTR_FLAG_PERTHREADFS) != 0;
+  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..81cf315c97
--- /dev/null
+++ b/nptl/tst-pthread-perthreadfs.c
@@ -0,0 +1,280 @@
+/* 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;
+
+/* 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");
+  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 te PTHREAD_PER_THREAD_NP, but runs the actual test on
+   a PTHREAD_PER_PROCESS_NP thread.  */
+static void *
+thread_perthreadfs_indirect (void *closure)
+{
+  return xpthread_join (xpthread_create (NULL, thread_perthreadfs, closure));
+}
+
+/* Thread function launched with shared file system attributes.  */
+static void *
+thread_sharedfs (void *closure)
+{
+  /* 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;
+
+  xpthread_barrier_init (&barrier, NULL, 3);
+  xpthread_attr_init (&attr_perthreadfs);
+  {
+    int scope = -1;
+    TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs, &scope),
+                  0);
+    TEST_COMPARE (scope, PTHREAD_PER_PROCESS_NP);
+    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_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);
+
+      /* 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 f173565202..b71f2f3a72 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -76,6 +76,7 @@ libsupport-routines = \
   xasprintf \
   xbind \
   xcalloc \
+  xchdir \
   xchroot \
   xclose \
   xconnect \
@@ -83,6 +84,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..37073e3ce7 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));
+
+/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
+   depending on the state of *ATTR.  */
+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 f3b44d723f..7912106998 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2142,3 +2142,5 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index fd81fc4ad0..8f55111716 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2217,6 +2217,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index f451fefac9..d6595fe7d0 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -127,6 +127,8 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c
index 579bd94743..3516077ded 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 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 018d02b414..28c54ac331 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2086,3 +2086,5 @@ GLIBC_2.29 xencrypt F
 GLIBC_2.29 xprt_register F
 GLIBC_2.29 xprt_unregister F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index fc3c5d5c27..82bbcfdb88 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2038,6 +2038,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index f2b04dbbff..c258476838 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2204,6 +2204,8 @@ GLIBC_2.3.4 vm86 F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 10ecf2e47c..439b51895d 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2070,6 +2070,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 814e81b9d2..3c4b521a71 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -128,6 +128,8 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 68e80372e7..a69f98d9f3 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2147,6 +2147,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 31178e4f54..880e71b23c 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2134,3 +2134,5 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 7074573638..a7710cd95d 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2121,6 +2121,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 154f9c77fc..a09634310a 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2119,6 +2119,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 97b8f42d5c..a865424562 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2127,6 +2127,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 5b3e85de93..e54df4f9c1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2121,6 +2121,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 04a130a81c..6c0e4f850a 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2175,3 +2175,5 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index a701584422..f4fb7c1108 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2177,6 +2177,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index bbb647cd98..b6482e239e 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2210,6 +2210,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index bb23bf61a8..5f558722dd 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2040,6 +2040,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 7921dda979..c5bca34fde 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2244,3 +2244,5 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index da123d3867..8409b9dab0 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2104,3 +2104,5 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 2aed339af4..fe23f03d8b 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2172,6 +2172,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index e46feb56e5..1c546e63d6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2076,6 +2076,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index 24a8f934cb..ad60fb32e5 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -2042,6 +2042,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index ebdbd2c5ae..f6bf145af9 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2166,6 +2166,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 0992349b06..aeb6cc37f5 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2093,6 +2093,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 af004fcff6..eb0558be26 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2051,6 +2051,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 84015f0a57..92d7386d87 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2150,3 +2150,5 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-04-10 17:52   ` Florian Weimer
@ 2019-04-10 20:17     ` Carlos O'Donell
  2019-04-15 12:28       ` Florian Weimer
  0 siblings, 1 reply; 24+ messages in thread
From: Carlos O'Donell @ 2019-04-10 20:17 UTC (permalink / raw)
  To: Florian Weimer; +Cc: libc-alpha

On 4/10/19 1:03 PM, Florian Weimer wrote:
> * Carlos O'Donell:
> 
>> Any child created with CLONE_FS will have per-thread properties, that's
>> clear and easy to understand.
>>
>> However, in the case of !CLONE_FS you will have a set of descendants
>> which all share the same properties (not those of the process itself).
>>
>> (a) Is there any desire to want to create a new thread that has the same
>>      shared properties as that of the process (not that of the parent
>>      task)?
> 
> I doubt we'll ever need it.  We could implement it with a separate
> helper thread with a tiny stack, specifically serving such requests (and
> which is created the first time per-thread attributes are created).  I
> don't think we need to implement it right now.

I agree we do not need to implement this right now, and you're right this
could be done with a helper thread, or a signaling/msg system like setxid
(which I actually like).

> (The setxid mechanism could be used as well, but we probably do not want
> to pile more functionality onto it.)
> 
>> (b) Is there any need to identify the parent that created the set of
>>      descendants that share all the same filesystem properties?
> 
> We do not have a unique identifier for the parent thread, so I don't
> think that can be implemented today.

Right there is an ABA issue with TID reuse.

> With my TID patches and kcmp with KCMP_FS, it will be possible to test
> if two running threads share the same file system attributes.

Perfect, and that's already useful because you it solves the use case
I was thinking about which is mostly "Do my changes affect the process?"
  
>> If (a) was possible, and I don't think it is given the current linux
>> interfaces, then when you have "PTHREAD_PER_PROCESS_NP" it would really
>> do what the name says, and attach the thread's fs-attributes to the
>> process (not the most recent set of descendant children from a parent
>> task that set this value).
> 
> I think that would be super-confusing because the net effect will be
> that pthread_create changes these attributes (in the sense that the new
> thread starts out with different values).

The solution we have today is also confusing, in that the semantics of
PTHREAD_PER_PROCESS_NP are changed by the state of the caller.

>> A library, with an outside view, can't tell, by accessing the
>> thread attributes via pthread_getattr_np(), if it shares with
>> the process or not because PTHREAD_PER_PROCESS_NP will bet set.
> 
> True, but one of the threads may have called unshare, so you need kernel
> support anyway.

That's very different from calling pthread_create() which is a known
API that might not be expected to change the behaviour of future
pthread_create() invocations.

> We could also make PTHREAD_PER_THREAD_NP sticky in the sense that *all*
> descendent threads have it set automatically, nom atter what the
> attribute requests.  This is what we need to implement for user and
> group IDs, as discussed before.  We could also add a third flag for the
> non-sticky behavior.

Yes, I like this idea. I think PTHREAD_PER_THREAD_NP should be sticky
and setting PTHREAD_PER_PROCESS_NP should result in a error, while
setting some new non-sticky value PTHREAD_PARENT_NP allows you to
inherit your FS from the thread calling pthread_create().

Did we miss anything else?

-- 
Cheers,
Carlos.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-04-10 15:47 ` Carlos O'Donell
@ 2019-04-10 17:52   ` Florian Weimer
  2019-04-10 20:17     ` Carlos O'Donell
  0 siblings, 1 reply; 24+ messages in thread
From: Florian Weimer @ 2019-04-10 17:52 UTC (permalink / raw)
  To: Carlos O'Donell; +Cc: libc-alpha

* Carlos O'Donell:

> Any child created with CLONE_FS will have per-thread properties, that's
> clear and easy to understand.
>
> However, in the case of !CLONE_FS you will have a set of descendants
> which all share the same properties (not those of the process itself).
>
> (a) Is there any desire to want to create a new thread that has the same
>     shared properties as that of the process (not that of the parent
>     task)?

I doubt we'll ever need it.  We could implement it with a separate
helper thread with a tiny stack, specifically serving such requests (and
which is created the first time per-thread attributes are created).  I
don't think we need to implement it right now.

(The setxid mechanism could be used as well, but we probably do not want
to pile more functionality onto it.)

> (b) Is there any need to identify the parent that created the set of
>     descendants that share all the same filesystem properties?

We do not have a unique identifier for the parent thread, so I don't
think that can be implemented today.

With my TID patches and kcmp with KCMP_FS, it will be possible to test
if two running threads share the same file system attributes.

> If (a) was possible, and I don't think it is given the current linux
> interfaces, then when you have "PTHREAD_PER_PROCESS_NP" it would really
> do what the name says, and attach the thread's fs-attributes to the
> process (not the most recent set of descendant children from a parent
> task that set this value).

I think that would be super-confusing because the net effect will be
that pthread_create changes these attributes (in the sense that the new
thread starts out with different values).

> A library, with an outside view, can't tell, by accessing the
> thread attributes via pthread_getattr_np(), if it shares with
> the process or not because PTHREAD_PER_PROCESS_NP will bet set.

True, but one of the threads may have called unshare, so you need kernel
support anyway.

We could also make PTHREAD_PER_THREAD_NP sticky in the sense that *all*
descendent threads have it set automatically, nom atter what the
attribute requests.  This is what we need to implement for user and
group IDs, as discussed before.  We could also add a third flag for the
non-sticky behavior.

Thanks,
Florian

^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH] Linux: Implement per-thread file system attributes
  2019-04-10 15:39 Florian Weimer
@ 2019-04-10 15:47 ` Carlos O'Donell
  2019-04-10 17:52   ` Florian Weimer
  0 siblings, 1 reply; 24+ messages in thread
From: Carlos O'Donell @ 2019-04-10 15:47 UTC (permalink / raw)
  To: Florian Weimer, libc-alpha

On 4/10/19 11:15 AM, 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.
> -----
> Changes from the previous version:
> 
> - rebased to glibc 2.30
> - some documentation in the manual
> - closer alignment to other pthread attributes
>    (e.g. the pshared flag handling)
> 
> If approved, I will put the support/ bits into a separate commit.

I haven't gone through the whole patch yet, but something specific came
to mind as I read through the API semantics.

Any child created with CLONE_FS will have per-thread properties, that's
clear and easy to understand.

However, in the case of !CLONE_FS you will have a set of descendants
which all share the same properties (not those of the process itself).

(a) Is there any desire to want to create a new thread that has the same
     shared properties as that of the process (not that of the parent
     task)?

(b) Is there any need to identify the parent that created the set of
     descendants that share all the same filesystem properties?

If (a) was possible, and I don't think it is given the current linux
interfaces, then when you have "PTHREAD_PER_PROCESS_NP" it would really
do what the name says, and attach the thread's fs-attributes to the
process (not the most recent set of descendant children from a parent
task that set this value).

Is (a) possible?

If (a) is not possible, it's interesting to ask the following question
as a programming:

* Given the current thread.
* Does it share the filesystem attributes with the process?
* If it does, then take certain steps to avoid stomping on it.
* If it doesn't, then do whatever you want.

The problem here is this:
pthread_create (PTHREAD_PER_THREAD_NP) -> Thread A.
Thread A -> pthread_create (PTHREAD_PER_PROCESS_NP) -> Thread B.
Thread B -> Library tries to determine if it's sharing or not with the whole process.

A library, with an outside view, can't tell, by accessing the
thread attributes via pthread_getattr_np(), if it shares with
the process or not because PTHREAD_PER_PROCESS_NP will bet set.

Should (b) be considered? Should we store the value of the parent task
into the attribute structure in some way? Or only store a bit to
indicate that we are in a distinct set from the process itself?

It may be that this doesn't matter and that in the future we'll just
need a new API for this kind of query if it becomes relevant.

I'm just looking at the broader design to see if it impacts any
choice you have to make today.

-- 
Cheers,
Carlos.

^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH] Linux: Implement per-thread file system attributes
@ 2019-04-10 15:39 Florian Weimer
  2019-04-10 15:47 ` Carlos O'Donell
  0 siblings, 1 reply; 24+ messages in thread
From: Florian Weimer @ 2019-04-10 15:39 UTC (permalink / raw)
  To: libc-alpha

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.
-----
Changes from the previous version:

- rebased to glibc 2.30
- some documentation in the manual
- closer alignment to other pthread attributes
  (e.g. the pshared flag handling)

If approved, I will put the support/ bits into a separate commit.

Thanks,
Florian

2019-04-10  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.29): 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/tst-pthread-perthreadfs.c: Likewise.
	* nptl/tst-pthread-perthreadfs-chroot.c: Likewise.
	* sysdeps/nptl/internaltypes.h (ATTR_FLAG_PERTHREADFS): Define.
	* sysdeps/unix/sysv/linux/createthread.c (create_thread): Use it.
	* sysdeps/nptl/pthread.h (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/libc-le.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 b58e2469d4..a8145e8423 100644
--- a/NEWS
+++ b/NEWS
@@ -24,6 +24,11 @@ Major new features:
 
 * The entry for the new Japanese era has been added for ja_JP locale.
 
+* 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 functions clock_gettime, clock_getres, clock_settime,
diff --git a/manual/threads.texi b/manual/threads.texi
index 87fda7d8e7..7bb69e16c9 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,89 @@ 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
+
+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 directiry 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.
+
+If a thread that has been created with the
+@code{PTHREAD_PER_THREAD_NP} flag creates further threads and those
+are created with @code{PTHREAD_PER_PROCESS_NP} as the file-system
+sharing mode (either explicit or implicty), they share the file-system
+properties with the creating thread and its descendant threads (and
+not the entire process).
+
+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 f9bc5cc887..d9f2dd42c0 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..6670939101
--- /dev/null
+++ b/nptl/pthread_attr_getperthreadfs_np.c
@@ -0,0 +1,29 @@
+/* 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;
+  *scope = (iattr->flags & ATTR_FLAG_PERTHREADFS) != 0;
+  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/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..a1be7ad7af
--- /dev/null
+++ b/nptl/tst-pthread-perthreadfs.c
@@ -0,0 +1,257 @@
+/* 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;
+
+/* 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");
+  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;
+}
+
+/* Thread function launched with shared file system attributes.  */
+static void *
+thread_sharedfs (void *closure)
+{
+  /* 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;
+
+  xpthread_barrier_init (&barrier, NULL, 3);
+  xpthread_attr_init (&attr_perthreadfs);
+  {
+    int scope = -1;
+    TEST_COMPARE (pthread_attr_getperthreadfs_np (&attr_perthreadfs, &scope),
+                  0);
+    TEST_COMPARE (scope, PTHREAD_PER_PROCESS_NP);
+    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_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);
+  }
+
+  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 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);
+
+  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 f173565202..b71f2f3a72 100644
--- a/support/Makefile
+++ b/support/Makefile
@@ -76,6 +76,7 @@ libsupport-routines = \
   xasprintf \
   xbind \
   xcalloc \
+  xchdir \
   xchroot \
   xclose \
   xconnect \
@@ -83,6 +84,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..4e02ee8c2b 100644
--- a/sysdeps/nptl/internaltypes.h
+++ b/sysdeps/nptl/internaltypes.h
@@ -48,6 +48,7 @@ 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
 
 
 /* Mutex attribute data structure.  */
diff --git a/sysdeps/nptl/pthread.h b/sysdeps/nptl/pthread.h
index 704a3c48d6..37073e3ce7 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));
+
+/* Set *SCOPE to PTHREAD_PER_PROCESS_NP or PTHREAD_PER_THREAD_NP,
+   depending on the state of *ATTR.  */
+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 f3b44d723f..7912106998 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2142,3 +2142,5 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index fd81fc4ad0..8f55111716 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2217,6 +2217,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/arm/libc.abilist b/sysdeps/unix/sysv/linux/arm/libc.abilist
index f451fefac9..d6595fe7d0 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -127,6 +127,8 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0xa0
 GLIBC_2.4 _IO_2_1_stdin_ D 0xa0
diff --git a/sysdeps/unix/sysv/linux/createthread.c b/sysdeps/unix/sysv/linux/createthread.c
index 579bd94743..3516077ded 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 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 018d02b414..28c54ac331 100644
--- a/sysdeps/unix/sysv/linux/csky/libc.abilist
+++ b/sysdeps/unix/sysv/linux/csky/libc.abilist
@@ -2086,3 +2086,5 @@ GLIBC_2.29 xencrypt F
 GLIBC_2.29 xprt_register F
 GLIBC_2.29 xprt_unregister F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index fc3c5d5c27..82bbcfdb88 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -2038,6 +2038,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/i386/libc.abilist b/sysdeps/unix/sysv/linux/i386/libc.abilist
index f2b04dbbff..c258476838 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2204,6 +2204,8 @@ GLIBC_2.3.4 vm86 F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 10ecf2e47c..439b51895d 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -2070,6 +2070,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 814e81b9d2..3c4b521a71 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -128,6 +128,8 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _Exit F
 GLIBC_2.4 _IO_2_1_stderr_ D 0x98
 GLIBC_2.4 _IO_2_1_stdin_ D 0x98
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
index 68e80372e7..a69f98d9f3 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -2147,6 +2147,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index 31178e4f54..880e71b23c 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2134,3 +2134,5 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 7074573638..a7710cd95d 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -2121,6 +2121,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 154f9c77fc..a09634310a 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -2119,6 +2119,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 97b8f42d5c..a865424562 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -2127,6 +2127,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 5b3e85de93..e54df4f9c1 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -2121,6 +2121,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/nios2/libc.abilist b/sysdeps/unix/sysv/linux/nios2/libc.abilist
index 04a130a81c..6c0e4f850a 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2175,3 +2175,5 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index a701584422..f4fb7c1108 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -2177,6 +2177,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
index bbb647cd98..b6482e239e 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -2210,6 +2210,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
index bb23bf61a8..5f558722dd 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/be/libc.abilist
@@ -2040,6 +2040,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
index 7921dda979..c5bca34fde 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/le/libc.abilist
@@ -2244,3 +2244,5 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
index da123d3867..8409b9dab0 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2104,3 +2104,5 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index 2aed339af4..fe23f03d8b 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -2172,6 +2172,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
index e46feb56e5..1c546e63d6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -2076,6 +2076,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sh/libc.abilist b/sysdeps/unix/sysv/linux/sh/libc.abilist
index 24a8f934cb..ad60fb32e5 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -2042,6 +2042,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_chk F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
index ebdbd2c5ae..f6bf145af9 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -2166,6 +2166,8 @@ GLIBC_2.30 __nldbl_vwarnx F
 GLIBC_2.30 __nldbl_warn F
 GLIBC_2.30 __nldbl_warnx F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 _IO_fprintf F
 GLIBC_2.4 _IO_printf F
 GLIBC_2.4 _IO_sprintf F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
index 0992349b06..aeb6cc37f5 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -2093,6 +2093,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 af004fcff6..eb0558be26 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -2051,6 +2051,8 @@ GLIBC_2.3.4 setsourcefilter F
 GLIBC_2.3.4 xdr_quad_t F
 GLIBC_2.3.4 xdr_u_quad_t F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F
 GLIBC_2.4 __confstr_chk F
 GLIBC_2.4 __fgets_chk F
 GLIBC_2.4 __fgets_unlocked_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 84015f0a57..92d7386d87 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2150,3 +2150,5 @@ GLIBC_2.29 getcpu F
 GLIBC_2.29 posix_spawn_file_actions_addchdir_np F
 GLIBC_2.29 posix_spawn_file_actions_addfchdir_np F
 GLIBC_2.30 gettid F
+GLIBC_2.30 pthread_attr_getperthreadfs_np F
+GLIBC_2.30 pthread_attr_setperthreadfs_np F

^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2019-07-01 16:32 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-11-30 12:03 [PATCH] Linux: Implement per-thread file system attributes Florian Weimer
2018-12-05 13:21 ` Florian Weimer
2018-12-13  9:18 ` Florian Weimer
2019-02-08 12:31   ` Florian Weimer
2019-04-10 15:39 Florian Weimer
2019-04-10 15:47 ` Carlos O'Donell
2019-04-10 17:52   ` Florian Weimer
2019-04-10 20:17     ` Carlos O'Donell
2019-04-15 12:28       ` Florian Weimer
2019-04-15 12:40         ` Andreas Schwab
2019-04-15 13:00           ` Florian Weimer
2019-06-07 16:41 Florian Weimer
2019-06-28 12:59 ` Carlos O'Donell
2019-06-28 14:57   ` Florian Weimer
2019-06-28 16:37     ` Carlos O'Donell
2019-06-28 16:55       ` Florian Weimer
2019-06-28 17:09         ` Carlos O'Donell
2019-06-28 18:34           ` Florian Weimer
2019-06-28 19:15             ` Carlos O'Donell
2019-06-28 19:19               ` Florian Weimer
2019-06-28 19:59                 ` Carlos O'Donell
2019-06-28 20:20                   ` Florian Weimer
2019-06-30  5:04                     ` Carlos O'Donell
2019-07-01 16:32                       ` Florian Weimer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).