[RFC,AARCH64] ILP32: support stat syscall family

Message ID 1467291615-30356-1-git-send-email-ynorov@caviumnetworks.com
State New, archived
Headers

Commit Message

Yury Norov June 30, 2016, 1 p.m. UTC
  From: Yury Norov <yury.norov@gmail.com>

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:
 - __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T macro introduced to indicate that 32-bit
   ABI has struct __timespec (and maybe __timeval in future) that is compatible
   to 64-bit _timespec;
 - conv_timespec() macro is introduced to convert __timespec to 32-bit timespec
   (not sure in proper place);
 - XSTAT_IS_XSTAT64 is reused in 32-bit code, and STATFS_IS_STATFS64 is introduced
   to hint GLIBC that structures are identical, and 32-bit syscalls should be
   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.

Please review this approach. I'm not sure for 100% that reusing of XSTAT_IS_XSTAT64
is safe for other ports, thought it's used in 64-bit ABIs only. I also doubt on
choosing names for new functions and macros.

Any comments appreciated. If better way exists, I'll be thankfull for pointing it.

Signed-off-by: Yury Norov <ynorov@caviumnetworks.com>
---
 string/endian.h                                    | 13 ++++++++
 sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h   |  9 ++++++
 sysdeps/unix/sysv/linux/aarch64/ilp32/Implies      |  2 +-
 sysdeps/unix/sysv/linux/aarch64/ilp32/fstatfs64.c  | 36 +++++++++++++++++++++
 sysdeps/unix/sysv/linux/aarch64/ilp32/statfs64.c   | 37 ++++++++++++++++++++++
 sysdeps/unix/sysv/linux/fxstat64.c                 | 17 ++++++++++
 sysdeps/unix/sysv/linux/fxstatat64.c               | 17 +++++++++-
 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 | 22 ++++++++++++-
 .../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  | 21 +++++++++++-
 time/time.h                                        | 27 ++++++++++++++++
 18 files changed, 263 insertions(+), 24 deletions(-)
 create mode 100644 sysdeps/unix/sysv/linux/aarch64/ilp32/fstatfs64.c
 create mode 100644 sysdeps/unix/sysv/linux/aarch64/ilp32/statfs64.c
  

Comments

Andreas Schwab June 30, 2016, 1:03 p.m. UTC | #1
Yury Norov <ynorov@caviumnetworks.com> writes:

> +# define XSTAT_IS_XSTAT64
> +# define STATFS_IS_STATFS64

These are not valid identifiers in a public header.

Andreas.
  
Joseph Myers June 30, 2016, 1:51 p.m. UTC | #2
On Thu, 30 Jun 2016, Yury Norov wrote:

>  - __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T macro introduced to indicate that 32-bit
>    ABI has struct __timespec (and maybe __timeval in future) that is compatible
>    to 64-bit _timespec;

You can't add a macro to one architecture like that then use it in generic 
code.  You have to define it in *every* architecture's bits/typesizes.h 
before it can be used in generic code.

> +      return INLINE_SYSCALL (fstatfs64, 2, fd, buf);

Bad indentation.  Likewise elsewhere in this patch.

> +++ b/sysdeps/unix/sysv/linux/aarch64/ilp32/statfs64.c
> @@ -0,0 +1,37 @@
> +/* Copyright (C) 2011-2015 Free Software Foundation, Inc.

Still missing descriptive first line and 2016 in copyright dates.

> +   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.

There should be no "Contributed by" lines in new files.

> +  return result;
> +#endif
> +#if __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T
> +      if (!result)
> +        {
> +	   conv_timespec(&buf->st_atim, &buf->__st_atim);
> +	   conv_timespec(&buf->st_mtim, &buf->__st_mtim);
> +	   conv_timespec(&buf->st_ctim, &buf->__st_ctim);
> +        }
>  #endif

Indentation way off.

> +       conv_timespec(&st->st_atim, &st->__st_atim);
> +       conv_timespec(&st->st_mtim, &st->__st_mtim);
> +       conv_timespec(&st->st_ctim, &st->__st_ctim);

Missing space before '('.

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

DECLARE_TIMESPEC is in the user's namespace, not valid in installed 
headers.

> +#  define conv_timespec(ts, _ts)		\

Again, not valid in installed headers.
  
Yury Norov July 1, 2016, 9:03 a.m. UTC | #3
On Thu, Jun 30, 2016 at 01:51:22PM +0000, Joseph Myers wrote:
> On Thu, 30 Jun 2016, Yury Norov wrote:
> 
> >  - __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T macro introduced to indicate that 32-bit
> >    ABI has struct __timespec (and maybe __timeval in future) that is compatible
> >    to 64-bit _timespec;
> 
> You can't add a macro to one architecture like that then use it in generic 
> code.  You have to define it in *every* architecture's bits/typesizes.h 
> before it can be used in generic code.

Is it OK to do like this then?
#define __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T /* w/o 1 or 0 */

