[RFC2,RESEND,AARCH64] ILP32: support stat syscall family
diff mbox

Message ID 1467816908-15290-1-git-send-email-ynorov@caviumnetworks.com
State New
Headers show

Commit Message

Yury Norov July 6, 2016, 2:55 p.m. UTC
In modern APIs stat and statfs structures has their layouts identical
to 64-bit version after changing off_t, ino_t etc sizes to 64-bit.
It means we can pass it to kernel same way as lp64 API does.

Initial version of this patch did introduce full set of stat{,fs} headers
and function implementation under aarch64/ilp32 directory. It was rejected
by Joseph, and he requested to extend and re-use existing files where
possible.

In this patch:
 - __ASSUME_SUPPORT_64_BIT_TIME_TYPES macro introduced to indicate that 32-bit
   ABI has struct __timespec (and maybe __timeval in future) that is compatible
   to 64-bit kernel timespec;
 - conv_timespec() and stat_conv_timespecs() macros are introduced to convert
   __timespec to 32-bit timespec;
 - XSTAT_IS_XSTAT64 is reused in 32-bit code to hint GLIBC that structures  stat
   and statfs are identical to 64-bit versions, and 64-bit syscalls should be used
   for corresponding requesta.
 - 32-bit syscalls are redirected to 64-bit version.

After all, aarch63/ilp32 contains only 2 syscall filess - fstatfs() and statfs()
that we cannot redirect to generic ones because aarch64 kernel expects arguments
in different registers.

It was tested with LTP, and no regressions found.

The series that includes this patch:
https://github.com/norov/glibc/tree/ilp32-dev

v2:
 - STATFS_IS_STATFS64 removed. Both stat and statfs structures are controlled by
   XSTAT_IS_XSTAT64. I did it because they will doubtly differ with it.
 - fixed coding style numerous issues.
 - conv_timespec() moved to non-imported header. stat_conv_timespecs() is introduced.
 - I didn't move DECLARE_TIMESPEC() to non-installed file because it's used in stat.h,
   and should be known on used side. If it's wrong please hint me how to do this trick.

Signed-off-by: Yury Norov <ynorov@caviumnetworks.com>
---
 string/endian.h                                    | 13 +++++++
 sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h   |  6 ++++
 sysdeps/unix/sysv/linux/aarch64/ilp32/fstatfs64.c  | 36 +++++++++++++++++++
 sysdeps/unix/sysv/linux/aarch64/ilp32/statfs64.c   | 39 +++++++++++++++++++++
 sysdeps/unix/sysv/linux/fxstat64.c                 | 12 +++++++
 sysdeps/unix/sysv/linux/fxstatat64.c               | 15 +++++++-
 sysdeps/unix/sysv/linux/generic/bits/stat.h        | 35 +++++++++++++++----
 sysdeps/unix/sysv/linux/generic/bits/statfs.h      | 32 ++++++++++-------
 .../unix/sysv/linux/generic/wordsize-32/fstatfs.c  |  4 +++
 .../unix/sysv/linux/generic/wordsize-32/fxstat.c   |  3 ++
 .../unix/sysv/linux/generic/wordsize-32/fxstatat.c |  3 ++
 .../unix/sysv/linux/generic/wordsize-32/lxstat.c   |  3 ++
 .../unix/sysv/linux/generic/wordsize-32/lxstat64.c | 21 ++++++++++--
 .../unix/sysv/linux/generic/wordsize-32/statfs.c   |  3 ++
 .../unix/sysv/linux/generic/wordsize-32/xstat.c    |  3 ++
 .../unix/sysv/linux/generic/wordsize-32/xstat64.c  | 17 ++++++++-
 sysdeps/unix/sysv/linux/kernel-time.h              | 40 ++++++++++++++++++++++
 time/time.h                                        | 30 +++++++++++++++-
 18 files changed, 290 insertions(+), 25 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/aarch64/ilp32/fstatfs64.c
 create mode 100644 sysdeps/unix/sysv/linux/aarch64/ilp32/statfs64.c
 create mode 100644 sysdeps/unix/sysv/linux/kernel-time.h

Comments

Andreas Schwab July 6, 2016, 3:32 p.m. UTC | #1
Yury Norov <ynorov@caviumnetworks.com> writes:

> diff --git a/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h b/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h
> index 39c0c81..be6497f 100644
> --- a/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h
> +++ b/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h
> @@ -62,6 +62,12 @@
>  #define __SYSCALL_ULONG_TYPE	__ULONGWORD_TYPE
>  #define __CPU_MASK_TYPE         __ULONGWORD_TYPE
>  
> +
> +#ifdef __ILP32__
> +# define __ASSUME_SUPPORT_64_BIT_TIME_TYPES
> +# define XSTAT_IS_XSTAT64
> +#endif

