[v5,00/14] port C-SKY to glibc

Message ID 20181121080856.GA4266@vmh-VirtualBox
State New, archived
Headers

Commit Message

毛晗 Nov. 21, 2018, 8:10 a.m. UTC
  On Mon, Nov 19, 2018 at 04:45:09PM +0000, Joseph Myers wrote:
> The correct thing to do there is to fix the GCC configure test so you 
> don't need --enable-initfini-array in build-many-glibcs.py.
> 
> As far as I can tell, in the current version of the gcc_AC_INITFINI_ARRAY 
> test, the only part that's an execution test is the ia64 case.  That is, 
> for every other target, the 'if test "x${build}" = "x${target}" && test 
> "x${build}" = "x${host}"' condition is bogus as the rest of the tests 
> would work just as well for cross compilation.  (In the ia64 case, the 
> fourth argument to AC_RUN_IFELSE - the action if cross compiling - is 
> already there.  So simply removing the requirement for build = host = 
> target should allow things to work for cross compiling as well as for 
> native except on ia64, and someone using ia64 could always fix that case 
> later to have better cross compilation defaults based on the target OS.)
> 
Thanks for suggestion. We will try if it works for C-SKY cross compilation.

> > Another issue is Linux kernel have remove stat64 family from default 
> > syscall set, and C-SKY dont' define __ARCH_WANT_STAT64. The generic
> > version seems can't work without stat64. So I added fxstat, fxstatat, 
> > lxstat, xstat implemented with statx for C-SKY.
> 
> I am supposing this is the preferred default for all future architectures 
> added to the Linux kernel - they won't have the stat64 syscalls because 
> the relevant functions are supposed to be implemented in userspace using 
> statx instead.
> 
> If so, the implementations in terms of statx do not belong in a csky 
> sysdeps directory.  Rather, all the 
> sysdeps/unix/sysv/linux/generic/wordsize-32/ implementations should gain 
> appropriate conditionals, so that if __NR_<whatever-old-syscall> is 
> defined they follow the existing logic, and if it's not defined they 
> follow the logic to use statx instead.
>

I'v modified patch 14/14 to a generic version with __NR3264_fstatat
conditionals (in the attachment). It is tested in the same environment
as patch V5 and got same result, but have't test fstat64 path yet.

> 
> >   - remove support for big endian
> 
> I'd expect an explicit error somewhere (either header #error of in the 
> preconfigure script) for an attempt to build for big endian.
>
I forget to remove big endian part while making patch v5, there was a #error
in bits/endian.h in patch v4. Thanks for reminding.
  

Comments

Joseph Myers Nov. 21, 2018, 5:01 p.m. UTC | #1
On Wed, 21 Nov 2018, Mao Han wrote:

> I'v modified patch 14/14 to a generic version with __NR3264_fstatat
> conditionals (in the attachment). It is tested in the same environment
> as patch V5 and got same result, but have't test fstat64 path yet.

Thanks, this is the sort of thing I'm looking for, but I'm concerned about 
the use of __NR3264_fstatat.  As I understand, that's an internal 
implementation detail of the asm-generic unistd.h; it shouldn't be 
considered something stable that will reliably be there in future kernel 
versions.  Rather, the stable interface from asm/unistd.h is the 
__NR_<syscall> macros for each <syscall> provided by the kernel.  So I 
think the #ifdef conditionals need to be on the actual syscalls used in 
each case (e.g. you'd condition on __NR_fstat64 when using fstat64 in the 
existing INLINE_SYSCALL use).  In statx_cp.c you'll need to find some stat 
syscall to condition on that's present on all existing architectures, as 
the aim is that no existing glibc architecture should get any code 
compiled from that file (which you could check using 
build-many-glibcs.py).

Also, it's a bad idea to duplicate the contents of 
sysdeps/unix/sysv/linux/fxstat64.c in 
sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat64.c - rather, keep the 
existing #include, and modify sysdeps/unix/sysv/linux/fxstat64.c 
appropriately to handle the statx case (which definitely requires using 
__NR_fstat64 in the #ifdef, since this file is used in cases not using the 
asm-generic syscall list at all).

You're using AT_NO_AUTOMOUNT in these statx calls - does that match what 
the old stat syscalls do on other architectures?  (I think the aim there 
should be to match the old stat syscalls, so if those don't automount for 
stat of an automount point, then using AT_NO_AUTOMOUNT is correct.)