Where's a proper place for it? In features.h maybe?

> > +      return INLINE_SYSCALL (fstatfs64, 2, fd, buf);
> 
> Bad indentation.  Likewise elsewhere in this patch.
> 
> > +++ b/sysdeps/unix/sysv/linux/aarch64/ilp32/statfs64.c
> > @@ -0,0 +1,37 @@
> > +/* Copyright (C) 2011-2015 Free Software Foundation, Inc.
> 
> Still missing descriptive first line and 2016 in copyright dates.
> 
> > +   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
> 
> There should be no "Contributed by" lines in new files.
> 
> > +  return result;
> > +#endif
> > +#if __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T
> > +      if (!result)
> > +        {
> > +	   conv_timespec(&buf->st_atim, &buf->__st_atim);
> > +	   conv_timespec(&buf->st_mtim, &buf->__st_mtim);
> > +	   conv_timespec(&buf->st_ctim, &buf->__st_ctim);
> > +        }
> >  #endif
> 
> Indentation way off.

It looks ugly only in email. If you apply patch, it will be better.

> 
> > +       conv_timespec(&st->st_atim, &st->__st_atim);
> > +       conv_timespec(&st->st_mtim, &st->__st_mtim);
> > +       conv_timespec(&st->st_ctim, &st->__st_ctim);
> 
> Missing space before '('.

This rule is scary, for sure. I cannot autoreplace all such places as
it doesn't work for definitions, and I cannot drop whitespaces everywhere
because it breaks rules. So I have to pay attention to it again and
again. Script you pointed me doesn't understand difference between
definition and usage of macro. I spent 2 hours fixing the fixes I made
following the report of that script.

Could someone give me clear understanding, how exactly this rule
improves readability and helps finding bugs. I write it because this
rule makes real troubles to me, and helps with nothing.

> > +    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.  */
> 
> DECLARE_TIMESPEC is in the user's namespace, not valid in installed 
> headers.
> 
> > +#  define conv_timespec(ts, _ts)		\
> 
> Again, not valid in installed headers.


What the proper place you suggest? New timer-related private header?

Yury
  
Joseph Myers July 1, 2016, 12:05 p.m. UTC | #4
On Fri, 1 Jul 2016, Yury Norov wrote:

> On Thu, Jun 30, 2016 at 01:51:22PM +0000, Joseph Myers wrote:
> > On Thu, 30 Jun 2016, Yury Norov wrote:
> > 
> > >  - __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T macro introduced to indicate that 32-bit
> > >    ABI has struct __timespec (and maybe __timeval in future) that is compatible
> > >    to 64-bit _timespec;
> > 
> > You can't add a macro to one architecture like that then use it in generic 
> > code.  You have to define it in *every* architecture's bits/typesizes.h 
> > before it can be used in generic code.
> 
> Is it OK to do like this then?
> #define __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T /* w/o 1 or 0 */

No.  Defining to 0 or 1 is the right thing to do - but you need to 
identify *all* relevant bits/typesizes.h headers (if that's the bits/ 
header you use for this) and update *all* of them to define the macro to 
the appropriate value.

In general, if a new port needs something new, you must think first in 
terms of architecture-independent design for how to handle the new issue 
in the logically best and cleanest way, and then make any necessary 
changes / refactoring for all existing ports.  Not just hack up whatever 
seems most convenient for your port without thinking about the logically 
correct design to cover all existing and expected future ports.