You still didn't take notice of the testsuite failures.

Andreas.
Joseph Myers July 20, 2016, 4:11 p.m. UTC | #2
On Wed, 6 Jul 2016, Yury Norov wrote:

>  - I didn't move DECLARE_TIMESPEC() to non-installed file because it's 
> used in stat.h,
>    and should be known on used side. If it's wrong please hint me how to 
>    do this trick.

First: why is it used in an installed header at all?  The public API uses 
struct timespec, not struct __timespec.  If you need to reinterpret the 
bits of struct timespec in some other way, because the kernel ABI is 
different from the userspace ABI, that is purely a matter for the relevant 
function implementations and should not affect the installed header.

Second: any interface in an installed header that does not start with 
_[_A-Z] is a public interface.  This means that (a) it must be permitted 
to appear in that header by the relevant standards, depending on the 
feature test macros in use, (b) we must have made a deliberate decision as 
a community that this is an interface that we wish to support for our 
users, indefinitely, (c) it must normally be documented and have testsuite 
coverage, and (d) it must be system-independent unless there is a definite 
reason for a system-specific interface.  So any macros, typedefs etc. in 
installed headers that do not meet all those requirements must be in the 
implementation namespace _[_A-Z]*.  This applies to all such macros added 
to installed headers by this patch.  That includes statfs_word_t; although 
POSIX reserves *_t, we should not have any such types in public headers, 
outside the _[_A-Z]* namespace, unless they are documented public 
interfaces meeting all of (a)-(d), so you should not use statfs_word_t as 
a type name.

> +/* Declare structure field that has different size
> +   in 32- and 64-bit ABIs with paddings where needed,
> +   so final layout becomes identical.  */
> +#if __WORDSIZE == 32
> +# if __BYTE_ORDER == __LITTLE_ENDIAN
> +#  define __type3264(type, name) type name; type name##_pad
> +# else
> +#  define __type3264(type, name) type name##_pad; type name
> +# endif

I don't think you want name##_pad; if name is a public interface, then 
this would make name##_pad a public interface as well, with all the 
corresponding requirements.  __##name##_pad would be better.  And why 
isn't this using alignment attributes as in 
sysdeps/unix/sysv/linux/generic/bits/stat.h?  I wonder if this needs to be 
separate from __field64 there or if there could be some common macro?
Yury Norov Aug. 4, 2016, 8:25 a.m. UTC | #3
On Wed, Jul 06, 2016 at 05:32:06PM +0200, Andreas Schwab wrote:
> Yury Norov <ynorov@caviumnetworks.com> writes:
> 
> > diff --git a/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h b/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h
> > index 39c0c81..be6497f 100644
> > --- a/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h
> > +++ b/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h
> > @@ -62,6 +62,12 @@
> >  #define __SYSCALL_ULONG_TYPE	__ULONGWORD_TYPE
> >  #define __CPU_MASK_TYPE         __ULONGWORD_TYPE
> >  
> > +
> > +#ifdef __ILP32__
> > +# define __ASSUME_SUPPORT_64_BIT_TIME_TYPES
> > +# define XSTAT_IS_XSTAT64
> > +#endif
> 
> You still didn't take notice of the testsuite failures.
> 
> Andreas.

Andreas, 

I cannot run testsuite right now. Could you describe the problem in
detiles?

Yury.
Andreas Schwab Aug. 4, 2016, 8:47 a.m. UTC | #4
On Do, Aug 04 2016, Yury Norov <ynorov@caviumnetworks.com> wrote:

> I cannot run testsuite right now.

Why not?

Andreas.
Yury Norov Aug. 4, 2016, 8:53 a.m. UTC | #5
On Thu, Aug 04, 2016 at 10:47:01AM +0200, Andreas Schwab wrote:
> On Do, Aug 04 2016, Yury Norov <ynorov@caviumnetworks.com> wrote:
> 
> > I cannot run testsuite right now.
> 
> Why not?
> 
> Andreas.

I cross-compile glibc, and run it under qemu. I just don't know how to
run testsuite in this case. If you know, could you share the manual?
Andreas Schwab Aug. 4, 2016, 9:11 a.m. UTC | #6
On Do, Aug 04 2016, Yury Norov <ynorov@caviumnetworks.com> wrote:

> I cross-compile glibc, and run it under qemu. I just don't know how to
> run testsuite in this case. If you know, could you share the manual?

Have you tried "make check"?

Andreas.
Yury Norov Aug. 4, 2016, 9:25 a.m. UTC | #7
On Thu, Aug 04, 2016 at 11:11:59AM +0200, Andreas Schwab wrote:
> On Do, Aug 04 2016, Yury Norov <ynorov@caviumnetworks.com> wrote:
> 
> > I cross-compile glibc, and run it under qemu. I just don't know how to
> > run testsuite in this case. If you know, could you share the manual?
> 
> Have you tried "make check"?
> 
> Andreas.

Doesn't work for me as I told. 

I have new patches for stat syscalls. So let's I send it to the list
without testsuite run, and while you and other people review it, I'll
fix testsuite failures. This is quite deep rework, so there will be
other comments except of this, for sure.

Yury

yury@yury-N73SV:~/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32$
make check
make -r PARALLELMFLAGS="" -C
/home/yury/work/toolchain/scripts/../glibc objdir=`pwd` check
make[1]: Entering directory '/home/yury/work/toolchain/gits/glibc'
make  subdir=csu -C csu ..=../ tests
make[2]: Entering directory '/home/yury/work/toolchain/gits/glibc/csu'
/home/yury/work/toolchain/scripts/../minimal-aarch64-thunderx-linux-gnu/bin/aarch64-thunderx-linux-gnu-gcc
-mabi=ilp32 -O2 -nostdlib -nostartfiles -o
/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/csu/tst-atomic
-Wl,-z,combreloc -Wl,-z,relro -Wl,--hash-style=both
/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/csu/crt1.o
/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/csu/crti.o
`/home/yury/work/toolchain/scripts/../minimal-aarch64-thunderx-linux-gnu/bin/aarch64-thunderx-linux-gnu-gcc
-mabi=ilp32 -O2  --print-file-name=crtbegin.o`
/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/csu/tst-atomic.o
-Wl,-dynamic-linker=/lib/ld-linux-aarch64_ilp32.so.1
-Wl,-rpath-link=/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32:/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/math:/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/elf:/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/dlfcn:/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/nss:/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/nis:/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/rt:/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/resolv:/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/crypt:/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/mathvec:/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/nptl
/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/libc.so.6
/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/libc_nonshared.a
-Wl,--as-needed
/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/elf/ld.so
-Wl,--no-as-needed -lgcc -Wl,--as-needed -lgcc_s  -Wl,--no-as-needed
`/home/yury/work/toolchain/scripts/../minimal-aarch64-thunderx-linux-gnu/bin/aarch64-thunderx-linux-gnu-gcc
-mabi=ilp32 -O2  --print-file-name=crtend.o`
/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/csu/crtn.o
/home/yury/work/toolchain/minimal-aarch64-thunderx-linux-gnu/bin/../lib/gcc/aarch64-thunderx-linux-gnu/5.2.0/../../../../aarch64-thunderx-linux-gnu/bin/ld:
cannot find -lgcc_s
collect2: error: ld returned 1 exit status
../Rules:154: recipe for target
'/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/csu/tst-atomic'
failed
make[2]: ***
[/home/yury/work/toolchain/build-glibc-aarch64-thunderx-linux-gnu-mabi-ilp32/csu/tst-atomic]
Error 1
make[2]: Leaving directory '/home/yury/work/toolchain/gits/glibc/csu'
Makefile:214: recipe for target 'csu/tests' failed
make[1]: *** [csu/tests] Error 2
make[1]: Leaving directory '/home/yury/work/toolchain/gits/glibc'
Makefile:9: recipe for target 'check' failed
make: *** [check] Error 2
Andreas Schwab Aug. 4, 2016, 9:31 a.m. UTC | #8
On Do, Aug 04 2016, Yury Norov <ynorov@caviumnetworks.com> wrote:

> /home/yury/work/toolchain/minimal-aarch64-thunderx-linux-gnu/bin/../lib/gcc/aarch64-thunderx-linux-gnu/5.2.0/../../../../aarch64-thunderx-linux-gnu/bin/ld:
> cannot find -lgcc_s

You need to fix your cross compiler.

Andreas.
Joseph Myers Aug. 4, 2016, 12:27 p.m. UTC | #9
On Thu, 4 Aug 2016, Yury Norov wrote:

> I cross-compile glibc, and run it under qemu. I just don't know how to
> run testsuite in this case. If you know, could you share the manual?

install.texi explains the use of cross-test-ssh.sh for testing over SSH.  
You can use the --ssh option if necessary to point to a wrapper that 
connects to whatever port your QEMU instance is listening for SSH 
connections on.