The indentation in the changes to sysdeps/unix/sysv/linux/Makefile seems 
to be off.  In statx_cp.c you're breaking lines after operators, but they 
should be broken before operators (and have parentheses used in such cases 
to ensure the continuation line is properly indented automatically, see 
the GNU Coding Standards).
  
Arnd Bergmann Nov. 21, 2018, 5:27 p.m. UTC | #2
On Wed, Nov 21, 2018 at 6:01 PM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Wed, 21 Nov 2018, Mao Han wrote:
>
> > I'v modified patch 14/14 to a generic version with __NR3264_fstatat
> > conditionals (in the attachment). It is tested in the same environment
> > as patch V5 and got same result, but have't test fstat64 path yet.
>
> Thanks, this is the sort of thing I'm looking for, but I'm concerned about
> the use of __NR3264_fstatat.  As I understand, that's an internal
> implementation detail of the asm-generic unistd.h; it shouldn't be
> considered something stable that will reliably be there in future kernel
> versions.  Rather, the stable interface from asm/unistd.h is the
> __NR_<syscall> macros for each <syscall> provided by the kernel.  So I
> think the #ifdef conditionals need to be on the actual syscalls used in
> each case (e.g. you'd condition on __NR_fstat64 when using fstat64 in the
> existing INLINE_SYSCALL use).  In statx_cp.c you'll need to find some stat
> syscall to condition on that's present on all existing architectures, as
> the aim is that no existing glibc architecture should get any code
> compiled from that file (which you could check using
> build-many-glibcs.py).

Sorry, that was my mistake. __NR3264_fstatat and the related macros
will be gone in 4.20, I just haven't forwarded the patch to hide them
for csky and other statx() based architectures.

      Arnd
  

Patch

From 67d158a0f631744ae99666ab1cd86d44457e59c1 Mon Sep 17 00:00:00 2001
Message-Id: <67d158a0f631744ae99666ab1cd86d44457e59c1.1542765182.git.han_mao@c-sky.com>
From: Mao Han <han_mao@c-sky.com>
Date: Wed, 21 Nov 2018 09:14:26 +0800
Subject: [PATCH 1/1] Add statx conditionals for wordsize-32 *xstat.c

Linux kernel have remove stat64 family from default syscall set, new
implementations with statx is needed when __ARCH_WANT_STAT64 is not
define. This patch add conditionals for relevant functions, using statx
system call to get information and then copy to the return buf, ref to
include/linux/fs.h from linux kernel.

	* sysdeps/unix/sysv/linux/Makefile: Add  for statx_cp.c.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c: Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat64.c: Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c: Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat64.c: Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c: Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c: Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c: Likewise.
	* sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c: Likewise.
	* sysdeps/unix/sysv/linux/statx_cp.c: New file.
	* sysdeps/unix/sysv/linux/statx_cp.h: Likewise.
---
 sysdeps/unix/sysv/linux/Makefile                   |  3 +-
 .../unix/sysv/linux/generic/wordsize-32/fxstat.c   | 11 ++++
 .../unix/sysv/linux/generic/wordsize-32/fxstat64.c | 47 ++++++++++++-
 .../unix/sysv/linux/generic/wordsize-32/fxstatat.c | 11 ++++
 .../sysv/linux/generic/wordsize-32/fxstatat64.c    | 42 +++++++++++-
 .../unix/sysv/linux/generic/wordsize-32/lxstat.c   | 11 ++++
 .../unix/sysv/linux/generic/wordsize-32/lxstat64.c | 19 +++++-
 .../unix/sysv/linux/generic/wordsize-32/xstat.c    | 10 +++
 .../unix/sysv/linux/generic/wordsize-32/xstat64.c  | 14 +++-
 sysdeps/unix/sysv/linux/statx_cp.c                 | 77 ++++++++++++++++++++++
 sysdeps/unix/sysv/linux/statx_cp.h                 | 23 +++++++
 11 files changed, 262 insertions(+), 6 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/statx_cp.c
 create mode 100644 sysdeps/unix/sysv/linux/statx_cp.h

diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index 72b6b64..7f817e0 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -177,7 +177,8 @@  sysdep_routines += xstatconv internal_statvfs internal_statvfs64 \
 		   close_nocancel fcntl_nocancel nanosleep_nocancel \
 		   open_nocancel open64_nocancel \
 		   openat_nocancel openat64_nocancel \
