Add the statx function

Message ID b1fd37e8-4fc5-9335-ab30-3685ab78be1f@redhat.com
State Committed
Headers

Commit Message

Florian Weimer July 5, 2018, 6:59 p.m. UTC
  On 07/05/2018 08:36 PM, Paul Eggert wrote:
> Florian Weimer wrote:
> 
>> +  *buf = (struct statx)
>> +    {
>> +      /* We copy everything from fstat64, which corresponds the basic
>> +         fstat64.  */
>> +      .stx_mask = STATX_BASIC_STATS,
> 
> That assignment to *BUF unnecessarily clears all *BUF fields not 
> mentioned. It should be a bit more efficient to have a separate 
> assignment for each mentioned field, e.g., 'buf->stx_mask = 
> STATX_BASIC_STATS;'.

Clearing all padding fields is part of the userspace interface.  It's 
described in the UAPI header file, and the kernel implements that.

I've updated the comment.

I also fixed a C&P mistake in the major/minor extraction.

>> +int statx (int __dirfd, const char *__path, int __flags,
>> +           unsigned int __mask, struct statx *__buf)
>> +  __THROW __nonnull ((2, 5));
> 
> The two pointer parameters should both be declared with __restrict.

Okay, I've added __restrict qualifiers.

As Andreas suggested, I've added STATX_ALL and STATX__RESERVED.

Thanks,
Florian
  

Comments

Carlos O'Donell July 5, 2018, 7:05 p.m. UTC | #1
On 07/05/2018 02:59 PM, Florian Weimer wrote:
> On 07/05/2018 08:36 PM, Paul Eggert wrote:
>> Florian Weimer wrote:
>>
>>> +  *buf = (struct statx)
>>> +    {
>>> +      /* We copy everything from fstat64, which corresponds the basic
>>> +         fstat64.  */
>>> +      .stx_mask = STATX_BASIC_STATS,
>>
>> That assignment to *BUF unnecessarily clears all *BUF fields not mentioned. It should be a bit more efficient to have a separate assignment for each mentioned field, e.g., 'buf->stx_mask = STATX_BASIC_STATS;'.
> 
> Clearing all padding fields is part of the userspace interface.  It's described in the UAPI header file, and the kernel implements that.
> 
> I've updated the comment.
> 
> I also fixed a C&P mistake in the major/minor extraction.
> 
>>> +int statx (int __dirfd, const char *__path, int __flags,
>>> +           unsigned int __mask, struct statx *__buf)
>>> +  __THROW __nonnull ((2, 5));
>>
>> The two pointer parameters should both be declared with __restrict.
> 
> Okay, I've added __restrict qualifiers.
> 
> As Andreas suggested, I've added STATX_ALL and STATX__RESERVED.

I'm not reviewing this yet.

However, as glibc 2.28 release manager I OK the addition of statx
into the release if you can get it reviewed in the next couple of
business days.
  
Paul Eggert July 7, 2018, 11:23 p.m. UTC | #2
Thanks for clarifying about the unused fields. This patch looks good.
  
Florian Weimer July 10, 2018, 9:16 a.m. UTC | #3
On 07/08/2018 01:23 AM, Paul Eggert wrote:
> Thanks for clarifying about the unused fields. This patch looks good.

Thanks for your review.

Carlos, do you want this in glibc 2.28?  There haven't been any comments 
from kernel people about our emulation so far, but we generally do not 
consider this a requirement for system call wrappers.

Florian
  
Carlos O'Donell July 10, 2018, 12:14 p.m. UTC | #4
On 07/10/2018 05:16 AM, Florian Weimer wrote:
> On 07/08/2018 01:23 AM, Paul Eggert wrote:
>> Thanks for clarifying about the unused fields. This patch looks
>> good.
> 
> Thanks for your review.
> 
> Carlos, do you want this in glibc 2.28?  There haven't been any
> comments from kernel people about our emulation so far, but we
> generally do not consider this a requirement for system call
> wrappers.

Please commit this for 2.28.

I'd like to see as many kernel wrappers in each release as possible.

The ABI/API was designed by the kernel developers, and I trust their
review.

In this case the discussion of emulation can continue without impacting
the ABI/API. Though it has an impact on what applications expect, all
such applications should be diligently checking error returns.
  
Florian Weimer July 10, 2018, 2:18 p.m. UTC | #5
On 07/10/2018 02:14 PM, Carlos O'Donell wrote:
> On 07/10/2018 05:16 AM, Florian Weimer wrote:
>> On 07/08/2018 01:23 AM, Paul Eggert wrote:
>>> Thanks for clarifying about the unused fields. This patch looks
>>> good.
>>
>> Thanks for your review.
>>
>> Carlos, do you want this in glibc 2.28?  There haven't been any
>> comments from kernel people about our emulation so far, but we
>> generally do not consider this a requirement for system call
>> wrappers.
> 
> Please commit this for 2.28.

Thanks, done.

Florian
  
Andreas Schwab July 11, 2018, 6:53 a.m. UTC | #6
/usr/include/sys/stat.h:446:11: fatal error: bits/statx.h: No such file or directory
 # include <bits/statx.h>
           ^~~~~~~~~~~~~~

Andreas.
  
Florian Weimer July 11, 2018, 6:55 a.m. UTC | #7
On 07/11/2018 08:53 AM, Andreas Schwab wrote:
> /usr/include/sys/stat.h:446:11: fatal error: bits/statx.h: No such file or directory
>   # include <bits/statx.h>
>             ^~~~~~~~~~~~~~

Okay, so this file should be an installed header.  I will commit a fix 
after testing.

Any idea why our header tests do not catch this?

Thanks,
Florian
  
Szabolcs Nagy July 11, 2018, 10:01 a.m. UTC | #8
On 11/07/18 07:55, Florian Weimer wrote:
> On 07/11/2018 08:53 AM, Andreas Schwab wrote:
>> /usr/include/sys/stat.h:446:11: fatal error: bits/statx.h: No such file or directory
>>   # include <bits/statx.h>
>>             ^~~~~~~~~~~~~~
> 
> Okay, so this file should be an installed header.  I will commit a fix after testing.
> 
> Any idea why our header tests do not catch this?
> 

because the glibc source tree does have bits/statx.h
and all tests (incorrectly) run with internal headers
in the include path (not just the installed ones).

build-many-glibcs.py catches it though when building gcc
(i've just run into this).
  
Jeff Law July 11, 2018, 1:44 p.m. UTC | #9
On 07/11/2018 04:01 AM, Szabolcs Nagy wrote:
> On 11/07/18 07:55, Florian Weimer wrote:
>> On 07/11/2018 08:53 AM, Andreas Schwab wrote:
>>> /usr/include/sys/stat.h:446:11: fatal error: bits/statx.h: No such
>>> file or directory
>>>   # include <bits/statx.h>
>>>             ^~~~~~~~~~~~~~
>>
>> Okay, so this file should be an installed header.  I will commit a fix
>> after testing.
>>
>> Any idea why our header tests do not catch this?
>>
> 
> because the glibc source tree does have bits/statx.h
> and all tests (incorrectly) run with internal headers
> in the include path (not just the installed ones).
> 
> build-many-glibcs.py catches it though when building gcc
> (i've just run into this).
My testers started tripping over this yesterday on various platforms.

jeff
  
Florian Weimer July 26, 2018, 3:16 p.m. UTC | #10
On 07/11/2018 12:01 PM, Szabolcs Nagy wrote:
> On 11/07/18 07:55, Florian Weimer wrote:
>> On 07/11/2018 08:53 AM, Andreas Schwab wrote:
>>> /usr/include/sys/stat.h:446:11: fatal error: bits/statx.h: No such 
>>> file or directory
>>>   # include <bits/statx.h>
>>>             ^~~~~~~~~~~~~~
>>
>> Okay, so this file should be an installed header.  I will commit a fix 
>> after testing.
>>
>> Any idea why our header tests do not catch this?
>>
> 
> because the glibc source tree does have bits/statx.h
> and all tests (incorrectly) run with internal headers
> in the include path (not just the installed ones).

I had hoped that the check-installed-headers-* tests would catch this, 
but clearly that's not the case.

> build-many-glibcs.py catches it though when building gcc
> (i've just run into this).

Only if GCC uses the header, right?  So it's only limited coverage 
because GCC aims to be portable and won't use obscure stuff.

Thanks,
Florian
  
Andreas Schwab July 26, 2018, 7:38 p.m. UTC | #11
On Jul 26 2018, Florian Weimer <fweimer@redhat.com> wrote:

> On 07/11/2018 12:01 PM, Szabolcs Nagy wrote:
>> On 11/07/18 07:55, Florian Weimer wrote:
>>> On 07/11/2018 08:53 AM, Andreas Schwab wrote:
>>>> /usr/include/sys/stat.h:446:11: fatal error: bits/statx.h: No such
>>>> file or directory
>>>>   # include <bits/statx.h>
>>>>             ^~~~~~~~~~~~~~
>>>
>>> Okay, so this file should be an installed header.  I will commit a fix
>>> after testing.
>>>
>>> Any idea why our header tests do not catch this?
>>>
>>
>> because the glibc source tree does have bits/statx.h
>> and all tests (incorrectly) run with internal headers
>> in the include path (not just the installed ones).
>
> I had hoped that the check-installed-headers-* tests would catch this, but
> clearly that's not the case.
>
>> build-many-glibcs.py catches it though when building gcc
>> (i've just run into this).
>
> Only if GCC uses the header, right?  So it's only limited coverage because
> GCC aims to be portable and won't use obscure stuff.

<sys/stat.h> isn't obscure.

Andreas.
  
Florian Weimer July 26, 2018, 9:16 p.m. UTC | #12
On 07/26/2018 09:38 PM, Andreas Schwab wrote:

>>> build-many-glibcs.py catches it though when building gcc
>>> (i've just run into this).
>>
>> Only if GCC uses the header, right?  So it's only limited coverage because
>> GCC aims to be portable and won't use obscure stuff.
> 
> <sys/stat.h> isn't obscure.

We had another issue with <threads.h>.

Florian
  

Patch

Subject: [PATCH] Add the statx function
To: libc-alpha@sourceware.org

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

	* io/Makefile (routines): Add statx.
	(tests-internal): Add tst-statx.
	* io/Versions (GLIBC_2.28): Export statx.
	* io/bits/statx.h: New file.
	* io/sys/stat.h [__USE_GNU]: Include it.
	* io/fcntl.h [__USE_GNU] (AT_STATX_SYNC_TYPE)
	(AT_STATX_SYNC_AS_STAT, AT_STATX_FORCE_SYNC, AT_STATX_DONT_SYNC):
	Define.
	* io/statx.c: New file.
	* io/statx_generic.: Likewise.
	* io/tst-statx.: Likewise.
	* include/bits/statx.h: Likewise.
	* sysdeps/unix/sysv/linux/kernel-features.h
	[__LINUX_KERNEL_VERSION >= 0x040B00] (__ASSUME_STATX): Define.
	* sysdeps/unix/sysv/linux/alpha/kernel-features.h
	[__LINUX_KERNEL_VERSION < 0x040D00] (__ASSUME_STATX): Undefine.
	* sysdeps/unix/sysv/linux/ia64/kernel-features.h (__ASSUME_STATX):
	Undefine.
	* sysdeps/unix/sysv/linux/microblaze/kernel-features.h
	[__LINUX_KERNEL_VERSION < 0x040C00] (__ASSUME_STATX): Undefine.
	* sysdeps/unix/sysv/linux/statx.c: New file.
	* manual/filesys.texi: Note that statx is undocumented.
	* sysdeps/**/libc*.abilist: Update.

diff --git a/NEWS b/NEWS
index 716d11cda1..32290c1f76 100644
--- a/NEWS
+++ b/NEWS
@@ -55,6 +55,8 @@  Major new features:
   flags and a non-existing destination (and therefore has a race condition
   that can clobber the destination inadvertently).
 
+* The statx function has been added.
+
 * IDN domain names in getaddrinfo and getnameinfo now use the system libidn2
   library if installed.  libidn2 version 2.0.5 or later is recommended.  If
   libidn2 is not available, internationalized domain names are not encoded
diff --git a/include/bits/statx.h b/include/bits/statx.h
new file mode 100644
index 0000000000..8ec78a4f37
--- /dev/null
+++ b/include/bits/statx.h
@@ -0,0 +1 @@ 
+#include <io/bits/statx.h>
diff --git a/io/Makefile b/io/Makefile
index 4a0d8fea09..f5b1b61d4e 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -31,7 +31,7 @@  routines :=								\
 	utime								\
 	mkfifo mkfifoat							\
 	stat fstat lstat stat64 fstat64 lstat64 fstatat fstatat64	\
-	xstat fxstat lxstat xstat64 fxstat64 lxstat64			\
+	xstat fxstat lxstat xstat64 fxstat64 lxstat64 statx		\
 	mknod mknodat xmknod xmknodat					\
 	fxstatat fxstatat64						\
 	statfs fstatfs statfs64 fstatfs64				\
@@ -78,6 +78,9 @@  tests		:= test-utime test-stat test-stat2 test-lfs tst-getcwd \
 tests-static += tst-copy_file_range-compat
 tests-internal += tst-copy_file_range-compat
 
+# Likewise for statx, but we do not need static linking here.
+tests-internal += tst-statx
+
 ifeq ($(run-built-tests),yes)
 tests-special += $(objpfx)ftwtest.out
 endif
diff --git a/io/Versions b/io/Versions
index 98037fbbfc..f7e5dbe49e 100644
--- a/io/Versions
+++ b/io/Versions
@@ -130,6 +130,7 @@  libc {
   }
   GLIBC_2.28 {
     fcntl64;
+    statx;
   }
   GLIBC_PRIVATE {
     __libc_fcntl64;
diff --git a/io/bits/statx.h b/io/bits/statx.h
new file mode 100644
index 0000000000..e31254e361
--- /dev/null
+++ b/io/bits/statx.h
@@ -0,0 +1,91 @@ 
+/* statx-related definitions and declarations.
+   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/>.  */
+
+/* This interface is based on <linux/stat.h> in Linux.  */
+
+#ifndef _SYS_STAT_H
+# error Never include <bits/stat.x.h> directly, include <sys/stat.h> instead.
+#endif
+
+struct statx_timestamp
+{
+  __int64_t tv_sec;
+  __uint32_t tv_nsec;
+  __int32_t __statx_timestamp_pad1[1];
+};
+
+/* Warning: The kernel may add additional fields to this struct in the
+   future.  Only use this struct for calling the statx function, not
+   for storing data.  (Expansion will be controlled by the mask
+   argument of the statx function.)  */
+struct statx
+{
+  __uint32_t stx_mask;
+  __uint32_t stx_blksize;
+  __uint64_t stx_attributes;
+  __uint32_t stx_nlink;
+  __uint32_t stx_uid;
+  __uint32_t stx_gid;
+  __uint16_t stx_mode;
+  __uint16_t __statx_pad1[1];
+  __uint64_t stx_ino;
+  __uint64_t stx_size;
+  __uint64_t stx_blocks;
+  __uint64_t stx_attributes_mask;
+  struct statx_timestamp stx_atime;
+  struct statx_timestamp stx_btime;
+  struct statx_timestamp stx_ctime;
+  struct statx_timestamp stx_mtime;
+  __uint32_t stx_rdev_major;
+  __uint32_t stx_rdev_minor;
+  __uint32_t stx_dev_major;
+  __uint32_t stx_dev_minor;
+  __uint64_t __statx_pad2[14];
+};
+
+#define STATX_TYPE 0x0001U
+#define STATX_MODE 0x0002U
+#define STATX_NLINK 0x0004U
+#define STATX_UID 0x0008U
+#define STATX_GID 0x0010U
+#define STATX_ATIME 0x0020U
+#define STATX_MTIME 0x0040U
+#define STATX_CTIME 0x0080U
+#define STATX_INO 0x0100U
+#define STATX_SIZE 0x0200U
+#define STATX_BLOCKS 0x0400U
+#define STATX_BASIC_STATS 0x07ffU
+#define STATX_ALL 0x0fffU
+#define STATX_BTIME 0x0800U
+#define STATX__RESERVED 0x80000000U
+
+#define STATX_ATTR_COMPRESSED 0x0004
+#define STATX_ATTR_IMMUTABLE 0x0010
+#define STATX_ATTR_APPEND 0x0020
+#define STATX_ATTR_NODUMP 0x0040
+#define STATX_ATTR_ENCRYPTED 0x0800
+#define STATX_ATTR_AUTOMOUNT 0x1000
+
+__BEGIN_DECLS
+
+/* Fill *BUF with information about PATH in DIRFD.  */
+int statx (int __dirfd, const char *__restrict __path, int __flags,
+           unsigned int __mask, struct statx *__restrict __buf)
+  __THROW __nonnull ((2, 5));
+
+__END_DECLS
diff --git a/io/fcntl.h b/io/fcntl.h
index 3afc62011a..6b0e9fa1fa 100644
--- a/io/fcntl.h
+++ b/io/fcntl.h
@@ -157,6 +157,10 @@  typedef __pid_t pid_t;
 #  define AT_NO_AUTOMOUNT	0x800	/* Suppress terminal automount
 					   traversal.  */
 #  define AT_EMPTY_PATH		0x1000	/* Allow empty relative pathname.  */
+#  define AT_STATX_SYNC_TYPE	0x6000
+#  define AT_STATX_SYNC_AS_STAT	0x0000
+#  define AT_STATX_FORCE_SYNC	0x2000
+#  define AT_STATX_DONT_SYNC	0x4000
 # endif
 # define AT_EACCESS		0x200	/* Test access permitted for
 					   effective IDs, not real IDs.  */
diff --git a/io/statx.c b/io/statx.c
new file mode 100644
index 0000000000..0b90cd00d1
--- /dev/null
+++ b/io/statx.c
@@ -0,0 +1,29 @@ 
+/* Generic statx implementation.
+   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 <errno.h>
+#include <sys/stat.h>
+
+#include "statx_generic.c"
+
+int
+statx (int fd, const char *path, int flags,
+       unsigned int mask, struct statx *buf)
+{
+  return statx_generic (fd, path, flags, mask, buf);
+}
diff --git a/io/statx_generic.c b/io/statx_generic.c
new file mode 100644
index 0000000000..df327f8c52
--- /dev/null
+++ b/io/statx_generic.c
@@ -0,0 +1,81 @@ 
+/* Generic implementation of statx based on fstatat64.
+   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 <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+
+static inline struct statx_timestamp
+statx_convert_timestamp (struct timespec tv)
+{
+  return (struct statx_timestamp) { tv.tv_sec, tv.tv_nsec };
+}
+
+/* Approximate emulation of statx.  This will always fill in
+   POSIX-mandated attributes even if the underlying file system does
+   not actually support it (for example, GID and UID on file systems
+   without UNIX-style permissions).  */
+static __attribute__ ((unused)) int
+statx_generic (int fd, const char *path, int flags,
+               unsigned int mask, struct statx *buf)
+{
+  /* Flags which need to be cleared before passing them to
+     fstatat64.  */
+  static const int clear_flags = AT_STATX_SYNC_AS_STAT;
+
+    /* Flags supported by our emulation.  */
+  static const int supported_flags
+    = AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW | clear_flags;
+
+  if (__glibc_unlikely ((flags & ~supported_flags) != 0))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  struct stat64 st;
+  int ret = __fstatat64 (fd, path, &st, flags & ~clear_flags);
+  if (ret != 0)
+    return ret;
+
+  /* The interface is defined in such a way that unused (padding)
+     fields have to be cleared.  STATX_BASIC_STATS corresponds to the
+     data which is available via fstatat64.  */
+  *buf = (struct statx)
+    {
+      .stx_mask = STATX_BASIC_STATS,
+      .stx_blksize = st.st_blksize,
+      .stx_nlink = st.st_nlink,
+      .stx_uid = st.st_uid,
+      .stx_gid = st.st_gid,
+      .stx_mode = st.st_mode,
+      .stx_ino = st.st_ino,
+      .stx_size = st.st_size,
+      .stx_blocks = st.st_blocks,
+      .stx_atime = statx_convert_timestamp (st.st_atim),
+      .stx_ctime = statx_convert_timestamp (st.st_ctim),
+      .stx_mtime = statx_convert_timestamp (st.st_mtim),
+      .stx_rdev_major = major (st.st_rdev),
+      .stx_rdev_minor = minor (st.st_rdev),
+      .stx_dev_major = major (st.st_dev),
+      .stx_dev_minor = minor (st.st_dev),
+    };
+
+  return 0;
+}
diff --git a/io/sys/stat.h b/io/sys/stat.h
index 90c403cfd6..762c8538ba 100644
--- a/io/sys/stat.h
+++ b/io/sys/stat.h
@@ -442,6 +442,10 @@  extern int __xmknodat (int __ver, int __fd, const char *__path,
 		       __mode_t __mode, __dev_t *__dev)
      __THROW __nonnull ((3, 5));
 
+#ifdef __USE_GNU
+# include <bits/statx.h>
+#endif
+
 #ifdef __USE_EXTERN_INLINES
 /* Inlined versions of the real stat and mknod functions.  */
 
diff --git a/io/tst-statx.c b/io/tst-statx.c
new file mode 100644
index 0000000000..61bf31d177
--- /dev/null
+++ b/io/tst-statx.c
@@ -0,0 +1,157 @@ 
+/* Basic test of statx system call.
+   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 <errno.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/xunistd.h>
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/sysmacros.h>
+#include <unistd.h>
+
+/* Ensure that the types have the kernel-expected layout.  */
+_Static_assert (sizeof (struct statx_timestamp) == 16, "statx_timestamp size");
+_Static_assert (sizeof (struct statx) == 256, "statx size");
+_Static_assert (offsetof (struct statx, stx_nlink) == 16, "statx nlink");
+_Static_assert (offsetof (struct statx, stx_ino) == 32, "statx ino");
+_Static_assert (offsetof (struct statx, stx_atime) == 64, "statx atime");
+_Static_assert (offsetof (struct statx, stx_rdev_major) == 128, "statx rdev");
+_Static_assert (offsetof (struct statx, __statx_pad2) == 144, "statx pad2");
+
+#include "statx_generic.c"
+
+typedef int (*statx_function) (int, const char *, int, unsigned int,
+                               struct statx *);
+
+/* Return true if we have a real implementation of statx.  */
+static bool
+kernel_supports_statx (void)
+{
+#ifdef __NR_statx
+  struct statx buf;
+  return syscall (__NR_statx, 0, "", AT_EMPTY_PATH, 0, &buf) == 0
+    || errno != ENOSYS;
+#else
+  return false;
+#endif
+}
+
+/* Tests which apply to both implementations.  */
+static void
+both_implementations_tests (statx_function impl, const char *path, int fd)
+{
+  uint64_t ino;
+  {
+    struct statx buf = { 0, };
+    TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &buf), 0);
+    TEST_COMPARE (buf.stx_size, 3);
+    ino = buf.stx_ino;
+  }
+  {
+    struct statx buf = { 0, };
+    TEST_COMPARE (statx (AT_FDCWD, path, 0, STATX_BASIC_STATS, &buf), 0);
+    TEST_COMPARE (buf.stx_size, 3);
+    TEST_COMPARE (buf.stx_ino, ino);
+  }
+  {
+    struct statx stx = { 0, };
+    TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS, &stx), 0);
+    struct stat64 st;
+    xfstat (fd, &st);
+    TEST_COMPARE (stx.stx_mode, st.st_mode);
+    TEST_COMPARE (stx.stx_dev_major, major (st.st_dev));
+    TEST_COMPARE (stx.stx_dev_minor, minor (st.st_dev));
+  }
+  {
+    struct statx stx = { 0, };
+    TEST_COMPARE (statx (AT_FDCWD, "/dev/null", 0, STATX_BASIC_STATS, &stx),
+                  0);
+    struct stat64 st;
+    xstat ("/dev/null", &st);
+    TEST_COMPARE (stx.stx_mode, st.st_mode);
+    TEST_COMPARE (stx.stx_dev_major, major (st.st_dev));
+    TEST_COMPARE (stx.stx_dev_minor, minor (st.st_dev));
+    TEST_COMPARE (stx.stx_rdev_major, major (st.st_rdev));
+    TEST_COMPARE (stx.stx_rdev_minor, minor (st.st_rdev));
+  }
+}
+
+/* Tests which apply only to the non-kernel (generic)
+   implementation.  */
+static void
+non_kernel_tests (statx_function impl, int fd)
+{
+  /* The non-kernel implementation must always fail for explicit sync
+     flags.  */
+  struct statx buf;
+  errno = 0;
+  TEST_COMPARE (impl (fd, "", AT_EMPTY_PATH | AT_STATX_FORCE_SYNC,
+                      STATX_BASIC_STATS, &buf), -1);
+  TEST_COMPARE (errno, EINVAL);
+  errno = 0;
+  TEST_COMPARE (impl (fd, "", AT_EMPTY_PATH | AT_STATX_DONT_SYNC,
+                      STATX_BASIC_STATS, &buf), -1);
+  TEST_COMPARE (errno, EINVAL);
+}
+
+static int
+do_test (void)
+{
+  char *path;
+  int fd = create_temp_file ("tst-statx-", &path);
+  TEST_VERIFY_EXIT (fd >= 0);
+  support_write_file_string (path, "abc");
+
+  both_implementations_tests (&statx, path, fd);
+  both_implementations_tests (&statx_generic, path, fd);
+
+  if (kernel_supports_statx ())
+    {
+      puts ("info: kernel supports statx");
+      struct statx buf;
+      buf.stx_size = 0;
+      TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH | AT_STATX_FORCE_SYNC,
+                           STATX_BASIC_STATS, &buf),
+                    0);
+      TEST_COMPARE (buf.stx_size, 3);
+      buf.stx_size = 0;
+      TEST_COMPARE (statx (fd, "", AT_EMPTY_PATH | AT_STATX_DONT_SYNC,
+                           STATX_BASIC_STATS, &buf),
+                    0);
+      TEST_COMPARE (buf.stx_size, 3);
+    }
+  else
+    {
+      puts ("info: kernel does not support statx");
+      non_kernel_tests (&statx, fd);
+    }
+  non_kernel_tests (&statx_generic, fd);
+
+  xclose (fd);
+  free (path);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/manual/filesys.texi b/manual/filesys.texi
index db2f1041de..ccda36cf84 100644
--- a/manual/filesys.texi
+++ b/manual/filesys.texi
@@ -3545,6 +3545,7 @@  The @code{mkdtemp} function comes from OpenBSD.
 @c fchownat
 @c futimesat
 @c fstatat (there's a commented-out safety assessment for this one)
+@c statx
 @c mkdirat
 @c mkfifoat
 @c name_to_handle_at
diff --git a/sysdeps/mach/hurd/i386/libc.abilist b/sysdeps/mach/hurd/i386/libc.abilist
index a9089d9064..9a3aac7a92 100644
--- a/sysdeps/mach/hurd/i386/libc.abilist
+++ b/sysdeps/mach/hurd/i386/libc.abilist
@@ -2035,6 +2035,7 @@  GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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/aarch64/libc.abilist b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
index 7a272a19bb..e92cd0ab9e 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libc.abilist
@@ -2133,3 +2133,4 @@  GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx F
diff --git a/sysdeps/unix/sysv/linux/alpha/kernel-features.h b/sysdeps/unix/sysv/linux/alpha/kernel-features.h
index 5781cffd5a..f63be39d1b 100644
--- a/sysdeps/unix/sysv/linux/alpha/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/alpha/kernel-features.h
@@ -45,4 +45,9 @@ 
 # undef __ASSUME_EXECVEAT
 #endif
 
+/* Support for statx was added in kernel 4.13.  */
+#if __LINUX_KERNEL_VERSION < 0x040D00
+# undef __ASSUME_STATX
+#endif
+
 #endif /* _KERNEL_FEATURES_H */
diff --git a/sysdeps/unix/sysv/linux/alpha/libc.abilist b/sysdeps/unix/sysv/linux/alpha/libc.abilist
index 23fec55d97..ba9473940a 100644
--- a/sysdeps/unix/sysv/linux/alpha/libc.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libc.abilist
@@ -2028,6 +2028,7 @@  GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 b203160889..dc71f1bb7f 100644
--- a/sysdeps/unix/sysv/linux/arm/libc.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libc.abilist
@@ -118,6 +118,7 @@  GLIBC_2.27 wcstof64_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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/hppa/libc.abilist b/sysdeps/unix/sysv/linux/hppa/libc.abilist
index 64809ca403..6a34090733 100644
--- a/sysdeps/unix/sysv/linux/hppa/libc.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libc.abilist
@@ -1875,6 +1875,7 @@  GLIBC_2.27 wcstof64_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 4a87f62ad9..30f8ddc682 100644
--- a/sysdeps/unix/sysv/linux/i386/libc.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libc.abilist
@@ -2040,6 +2040,7 @@  GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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/kernel-features.h b/sysdeps/unix/sysv/linux/ia64/kernel-features.h
index 04cdf43511..4fde73fba1 100644
--- a/sysdeps/unix/sysv/linux/ia64/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/ia64/kernel-features.h
@@ -26,6 +26,9 @@ 
 #define __ASSUME_SEND_SYSCALL		1
 #define __ASSUME_ACCEPT4_SYSCALL	1
 
+/* No statx system call on ia64 yet.  */
+#undef __ASSUME_STATX
+
 #undef __ASSUME_CLONE_DEFAULT
 #define __ASSUME_CLONE2
 
diff --git a/sysdeps/unix/sysv/linux/ia64/libc.abilist b/sysdeps/unix/sysv/linux/ia64/libc.abilist
index 6bdd0d0443..8f7aaff388 100644
--- a/sysdeps/unix/sysv/linux/ia64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libc.abilist
@@ -1909,6 +1909,7 @@  GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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/kernel-features.h b/sysdeps/unix/sysv/linux/kernel-features.h
index 86fc66574b..5543d92d7e 100644
--- a/sysdeps/unix/sysv/linux/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/kernel-features.h
@@ -115,6 +115,11 @@ 
 # define __ASSUME_COPY_FILE_RANGE 1
 #endif
 
+/* Support for statx was added in kernel 4.11.  */
+#if __LINUX_KERNEL_VERSION >= 0x040B00
+# define __ASSUME_STATX 1
+#endif
+
 /* Support for clone call used on fork.  The signature varies across the
    architectures with current 4 different variants:
 
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
index 3226f916eb..1b057ec6a6 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libc.abilist
@@ -119,6 +119,7 @@  GLIBC_2.27 wcstof64_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 b1074eeed1..70232f2d16 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libc.abilist
@@ -1984,6 +1984,7 @@  GLIBC_2.27 wcstof64_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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/kernel-features.h b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h
index 7db3d05636..e8e2ac6a87 100644
--- a/sysdeps/unix/sysv/linux/microblaze/kernel-features.h
+++ b/sysdeps/unix/sysv/linux/microblaze/kernel-features.h
@@ -63,5 +63,10 @@ 
 # undef __ASSUME_COPY_FILE_RANGE
 #endif
 
+/* Support for statx was added in kernel 4.12.  */
+#if __LINUX_KERNEL_VERSION < 0X040C00
+# undef __ASSUME_STATX
+#endif
+
 #undef __ASSUME_CLONE_DEFAULT
 #define __ASSUME_CLONE_BACKWARDS3
diff --git a/sysdeps/unix/sysv/linux/microblaze/libc.abilist b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
index b52fc7d6f7..6f295789c6 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libc.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libc.abilist
@@ -2125,3 +2125,4 @@  GLIBC_2.27 wcstof64_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
index 718c74262a..88f79b7d9d 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/fpu/libc.abilist
@@ -1962,6 +1962,7 @@  GLIBC_2.27 wcstof64_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 9b218a9435..563b3101b7 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/nofpu/libc.abilist
@@ -1960,6 +1960,7 @@  GLIBC_2.27 wcstof64_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 5a90ab83e7..5cdf8c2232 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n32/libc.abilist
@@ -1968,6 +1968,7 @@  GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 3005fc9500..ce27832705 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/libc.abilist
@@ -1963,6 +1963,7 @@  GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 a87fbbeb6b..78cc9cfff3 100644
--- a/sysdeps/unix/sysv/linux/nios2/libc.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libc.abilist
@@ -2166,3 +2166,4 @@  GLIBC_2.27 wcstof64_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
index d56f776a52..9ae40a9470 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libc.abilist
@@ -1988,6 +1988,7 @@  GLIBC_2.27 wcstof64_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 2b5337aab6..863f85b430 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libc.abilist
@@ -1992,6 +1992,7 @@  GLIBC_2.27 wcstof64_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 d0dfde3897..4cc5a4473b 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc-le.abilist
@@ -2223,3 +2223,4 @@  GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
index d505ae0e7d..a3cd3229c9 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libc.abilist
@@ -118,6 +118,7 @@  GLIBC_2.27 wcstof64 F
 GLIBC_2.27 wcstof64_l F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 33f751abc0..f094b0f3cd 100644
--- a/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/riscv/rv64/libc.abilist
@@ -2095,3 +2095,4 @@  GLIBC_2.27 xprt_register F
 GLIBC_2.27 xprt_unregister F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
index c4ec93ff43..26a95e6fda 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libc.abilist
@@ -1997,6 +1997,7 @@  GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 2a6a0abde8..650385b607 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libc.abilist
@@ -1902,6 +1902,7 @@  GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 8de0d1711a..cd349ccec1 100644
--- a/sysdeps/unix/sysv/linux/sh/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libc.abilist
@@ -1879,6 +1879,7 @@  GLIBC_2.27 wcstof64_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 9858460c9f..e0438402b3 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libc.abilist
@@ -1991,6 +1991,7 @@  GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 a22b8fb7ca..9f036ddf4b 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libc.abilist
@@ -1932,6 +1932,7 @@  GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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/statx.c b/sysdeps/unix/sysv/linux/statx.c
new file mode 100644
index 0000000000..76761d6ef2
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/statx.c
@@ -0,0 +1,41 @@ 
+/* Linux statx implementation.
+   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 <errno.h>
+#include <sys/stat.h>
+
+#include "statx_generic.c"
+
+int
+statx (int fd, const char *path, int flags,
+       unsigned int mask, struct statx *buf)
+{
+#ifdef __NR_statx
+  int ret = INLINE_SYSCALL_CALL (statx, fd, path, flags, mask, buf);
+# ifdef __ASSUME_STATX
+  return ret;
+# else
+  if (ret == 0 || errno != ENOSYS)
+    /* Preserve non-error/non-ENOSYS return values.  */
+    return ret;
+# endif
+#endif
+#ifndef __ASSUME_STATX
+  return statx_generic (fd, path, flags, mask, buf);
+#endif
+}
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
index d5d71cccba..2df20ebafd 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libc.abilist
@@ -1890,6 +1890,7 @@  GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx 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 e6ad42440e..83e15f84fc 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libc.abilist
@@ -2141,3 +2141,4 @@  GLIBC_2.27 wcstof64x F
 GLIBC_2.27 wcstof64x_l F
 GLIBC_2.28 fcntl64 F
 GLIBC_2.28 renameat2 F
+GLIBC_2.28 statx F