Patch
diff mbox

diff --git a/string/endian.h b/string/endian.h
index b13ddaa..f021f04 100644
--- a/string/endian.h
+++ b/string/endian.h
@@ -54,6 +54,19 @@ 
 # define __LONG_LONG_PAIR(HI, LO) HI, LO
 #endif
 
+/* Declare structure field that has different size
+   in 32- and 64-bit ABIs with paddings where needed,
+   so final layout becomes identical.  */
+#if __WORDSIZE == 32
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+#  define __type3264(type, name) type name; type name##_pad
+# else
+#  define __type3264(type, name) type name##_pad; type name
+# endif
+#else /* __WORDSIZE == 64.  */
+# define __type3264(type, name) type name
+#endif
+
 
 #if defined __USE_MISC && !defined __ASSEMBLER__
 /* Conversion interfaces.  */
diff --git a/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h b/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h
index 39c0c81..be6497f 100644
--- a/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h
+++ b/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h
@@ -62,6 +62,12 @@ 
 #define __SYSCALL_ULONG_TYPE	__ULONGWORD_TYPE
 #define __CPU_MASK_TYPE         __ULONGWORD_TYPE
 
+
+#ifdef __ILP32__
+# define __ASSUME_SUPPORT_64_BIT_TIME_TYPES
+# define XSTAT_IS_XSTAT64
+#endif
+
 /* Tell the libc code that off_t and off64_t are actually the same type
    for all ABI purposes, even if possibly expressed as different base types
    for C type-checking purposes.  */
diff --git a/sysdeps/unix/sysv/linux/aarch64/ilp32/fstatfs64.c b/sysdeps/unix/sysv/linux/aarch64/ilp32/fstatfs64.c
new file mode 100644
index 0000000..174d3a9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/aarch64/ilp32/fstatfs64.c
@@ -0,0 +1,36 @@ 
+/* Return information about the filesystem on which FD resides.
+   Copyright (C) 1996-2016 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/>.  */
+#define __fstatfs __statfs_disable
+#define fstatfs statfs_disable
+
+#include <errno.h>
+#include <sys/statfs.h>
+#include <stddef.h>
+
+int
+__fstatfs64 (int fd, struct statfs64 *buf)
+{
+  return INLINE_SYSCALL (fstatfs64, 2, fd, buf);
+}
+
+#undef __fstatfs
+#undef fstatfs
+strong_alias (__fstatfs64, __fstatfs)
+weak_alias (__fstatfs64, fstatfs64)
+weak_alias (__fstatfs64, fstatfs)
+
diff --git a/sysdeps/unix/sysv/linux/aarch64/ilp32/statfs64.c b/sysdeps/unix/sysv/linux/aarch64/ilp32/statfs64.c
new file mode 100644
index 0000000..6c7d1b9
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/aarch64/ilp32/statfs64.c
@@ -0,0 +1,39 @@ 
+/* Return information about the filesystem on which FILE resides.
+
+   Copyright (C) 2011-2015 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
+
+   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/>.  */
+#define __statfs __statfs_disable
+#define statfs statfs_disable
+
+#include <errno.h>
+#include <sys/statfs.h>
+#include <stddef.h>
+
+int
+__statfs64 (const char *file, struct statfs64 *buf)
+{
+  return INLINE_SYSCALL (statfs64, 2, file, buf);
+}
+
+#undef __statfs
+#undef statfs
+weak_alias (__statfs64, statfs64)
+strong_alias (__statfs64, __statfs)
+libc_hidden_ver (__statfs64, __statfs)
+weak_alias (__statfs64, statfs)
+
diff --git a/sysdeps/unix/sysv/linux/fxstat64.c b/sysdeps/unix/sysv/linux/fxstat64.c
index 5468dd6..9690da6 100644
--- a/sysdeps/unix/sysv/linux/fxstat64.c
+++ b/sysdeps/unix/sysv/linux/fxstat64.c
@@ -15,6 +15,7 @@ 
    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/>.  */
+#define __fxstat __fxstat_disable
 
 #include <errno.h>
 #include <stddef.h>
@@ -25,6 +26,7 @@ 
 #include <sys/syscall.h>
 
 #include <kernel-features.h>
+#include <kernel-time.h>
 
 /* Get information about the file FD in BUF.  */
 