-		   pause_nocancel read_nocancel waitpid_nocancel write_nocancel
+		   pause_nocancel read_nocancel waitpid_nocancel \
+                   write_nocancel statx_cp
 
 sysdep_headers += bits/fcntl-linux.h
 
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c
index b5c766d..bb3eec2 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c
@@ -18,6 +18,7 @@ 
 
 #include <errno.h>
 #include <stddef.h>
+#include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <kernel_stat.h>
@@ -27,6 +28,7 @@ 
 
 #if !XSTAT_IS_XSTAT64
 #include "overflow.h"
+#include "statx_cp.h"
 
 /* Get information about the file FD in BUF.  */
 int
@@ -34,8 +36,17 @@  __fxstat (int vers, int fd, struct stat *buf)
 {
   if (vers == _STAT_VER_KERNEL)
     {
+# ifdef __NR3264_fstatat
       int rc = INLINE_SYSCALL (fstat64, 2, fd, buf);
       return rc ?: stat_overflow (buf);
+# else
+      struct statx tmp;
+      int rc = INLINE_SYSCALL (statx, 5, fd, "", AT_EMPTY_PATH,
+                               STATX_BASIC_STATS, &tmp);
+      if (rc == 0)
+        __cp_stat_statx (buf, &tmp);
+      return rc;
+# endif
     }
 
   errno = EINVAL;
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat64.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat64.c
index c558388..e94e652 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat64.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat64.c
@@ -25,7 +25,52 @@ 
 #define __fxstat __fxstat_disable
 #define _fxstat _fxstat_disable
 
-#include <sysdeps/unix/sysv/linux/fxstat64.c>
+#include <errno.h>
+#include <stddef.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <kernel_stat.h>
+
+#include <sysdep.h>
+#include <sys/syscall.h>
+
+#include <kernel-features.h>
+
+#include "statx_cp.h"
+
+/* Get information about the file FD in BUF.  */
+
+int
+___fxstat64 (int vers, int fd, struct stat64 *buf)
+{
+  int result;
+#ifdef __NR3264_fstatat
+  result = INLINE_SYSCALL (fstat64, 2, fd, buf);
+#else
+  struct statx tmp;
+  result = INLINE_SYSCALL (statx, 5, fd, "", AT_EMPTY_PATH, STATX_BASIC_STATS,
+                           &tmp);
+  if (result == 0)
+  __cp_stat64_statx (buf, &tmp);
+#endif
+#if defined _HAVE_STAT64___ST_INO && !__ASSUME_ST_INO_64_BIT
+  if (__builtin_expect (!result, 1) && buf->__st_ino != (__ino_t) buf->st_ino)
+    buf->st_ino = buf->__st_ino;
+#endif
+  return result;
+}
+
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
+versioned_symbol (libc, ___fxstat64, __fxstat64, GLIBC_2_2);
+strong_alias (___fxstat64, __old__fxstat64)
+compat_symbol (libc, __old__fxstat64, __fxstat64, GLIBC_2_1);
+hidden_ver (___fxstat64, __fxstat64)
+#else
+strong_alias (___fxstat64, __fxstat64)
+hidden_def (__fxstat64)
+#endif
 
 #undef __fxstat
 #undef _fxstat
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c
index 0bda8f7..3c031c5 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c
@@ -28,6 +28,7 @@ 
 
 #if !XSTAT_IS_XSTAT64
 #include "overflow.h"
+#include "statx_cp.h"
 
 /* Get information about the file NAME in BUF.  */
 int
@@ -35,8 +36,18 @@  __fxstatat (int vers, int fd, const char *file, struct stat *buf, int flag)
 {
   if (vers == _STAT_VER_KERNEL)
     {
+# ifdef __NR3264_fstatat
       int rc = INLINE_SYSCALL (fstatat64, 4, fd, file, buf, flag);
       return rc ?: stat_overflow (buf);
+# else
+      struct statx tmp;
+      int rc = INLINE_SYSCALL (statx, 5, fd, file,
+                               AT_NO_AUTOMOUNT | flag,
+                               STATX_BASIC_STATS, &tmp);
+      if (rc == 0)
+        __cp_stat_statx (buf, &tmp);
+      return rc;
+# endif
     }
 
   errno = EINVAL;
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat64.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat64.c
index 602bf4b..16ad3ad 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat64.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat64.c
@@ -28,7 +28,47 @@ 
 #undef _STAT_VER_LINUX
 #define _STAT_VER_LINUX _STAT_VER_KERNEL
 
-#include <sysdeps/unix/sysv/linux/fxstatat64.c>
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <kernel_stat.h>
+
+#include <sysdep.h>
+#include <sys/syscall.h>
+
+#include "statx_cp.h"
+
+/* Get information about the file NAME in BUF.  */
+
+int
+__fxstatat64 (int vers, int fd, const char *file, struct stat64 *st, int flag)
+{
+  if (__glibc_unlikely (vers != _STAT_VER_LINUX))
+    return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL);
+
+  int result;
+  INTERNAL_SYSCALL_DECL (err);
+
+#ifdef __NR3264_fstatat
+  result = INTERNAL_SYSCALL (fstatat64, err, 4, fd, file, st, flag);
+#else
+  struct statx tmp;
+
+  result = INTERNAL_SYSCALL (statx, err, 5, fd, file,
+                             AT_NO_AUTOMOUNT | flag,
+                             STATX_BASIC_STATS, &tmp);
+  if (result == 0)
+    __cp_stat64_statx (st, &tmp);
+#endif
+  if (!__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 1))
+    return 0;
+  else
+    return INLINE_SYSCALL_ERROR_RETURN_VALUE (INTERNAL_SYSCALL_ERRNO (result,
+                                                                      err));
+}
+libc_hidden_def (__fxstatat64)
 
 #undef __fxstatat
 #if XSTAT_IS_XSTAT64
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c
index c278a4d..f4eac25 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c
@@ -27,6 +27,7 @@ 
 
 #if !XSTAT_IS_XSTAT64
 #include "overflow.h"