> > > +  return result;
> > > +#endif
> > > +#if __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T
> > > +      if (!result)
> > > +        {
> > > +	   conv_timespec(&buf->st_atim, &buf->__st_atim);
> > > +	   conv_timespec(&buf->st_mtim, &buf->__st_mtim);
> > > +	   conv_timespec(&buf->st_ctim, &buf->__st_ctim);
> > > +        }
> > >  #endif
> > 
> > Indentation way off.
> 
> It looks ugly only in email. If you apply patch, it will be better.

Still wrong.  The "if" line should be indented by two columns, the "{" and 
"}" by four columns and the conv_timespec calls by six columns.

> > > +#  define conv_timespec(ts, _ts)		\
> > 
> > Again, not valid in installed headers.
> 
> What the proper place you suggest? New timer-related private header?

If something is only needed in the implementation, it should go in an 
internal header, not installed.

If something is needed in the installed headers but is not part of the 
public, documented (generally system-independent) API, it must have a name 
in the implementation namespace.

No, I'm not saying "macro X should go in header Y".  I'm giving the 
principles that you, understanding the issues you are trying to address, 
can use to determine what is correct.  It's your responsibility as a patch 
submitter to apply those principles to the port you are implementing, and 
to write up your patch submissions in sufficient depth to make clear to 
the reviewers how you have considered and addressed those principles.
  
Adhemerval Zanella July 1, 2016, 12:12 p.m. UTC | #5
On 01/07/2016 06:03, Yury Norov wrote:
> On Thu, Jun 30, 2016 at 01:51:22PM +0000, Joseph Myers wrote:
>> On Thu, 30 Jun 2016, Yury Norov wrote:
>>
>>>  - __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T macro introduced to indicate that 32-bit
>>>    ABI has struct __timespec (and maybe __timeval in future) that is compatible
>>>    to 64-bit _timespec;
>>
>> You can't add a macro to one architecture like that then use it in generic 
>> code.  You have to define it in *every* architecture's bits/typesizes.h 
>> before it can be used in generic code.
> 
> Is it OK to do like this then?
> #define __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T /* w/o 1 or 0 */
> 
> Where's a proper place for it? In features.h maybe?

I would say kernel-features.h since you are touching Linux specific code.
Also I would make the sysdeps/unix/sysv/linux/* implementation use the
default and expected case and add a new flag only in the non-default case
(so you won't need to check all current ports to see they fit or not).

> 
>>> +      return INLINE_SYSCALL (fstatfs64, 2, fd, buf);
>>
>> Bad indentation.  Likewise elsewhere in this patch.
>>
>>> +++ b/sysdeps/unix/sysv/linux/aarch64/ilp32/statfs64.c
>>> @@ -0,0 +1,37 @@
>>> +/* Copyright (C) 2011-2015 Free Software Foundation, Inc.
>>
>> Still missing descriptive first line and 2016 in copyright dates.
>>
>>> +   Contributed by Chris Metcalf <cmetcalf@tilera.com>, 2011.
>>
>> There should be no "Contributed by" lines in new files.
>>
>>> +  return result;
>>> +#endif
>>> +#if __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T
>>> +      if (!result)
>>> +        {
>>> +	   conv_timespec(&buf->st_atim, &buf->__st_atim);
>>> +	   conv_timespec(&buf->st_mtim, &buf->__st_mtim);
>>> +	   conv_timespec(&buf->st_ctim, &buf->__st_ctim);
>>> +        }
>>>  #endif
>>
>> Indentation way off.
> 
> It looks ugly only in email. If you apply patch, it will be better.

The problem is patch is using whitespace where it should a tab.

> 
>>
>>> +       conv_timespec(&st->st_atim, &st->__st_atim);
>>> +       conv_timespec(&st->st_mtim, &st->__st_mtim);
>>> +       conv_timespec(&st->st_ctim, &st->__st_ctim);
>>
>> Missing space before '('.
> 
> This rule is scary, for sure. I cannot autoreplace all such places as
> it doesn't work for definitions, and I cannot drop whitespaces everywhere
> because it breaks rules. So I have to pay attention to it again and
> again. Script you pointed me doesn't understand difference between
> definition and usage of macro. I spent 2 hours fixing the fixes I made
> following the report of that script.
> 
> Could someone give me clear understanding, how exactly this rule
> improves readability and helps finding bugs. I write it because this
> rule makes real troubles to me, and helps with nothing.

Most of current code guidelines are described at [1].  One tool you can use
with some care is 'indent' [2], however I see this break some code (specially
with inline assembly or some deep macro usage).

[1] https://sourceware.org/glibc/wiki/Style_and_Conventions
[2] https://www.gnu.org/software/indent/manual/indent.html

> 
>>> +    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.  */
>>
>> DECLARE_TIMESPEC is in the user's namespace, not valid in installed 
>> headers.
>>
>>> +#  define conv_timespec(ts, _ts)		\
>>
>> Again, not valid in installed headers.
> 
> 
> What the proper place you suggest? New timer-related private header?
> 
> Yury
>
  