@@ -36,12 +38,16 @@  ___fxstat64 (int vers, int fd, struct stat64 *buf)
 #if defined _HAVE_STAT64___ST_INO && !defined __ASSUME_ST_INO_64_BIT
   if (__builtin_expect (!result, 1) && buf->__st_ino != (__ino_t) buf->st_ino)
     buf->st_ino = buf->__st_ino;
+  return result;
 #endif
+  if (!result)
+    stat_conv_timespecs (buf);
   return result;
 }
 
 #include <shlib-compat.h>
 
+#undef __fxstat
 #if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2)
 versioned_symbol (libc, ___fxstat64, __fxstat64, GLIBC_2_2);
 strong_alias (___fxstat64, __old__fxstat64)
@@ -51,3 +57,9 @@  hidden_ver (___fxstat64, __fxstat64)
 strong_alias (___fxstat64, __fxstat64)
 hidden_def (__fxstat64)
 #endif
+
+#ifdef XSTAT_IS_XSTAT64
+strong_alias (__fxstat64, __fxstat)
+libc_hidden_ver (__fxstat64, __fxstat)
+#endif
+
diff --git a/sysdeps/unix/sysv/linux/fxstatat64.c b/sysdeps/unix/sysv/linux/fxstatat64.c
index 7ffa2d4..f1d7488 100644
--- a/sysdeps/unix/sysv/linux/fxstatat64.c
+++ b/sysdeps/unix/sysv/linux/fxstatat64.c
@@ -14,6 +14,7 @@ 
    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/>.  */
+#define __fxstatat __fxstatat_disable
 
 #include <errno.h>
 #include <fcntl.h>
@@ -26,6 +27,8 @@ 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
+#include <kernel-time.h>
+
 /* Get information about the file NAME in BUF.  */
 
 int
@@ -39,9 +42,19 @@  __fxstatat64 (int vers, int fd, const char *file, struct stat64 *st, int flag)
 
   result = INTERNAL_SYSCALL (fstatat64, err, 4, fd, file, st, flag);
   if (!__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 1))
-    return 0;
+    {
+      stat_conv_timespecs (st);
+      return 0;
+    }
   else
     return INLINE_SYSCALL_ERROR_RETURN_VALUE (INTERNAL_SYSCALL_ERRNO (result,
 								      err));
 }
 libc_hidden_def (__fxstatat64)
+
+#undef __fxstatat
+#ifdef XSTAT_IS_XSTAT64
+strong_alias (__fxstatat64, __fxstatat)
+libc_hidden_ver (__fxstatat64, __fxstatat)
+#endif
+
diff --git a/sysdeps/unix/sysv/linux/generic/bits/stat.h b/sysdeps/unix/sysv/linux/generic/bits/stat.h
index dd8d799..4688ed6 100644
--- a/sysdeps/unix/sysv/linux/generic/bits/stat.h
+++ b/sysdeps/unix/sysv/linux/generic/bits/stat.h
@@ -42,7 +42,7 @@ 
 
 #if defined __USE_FILE_OFFSET64
 # define __field64(type, type64, name) type64 name
-#elif __WORDSIZE == 64
+#elif __WORDSIZE == 64 || defined (XSTAT_IS_XSTAT64)
 # define __field64(type, type64, name) type name
 #elif __BYTE_ORDER == __LITTLE_ENDIAN
 # define __field64(type, type64, name) \
@@ -73,19 +73,28 @@  struct stat
        identifier 'timespec' to appear in the <sys/stat.h> header.
        Therefore we have to handle the use of this header in strictly
        standard-compliant sources special.  */
-    struct timespec st_atim;		/* Time of last access.  */
-    struct timespec st_mtim;		/* Time of last modification.  */
-    struct timespec st_ctim;		/* Time of last status change.  */
+    DECLARE_TIMESPEC (st_atim);		/* Time of last access.  */
+    DECLARE_TIMESPEC (st_mtim);		/* Time of last modification.  */
+    DECLARE_TIMESPEC (st_ctim);		/* Time of last status change.  */
 # define st_atime st_atim.tv_sec	/* Backward compatibility.  */
 # define st_mtime st_mtim.tv_sec
 # define st_ctime st_ctim.tv_sec
 #else
+# if SUPPORT_64BIT_TIME_TYPES
+    __type3264 (__time_t, st_atime);			/* Time of last access.  */
+    __type3264 (unsigned long int, st_atimensec);	/* Nscecs of last access.  */
+    __type3264 (__time_t, st_mtime);			/* Time of last modification.  */
+    __type3264 (unsigned long int, st_mtimensec);	/* Nsecs of last modification.  */
+    __type3264 (__time_t, st_ctime);			/* Time of last status change.  */
+    __type3264 (unsigned long int, st_ctimensec);	/* Nsecs of last status change.  */
+# else
     __time_t st_atime;			/* Time of last access.  */
     unsigned long int st_atimensec;	/* Nscecs of last access.  */
     __time_t st_mtime;			/* Time of last modification.  */
     unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
     __time_t st_ctime;			/* Time of last status change.  */
     unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