+#include "statx_cp.h"
 
 /* Get information about the file NAME in BUF.  */
 int
@@ -34,9 +35,19 @@  __lxstat (int vers, const char *name, struct stat *buf)
 {
   if (vers == _STAT_VER_KERNEL)
     {
+#ifdef __NR3264_fstatat
       int rc = INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf,
                                AT_SYMLINK_NOFOLLOW);
       return rc ?: stat_overflow (buf);
+#else
+      struct statx tmp;
+      int rc = INLINE_SYSCALL (statx, 5, AT_FDCWD, name,
+                               AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW,
+                               STATX_BASIC_STATS, &tmp);
+      if (rc == 0)
+        __cp_stat_statx (buf, &tmp);
+      return rc;
+#endif
     }
   errno = EINVAL;
   return -1;
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c
index 761dd16..0d76d24 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c
@@ -32,13 +32,28 @@ 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
+#include "statx_cp.h"
+
 /* Get information about the file NAME in BUF.  */
 int
 __lxstat64 (int vers, const char *name, struct stat64 *buf)
 {
   if (vers == _STAT_VER_KERNEL)
-    return INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf,
-                           AT_SYMLINK_NOFOLLOW);
+    {
+#ifdef __NR3264_fstatat
+      return INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf,
+                             AT_SYMLINK_NOFOLLOW);
+#else
+      struct statx tmp;
+      int rc = INLINE_SYSCALL (statx, 5, AT_FDCWD, name,
+                               AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW,
+                               STATX_BASIC_STATS, &tmp);
+      if (rc == 0)
+        __cp_stat64_statx (buf, &tmp);
+      return rc;
+#endif
+    }
+
   errno = EINVAL;
   return -1;
 }
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c
index 1fd57ff..292a292 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c
@@ -27,6 +27,7 @@ 
 
 #if !XSTAT_IS_XSTAT64
 #include "overflow.h"
+#include "statx_cp.h"
 
 /* Get information about the file NAME in BUF.  */
 int
@@ -34,8 +35,17 @@  __xstat (int vers, const char *name, struct stat *buf)
 {
   if (vers == _STAT_VER_KERNEL)
     {
+# ifdef __NR3264_fstatat
       int rc = INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf, 0);
       return rc ?: stat_overflow (buf);
+# else
+      struct statx tmp;
+      int rc = INLINE_SYSCALL (statx, 5, AT_FDCWD, name, AT_NO_AUTOMOUNT,
+                               STATX_BASIC_STATS, &tmp);
+      if (rc == 0)
+        __cp_stat_statx (buf, &tmp);
+      return rc;
+# endif
     }
 
   errno = EINVAL;
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c
index ae70495..bd10402 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c
@@ -32,13 +32,25 @@ 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
+#include "statx_cp.h"
+
 /* Get information about the file NAME in BUF.  */
 int
 __xstat64 (int vers, const char *name, struct stat64 *buf)
 {
   if (vers == _STAT_VER_KERNEL)
+    {
+#ifdef __NR3264_fstatat
     return INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf, 0);
-
+#else
+      struct statx tmp;
+      int rc = INLINE_SYSCALL (statx, 5, AT_FDCWD, name, AT_NO_AUTOMOUNT,
+                               STATX_BASIC_STATS, &tmp);
+      if (rc == 0)
+        __cp_stat64_statx (buf, &tmp);
+      return rc;
+#endif
+    }
   errno = EINVAL;
   return -1;
 }