Florian Weimer July 4, 2016, 10:43 a.m. UTC | #6
On 07/01/2016 11:03 AM, Yury Norov wrote:
> On Thu, Jun 30, 2016 at 01:51:22PM +0000, Joseph Myers wrote:
>> On Thu, 30 Jun 2016, Yury Norov wrote:
>>
>>>  - __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T macro introduced to indicate that 32-bit
>>>    ABI has struct __timespec (and maybe __timeval in future) that is compatible
>>>    to 64-bit _timespec;
>>
>> You can't add a macro to one architecture like that then use it in generic
>> code.  You have to define it in *every* architecture's bits/typesizes.h
>> before it can be used in generic code.
>
> Is it OK to do like this then?
> #define __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T /* w/o 1 or 0 */
>
> Where's a proper place for it? In features.h maybe?

How do you propose to set the default and add the architecture-specific 
overrides?

Thanks,
Florian
  
Yury Norov July 4, 2016, 12:04 p.m. UTC | #7
On Mon, Jul 04, 2016 at 12:43:19PM +0200, Florian Weimer wrote:
> On 07/01/2016 11:03 AM, Yury Norov wrote:
> >On Thu, Jun 30, 2016 at 01:51:22PM +0000, Joseph Myers wrote:
> >>On Thu, 30 Jun 2016, Yury Norov wrote:
> >>
> >>> - __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T macro introduced to indicate that 32-bit
> >>>   ABI has struct __timespec (and maybe __timeval in future) that is compatible
> >>>   to 64-bit _timespec;
> >>
> >>You can't add a macro to one architecture like that then use it in generic
> >>code.  You have to define it in *every* architecture's bits/typesizes.h
> >>before it can be used in generic code.
> >
> >Is it OK to do like this then?
> >#define __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T /* w/o 1 or 0 */
> >
> >Where's a proper place for it? In features.h maybe?
> 
> How do you propose to set the default and add the architecture-specific
> overrides?
> 
> Thanks,
> Florian

I don't know. I'm experimenting with it, but have no answer yet.
Is there standard way to add new option to glibc, and not to set it to 0
in all unrelated ports?

As now, the best option I see is to define all needed options in arch
header, and then use #inclure_next.

Yury
  

Patch

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..206c64b 100644
--- a/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h
+++ b/sysdeps/unix/sysv/linux/aarch64/bits/typesizes.h
@@ -62,6 +62,15 @@ 
 #define __SYSCALL_ULONG_TYPE	__ULONGWORD_TYPE
 #define __CPU_MASK_TYPE         __ULONGWORD_TYPE
 
+
+#ifdef __ILP32__
+# define __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T		1
+# define XSTAT_IS_XSTAT64
+# define STATFS_IS_STATFS64
+#else
+# define __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T		0
+#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/Implies b/sysdeps/unix/sysv/linux/aarch64/ilp32/Implies
index 151f0e4..7dd239e 100644
--- a/sysdeps/unix/sysv/linux/aarch64/ilp32/Implies
+++ b/sysdeps/unix/sysv/linux/aarch64/ilp32/Implies
@@ -1,4 +1,4 @@ 
 aarch64/nptl
 unix/sysv/linux/aarch64