+# endif
 #endif
     int __glibc_reserved[2];
   };
@@ -114,16 +123,28 @@  struct stat64
        identifier 'timespec' to appear in the <sys/stat.h> header.
        Therefore we have to handle the use of this header in strictly
        standard-compliant sources special.  */
-    struct timespec st_atim;		/* Time of last access.  */
-    struct timespec st_mtim;		/* Time of last modification.  */
-    struct timespec st_ctim;		/* Time of last status change.  */
+    DECLARE_TIMESPEC (st_atim);		/* Time of last access.  */
+    DECLARE_TIMESPEC (st_mtim);		/* Time of last modification.  */
+    DECLARE_TIMESPEC (st_ctim);		/* Time of last status change.  */
+# define st_atime st_atim.tv_sec	/* Backward compatibility.  */
+# define st_mtime st_mtim.tv_sec
+# define st_ctime st_ctim.tv_sec
 #else
+# if SUPPORT_64BIT_TIME_TYPES
+    __type3264 (__time_t, st_atime);			/* Time of last access.  */
+    __type3264 (unsigned long int, st_atimensec);	/* Nscecs of last access.  */
+    __type3264 (__time_t, st_mtime);			/* Time of last modification.  */
+    __type3264 (unsigned long int, st_mtimensec);	/* Nsecs of last modification.  */
+    __type3264 (__time_t, st_ctime);			/* Time of last status change.  */
+    __type3264 (unsigned long int, st_ctimensec);	/* Nsecs of last status change.  */
+# else
     __time_t st_atime;			/* Time of last access.  */
     unsigned long int st_atimensec;	/* Nscecs of last access.  */
     __time_t st_mtime;			/* Time of last modification.  */
     unsigned long int st_mtimensec;	/* Nsecs of last modification.  */
     __time_t st_ctime;			/* Time of last status change.  */
     unsigned long int st_ctimensec;	/* Nsecs of last status change.  */
+# endif
 #endif
     int __glibc_reserved[2];
   };
diff --git a/sysdeps/unix/sysv/linux/generic/bits/statfs.h b/sysdeps/unix/sysv/linux/generic/bits/statfs.h
index 7d5aa2d..581cf4f 100644
--- a/sysdeps/unix/sysv/linux/generic/bits/statfs.h
+++ b/sysdeps/unix/sysv/linux/generic/bits/statfs.h
@@ -34,7 +34,7 @@ 
 
 #if defined __USE_FILE_OFFSET64
 # define __field64(type, type64, name) type64 name
-#elif __WORDSIZE == 64
+#elif __WORDSIZE == 64 || defined (XSTAT_IS_XSTAT64)
 # define __field64(type, type64, name) type name
 #elif __BYTE_ORDER == __LITTLE_ENDIAN
 # define __field64(type, type64, name) \
@@ -44,20 +44,26 @@ 
   int __##name##_pad __attribute__((__aligned__ (__alignof__ (type64)))); type name
 #endif
 
+#ifdef XSTAT_IS_XSTAT64
+# define statfs_word_t long long
+#else
+# define statfs_word_t __SWORD_TYPE
+#endif
+
 struct statfs
   {
-    __SWORD_TYPE f_type;
-    __SWORD_TYPE f_bsize;
+    statfs_word_t f_type;
+    statfs_word_t f_bsize;
     __field64(__fsblkcnt_t, __fsblkcnt64_t, f_blocks);
     __field64(__fsblkcnt_t, __fsblkcnt64_t, f_bfree);
     __field64(__fsblkcnt_t, __fsblkcnt64_t, f_bavail);
     __field64(__fsfilcnt_t, __fsfilcnt64_t, f_files);
     __field64(__fsfilcnt_t, __fsfilcnt64_t, f_ffree);
     __fsid_t f_fsid;
-    __SWORD_TYPE f_namelen;
-    __SWORD_TYPE f_frsize;
-    __SWORD_TYPE f_flags;
-    __SWORD_TYPE f_spare[4];
+    statfs_word_t f_namelen;
+    statfs_word_t f_frsize;
+    statfs_word_t f_flags;
+    statfs_word_t f_spare[4];
   };
 
 #undef __field64