diff --git a/sysdeps/unix/sysv/linux/statx_cp.c b/sysdeps/unix/sysv/linux/statx_cp.c
new file mode 100644
index 0000000..f10bd74
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/statx_cp.c
@@ -0,0 +1,77 @@ 
+/* Struct statx to stat/stat64 conversion for Linux.
+   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 <stddef.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <kernel_stat.h>
+
+#include <sysdep.h>
+#include <sys/syscall.h>
+
+#if !defined(__NR3264_fstatat) && __WORDSIZE == 32
+void
+__cp_stat_statx (struct stat *to, struct statx *from)
+{
+  memset(to, 0, sizeof(struct stat));
+  to->st_dev = (from->stx_dev_minor & 0xff) | (from->stx_dev_major << 8) |
+               ((from->stx_dev_minor & ~0xff) << 12);
+  to->st_rdev = (from->stx_rdev_minor & 0xff) | (from->stx_rdev_major << 8) |
+               ((from->stx_rdev_minor & ~0xff) << 12);
+  to->st_ino = from->stx_ino;
+  to->st_mode = from->stx_mode;
+  to->st_nlink = from->stx_nlink;
+  to->st_uid = from->stx_uid;
+  to->st_gid = from->stx_gid;
+  to->st_atime = from->stx_atime.tv_sec;
+  to->st_atim.tv_nsec = from->stx_atime.tv_nsec;
+  to->st_mtime = from->stx_mtime.tv_sec;
+  to->st_mtim.tv_nsec = from->stx_mtime.tv_nsec;
+  to->st_ctime = from->stx_ctime.tv_sec;
+  to->st_ctim.tv_nsec = from->stx_ctime.tv_nsec;
+  to->st_size = from->stx_size;
+  to->st_blocks = from->stx_blocks;
+  to->st_blksize = from->stx_blksize;
+}
+
+void
+__cp_stat64_statx (struct stat64 *to, struct statx *from)
+{
+  memset(to, 0, sizeof(struct stat64));
+  to->st_dev = (from->stx_dev_minor & 0xff) | (from->stx_dev_major << 8) |
+               ((from->stx_dev_minor & ~0xff) << 12);
+  to->st_rdev = (from->stx_rdev_minor & 0xff) | (from->stx_rdev_major << 8) |
+               ((from->stx_rdev_minor & ~0xff) << 12);
+  to->st_ino = from->stx_ino;
+  to->st_mode = from->stx_mode;
+  to->st_nlink = from->stx_nlink;
+  to->st_uid = from->stx_uid;
+  to->st_gid = from->stx_gid;
+  to->st_atime = from->stx_atime.tv_sec;
+  to->st_atim.tv_nsec = from->stx_atime.tv_nsec;
+  to->st_mtime = from->stx_mtime.tv_sec;
+  to->st_mtim.tv_nsec = from->stx_mtime.tv_nsec;
+  to->st_ctime = from->stx_ctime.tv_sec;
+  to->st_ctim.tv_nsec = from->stx_ctime.tv_nsec;
+  to->st_size = from->stx_size;
+  to->st_blocks = from->stx_blocks;
+  to->st_blksize = from->stx_blksize;
+}
+#endif
diff --git a/sysdeps/unix/sysv/linux/statx_cp.h b/sysdeps/unix/sysv/linux/statx_cp.h
new file mode 100644
index 0000000..7e411a7
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/statx_cp.h
@@ -0,0 +1,23 @@ 
+/* Struct statx to stat/stat64 conversion for Linux.
+   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/>.  */
+
+extern void __cp_stat_statx (struct stat *to, struct statx *from)
+  attribute_hidden;
+
+extern void __cp_stat64_statx (struct stat64 *to, struct statx *from)
+  attribute_hidden;
-- 
2.7.4