-unix/sysv/linux/generic
 unix/sysv/linux/generic/wordsize-32
+unix/sysv/linux/generic
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..3e0fef4
--- /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>
+
+/* Return information about the filesystem on which FD resides.  */
+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..273975b
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/aarch64/ilp32/statfs64.c
@@ -0,0 +1,37 @@ 
+/* 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>
+
+/* Return information about the filesystem on which FILE resides.  */
+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..923ba37 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>
@@ -36,12 +37,22 @@  ___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 __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T
+      if (!result)
+        {
+	   conv_timespec(&buf->st_atim, &buf->__st_atim);
+	   conv_timespec(&buf->st_mtim, &buf->__st_mtim);
+	   conv_timespec(&buf->st_ctim, &buf->__st_ctim);
+        }
 #endif
   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 +62,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..5d3846a 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>
@@ -39,9 +40,23 @@  __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;
+    {
+#ifdef __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T
+       conv_timespec(&st->st_atim, &st->__st_atim);
+       conv_timespec(&st->st_mtim, &st->__st_mtim);
+       conv_timespec(&st->st_ctim, &st->__st_ctim);
+#endif
+       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..e1e0c11 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
+# ifdef __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T
+    __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 /* __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T.  */
 #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
+# ifdef __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T
+    __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 /* __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T.  */
 #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..3379e0a 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 (STATFS_IS_STATFS64)
 # 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 STATFS_IS_STATFS64
+# 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..d0c140b 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 STATFS_IS_STATFS64
+
 #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..44a855d 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>
@@ -30,9 +31,28 @@  int
 __lxstat64 (int vers, const char *name, struct stat64 *buf)
 {
   if (vers == _STAT_VER_KERNEL)
-    return INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf,
+    {
+      int rc = INLINE_SYSCALL (fstatat64, 4, AT_FDCWD, name, buf,
                            AT_SYMLINK_NOFOLLOW);
+#if __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T
+      if (!rc)
+        {
+	  conv_timespec(&buf->st_atim, &buf->__st_atim);
+	  conv_timespec(&buf->st_mtim, &buf->__st_mtim);
+	  conv_timespec(&buf->st_ctim, &buf->__st_ctim);
+        }
+#endif
+      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..9b33eae 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 STATFS_IS_STATFS64
 #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..3f1bd43 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>
@@ -30,9 +31,27 @@  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 __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T
+      if (!rc)
+        {
+	   conv_timespec(&buf->st_atim, &buf->__st_atim);
+	   conv_timespec(&buf->st_mtim, &buf->__st_mtim);
+	   conv_timespec(&buf->st_ctim, &buf->__st_ctim);
+        }
+#endif
+      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/time/time.h b/time/time.h
index cc93917..6b01971 100644
--- a/time/time.h
+++ b/time/time.h
@@ -123,6 +123,33 @@  struct timespec
     __syscall_slong_t tv_nsec;	/* Nanoseconds.  */
   };
 
+# if __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T == 1
+struct __timespec
+  {
+    long long tv_sec;		/* Seconds.  */
+    long long tv_nsec;		/* Nanoseconds.  */
+  };
+
+#  define conv_timespec(ts, _ts)		\
+  do						\
+    {						\
+      (ts)->tv_sec = (_ts)->tv_sec;		\
+      (ts)->tv_nsec = (_ts)->tv_nsec;		\
+    }						\
+  while (0)
+
+#  define DECLARE_TIMESPEC(__name)		\
+    union					\
+      {						\
+	    struct timespec __name;		\
+	    struct __timespec __##__name;	\
+      };
+
+# else
+#  define DECLARE_TIMESPEC(__name) struct timespec __name
+#  define conv_timespec(ts, _ts)
+# endif /* __32_BIT_ABI_SUPPORTS_64_BIT_TIME_T.  */
+
 #endif /* timespec not defined and <time.h> or need timespec.  */
 #undef	__need_timespec