@@ -65,18 +71,18 @@  struct statfs
 #ifdef __USE_LARGEFILE64
 struct statfs64
   {
-    __SWORD_TYPE f_type;
-    __SWORD_TYPE f_bsize;
+    statfs_word_t f_type;
+    statfs_word_t f_bsize;
     __fsblkcnt64_t f_blocks;
     __fsblkcnt64_t f_bfree;
     __fsblkcnt64_t f_bavail;
     __fsfilcnt64_t f_files;
     __fsfilcnt64_t f_ffree;
     __fsid_t f_fsid;
-    __SWORD_TYPE f_namelen;
-    __SWORD_TYPE f_frsize;
-    __SWORD_TYPE f_flags;
-    __SWORD_TYPE f_spare[4];
+    statfs_word_t f_namelen;
+    statfs_word_t f_frsize;
+    statfs_word_t f_flags;
+    statfs_word_t f_spare[4];
   };
 #endif
 
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/fstatfs.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/fstatfs.c
index be9599a..e95800d 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/fstatfs.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/fstatfs.c
@@ -20,6 +20,8 @@ 
 #include <sys/statfs.h>
 #include <stddef.h>
 
+#ifndef XSTAT_IS_XSTAT64
+
 #include "overflow.h"
 
 /* Return information about the filesystem on which FD resides.  */
@@ -30,3 +32,5 @@  __fstatfs (int fd, struct statfs *buf)
   return rc ?: statfs_overflow (buf);
 }
 weak_alias (__fstatfs, fstatfs)
+#endif
+
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c
index dd52011..b246f5d 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstat.c
@@ -25,6 +25,7 @@ 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
+#ifndef XSTAT_IS_XSTAT64
 #include "overflow.h"
 
 /* Get information about the file FD in BUF.  */
@@ -43,3 +44,5 @@  __fxstat (int vers, int fd, struct stat *buf)
 
 hidden_def (__fxstat)
 weak_alias (__fxstat, _fxstat);
+#endif
+
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c
index dc7f934..af1ff48 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/fxstatat.c
@@ -26,6 +26,7 @@ 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
+#ifndef XSTAT_IS_XSTAT64
 #include "overflow.h"
 
 /* Get information about the file NAME in BUF.  */
@@ -42,3 +43,5 @@  __fxstatat (int vers, int fd, const char *file, struct stat *buf, int flag)
   return -1;
 }
 libc_hidden_def (__fxstatat)
+#endif
+
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c
index 395f98b..4543897 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat.c
@@ -25,6 +25,7 @@ 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
+#ifndef XSTAT_IS_XSTAT64
 #include "overflow.h"
 
 /* Get information about the file NAME in BUF.  */
@@ -41,3 +42,5 @@  __lxstat (int vers, const char *name, struct stat *buf)
   return -1;
 }
 hidden_def (__lxstat)
+#endif
+
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c
index e1c15a8..217a6c8 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/lxstat64.c
@@ -15,6 +15,7 @@ 
    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/>.  */
+#define __lxstat __lxstat_disable
 
 #include <errno.h>
 #include <stddef.h>
@@ -25,14 +26,30 @@ 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
+#include <kernel-time.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);
+    {
+      int rc = INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf,
+			       AT_SYMLINK_NOFOLLOW);
+      if (!rc)
+	stat_conv_timespecs (buf);
+
+      return rc;
+    }
+
   errno = EINVAL;
   return -1;
 }
 hidden_def (__lxstat64)
+
+#undef __lxstat
+#ifdef XSTAT_IS_XSTAT64
+strong_alias (__lxstat64, __lxstat)
+hidden_ver (__lxstat64, __lxstat)
+#endif
+
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/statfs.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/statfs.c
index 1937f05..4893398 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/statfs.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/statfs.c
@@ -20,6 +20,7 @@ 
 #include <sys/statfs.h>
 #include <stddef.h>
 
+#ifndef XSTAT_IS_XSTAT64
 #include "overflow.h"
 
 /* Return information about the filesystem on which FILE resides.  */
@@ -31,3 +32,5 @@  __statfs (const char *file, struct statfs *buf)
 }
 libc_hidden_def (__statfs)
 weak_alias (__statfs, statfs)
+#endif
+
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c
index fdd2cb0..effb3a0 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat.c
@@ -25,6 +25,7 @@ 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
+#ifndef XSTAT_IS_XSTAT64
 #include "overflow.h"
 
 /* Get information about the file NAME in BUF.  */
@@ -41,3 +42,5 @@  __xstat (int vers, const char *name, struct stat *buf)
   return -1;
 }
 hidden_def (__xstat)
+#endif
+
diff --git a/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c b/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c
index 2252337..fc3ce13 100644
--- a/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c
+++ b/sysdeps/unix/sysv/linux/generic/wordsize-32/xstat64.c
@@ -15,6 +15,7 @@ 
    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/>.  */
+#define __xstat __xstat_disable
 
 #include <errno.h>
 #include <stddef.h>
@@ -25,14 +26,28 @@ 
 #include <sysdep.h>
 #include <sys/syscall.h>
 
+#include <kernel-time.h>
+
 /* Get information about the file NAME in BUF.  */
 int
 __xstat64 (int vers, const char *name, struct stat64 *buf)
 {
   if (vers == _STAT_VER_KERNEL)
-    return INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf, 0);
+    {
+      int rc = INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf, 0);
+      if (!rc)
+	stat_conv_timespecs (buf);
+      return rc;
+    }
 
   errno = EINVAL;
   return -1;
 }
 hidden_def (__xstat64)
+
+#undef __xstat
+#ifdef XSTAT_IS_XSTAT64
+strong_alias (__xstat64, __xstat)
+hidden_ver (__xstat64, __xstat)
+#endif
+
diff --git a/sysdeps/unix/sysv/linux/kernel-time.h b/sysdeps/unix/sysv/linux/kernel-time.h
new file mode 100644
index 0000000..500de02
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/kernel-time.h
@@ -0,0 +1,40 @@ 
+/* Helpers to convert struct __timespec to user-visible timespec.
+
+   Copyright (C) 1991-2016 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/>.  */
+
+#if SUPPORT_64BIT_TIME_TYPES
+# define conv_timespec(ts, _ts)					\
+  do								\
+    {								\
+      (ts)->tv_sec = (_ts)->tv_sec;				\
+      (ts)->tv_nsec = (_ts)->tv_nsec;				\
+    }								\
+  while (0)
+# define stat_conv_timespecs(__stat)				\
+  do								\
+    {								\
+      conv_timespec (&(__stat)->st_atim, &(__stat)->__st_atim);	\
+      conv_timespec (&(__stat)->st_mtim, &(__stat)->__st_mtim);	\
+      conv_timespec (&(__stat)->st_ctim, &(__stat)->__st_ctim);	\
+    }								\
+  while (0)
+#else
+# define conv_timespec(ts, _ts)		do {} while (0)
+# define stat_conv_timespecs(__stat)	do {} while (0)
+#endif
+
diff --git a/time/time.h b/time/time.h
index cc93917..c5dfcbb 100644
--- a/time/time.h
+++ b/time/time.h
@@ -65,6 +65,17 @@  __USING_NAMESPACE_STD(clock_t)
 #endif /* clock_t not defined and <time.h> or need clock_t.  */
 #undef	__need_clock_t
 
+#ifndef SUPPORT_64BIT_TIME_TYPES
+# ifdef __ASSUME_SUPPORT_64_BIT_TIME_TYPES
+#  if __WORDSIZE != 32
+#   error "__ASSUME_SUPPORT_64_BIT_TIME_TYPES is 32-bit only option"
+#  endif
+#  define SUPPORT_64BIT_TIME_TYPES	1
+# else
+#  define SUPPORT_64BIT_TIME_TYPES	0
+# endif
+#endif
+
 #if !defined __time_t_defined && (defined _TIME_H || defined __need_time_t)
 # define __time_t_defined	1
 
@@ -105,7 +116,6 @@  typedef __timer_t timer_t;
 #endif /* timer_t not defined and <time.h> or need timer_t.  */
 #undef	__need_timer_t
 
-
 #if (!defined __timespec_defined					\
      && ((defined _TIME_H						\
 	  && (defined __USE_POSIX199309					\
@@ -123,6 +133,24 @@  struct timespec
     __syscall_slong_t tv_nsec;	/* Nanoseconds.  */
   };
 
+# if SUPPORT_64BIT_TIME_TYPES
+struct __timespec
+  {
+    long long tv_sec;		/* Seconds.  */
+    long long tv_nsec;		/* Nanoseconds.  */
+  };
+
+#  define DECLARE_TIMESPEC(__name)		\
+    union					\
+      {						\
+	    struct timespec __name;		\
+	    struct __timespec __##__name;	\
+      };
+
+# else
+#  define DECLARE_TIMESPEC(__name) struct timespec __name
+# endif
+
 #endif /* timespec not defined and <time.h> or need timespec.  */
 #undef	__need_timespec