Y2038: provide kernel support indication

Message ID 20180919071303.26636-1-albert.aribaud@3adev.fr
State New
Headers show
Series
  • Y2038: provide kernel support indication
Related show

Commit Message

Albert ARIBAUD Sept. 19, 2018, 7:13 a.m.
* New function __y2038_get_kernel_support() returns:
  * 0 if the underlying kernel does not support Y2038 at all
  * > 0 if the underlying kernel has some support for Y2038
  * < 0 if the underlying kernel support for Y2038 is broken
* New function __y2038_set_kernel_support() allows indicating
  a kernel's Y2038 support (or support failure)
* Default implementation (covering non-Linux kernels) always
  returns 0 (no support).
---

This patch is part of the Y2038 patch series, which is available at
<https://sourceware.org/git/?p=glibc.git;a=shortlog;h=refs/heads/aaribaud/y2038>.
Warning: this branch may be rebased on current master and/or updated based on
feedback from the list at any time.

 misc/Makefile                           |  2 +-
 misc/Versions                           |  4 +++
 misc/y2038-support.c                    | 32 ++++++++++++++++++++
 misc/y2038-support.h                    | 36 ++++++++++++++++++++++
 sysdeps/unix/sysv/linux/y2038-support.c | 40 +++++++++++++++++++++++++
 sysdeps/unix/sysv/linux/y2038-support.h | 30 +++++++++++++++++++
 6 files changed, 143 insertions(+), 1 deletion(-)
 create mode 100644 misc/y2038-support.c
 create mode 100644 misc/y2038-support.h
 create mode 100644 sysdeps/unix/sysv/linux/y2038-support.c
 create mode 100644 sysdeps/unix/sysv/linux/y2038-support.h

Comments

Joseph Myers Sept. 19, 2018, 1:03 p.m. | #1
On Wed, 19 Sep 2018, Albert ARIBAUD (3ADEV) wrote:

> * New function __y2038_get_kernel_support() returns:
>   * 0 if the underlying kernel does not support Y2038 at all
>   * > 0 if the underlying kernel has some support for Y2038
>   * < 0 if the underlying kernel support for Y2038 is broken
> * New function __y2038_set_kernel_support() allows indicating
>   a kernel's Y2038 support (or support failure)
> * Default implementation (covering non-Linux kernels) always
>   returns 0 (no support).

There should be an __ASSUME_* macro that kernel-features.h defines when 
the minimum kernel version has the required feature.  Calls to these APIs 
need to become compile-time constants in that case, with the functions / 
variables not existing in the glibc binaries at all.

> +  GLIBC_2.29 {
> +    __y2038_get_kernel_support;
> +    __y2038_set_kernel_support;
> +  }

I don't think these should be public interfaces (but if they were, the 
patch would need to update all the ABI test baselines).  If exported for 
use by other glibc shared libraries, they should be exported at version 
GLIBC_PRIVATE.  (That does require they are never used in code in 
*_nonshared.a because that may end up in users' programs / shared 
libraries, but very little should go in *_nonshared.a.)
Paul Eggert Sept. 19, 2018, 4:11 p.m. | #2
Albert ARIBAUD (3ADEV) wrote:
> +/* Indicates Y2038 support.
> + * 0 means no suppport
> + * > 0 means (some) support
> + * < 0 means support is broken
> + * Can be read directly from within libc linux-related files.
> + * Can be written non-zero to indicate support or lack thereof.
> + */
> +extern int __y2038_linux_support;

This variable needs a better comment, since it's not clear from that comment 
what it's for. In the current branch, I don't see any code setting the variable 
to a positive value; it defaults to 0 and if any glibc code discovers anything 
that looks like a y2038 bug, the variable is set to -1.

So it looks like a cache: as glibc discovers y2038 bugs, it uses the cache to 
avoid trying to invoke system calls that it knows will fail anyway with ENOSYS, 
or something like that. If that's the intent, it needs to be documented in the 
variable.

However, I imagine that some kernels will have some y2038 bugs but not others. 
For example, clock_gettime and related functions might work fine on a particular 
kernel, but some ioctls might not work (or might work for some devices but not 
others) due to device-drivers not being y2038-safe. How is __y2038_linux_support 
supposed to reflect this more-complicated situation?
Albert ARIBAUD Sept. 24, 2018, 9:34 p.m. | #3
Hi Paul,

On Wed, 19 Sep 2018 09:11:18 -0700, Paul Eggert <eggert@cs.ucla.edu>
wrote :

> Albert ARIBAUD (3ADEV) wrote:
> > +/* Indicates Y2038 support.
> > + * 0 means no suppport
> > + * > 0 means (some) support
> > + * < 0 means support is broken
> > + * Can be read directly from within libc linux-related files.
> > + * Can be written non-zero to indicate support or lack thereof.
> > + */
> > +extern int __y2038_linux_support;  
> 
> This variable needs a better comment, since it's not clear from that comment 
> what it's for. In the current branch, I don't see any code setting the variable 
> to a positive value; it defaults to 0 and if any glibc code discovers anything 
> that looks like a y2038 bug, the variable is set to -1.
> 
> So it looks like a cache: as glibc discovers y2038 bugs, it uses the cache to 
> avoid trying to invoke system calls that it knows will fail anyway with ENOSYS, 
> or something like that. If that's the intent, it needs to be documented in the 
> variable.
>
> However, I imagine that some kernels will have some y2038 bugs but not others. 
> For example, clock_gettime and related functions might work fine on a particular 
> kernel, but some ioctls might not work (or might work for some devices but not 
> others) due to device-drivers not being y2038-safe. How is __y2038_linux_support 
> supposed to reflect this more-complicated situation?

Right now we can use the bits in __y2038_linux_support to indicate
level of support (when positive) or reasons for not supporting (when
negative). That's 31 distinct flags.

If we want to be able to use more than 31 bits, we could reuse the
bitset_t type of the posix/regex_internal.h file and make the variable
a bitset_t. Then we could define an arbitrary number of Y2038 features /
quirks / bugs as bit indices:

  /* Y2038 unique feature/quirk/bug identifiers.  */

  /* Kernel does or does not support Y2038 globally.  */
  #define Y2038_FEATURE 0

  /* Linux kernel does or does not provide clock_gettime64 syscall.  */
  #define Y2038_FEATURE_LINUX_CLOCK_GETTIME64 1

  /* Linux kernel does or does not provide clock_settime64 syscall.  */
  #define Y2038_FEATURE_LINUX_CLOCK_SETTIME64 2
  /* etc.  *.

  [...]

  /* Linux kernel clock_gettime64 implementation has quirk 'XYZ'
  #define Y2038_FEATURE_LINUX_CLOCK_GETTIME64_XYZ 42
  /* etc.  */

(there could be a set of indices for Linux, another for BSD, etc.)

For glibc modules which could not directly access the variable (and
thus could not use the inline bitset_t functions, we would provide
getters and setters named after their bitset_t equivalents:

  bool __y2038_kernel_feature_contain(int feature);
  bool __y2038_kernel_feature_set(int feature);
  bool __y2038_kernel_feature_clear(int feature);

Comments?

Cordialement,
Albert ARIBAUD
3ADEV
Paul Eggert Sept. 24, 2018, 9:50 p.m. | #4
On 9/24/18 2:34 PM, Albert ARIBAUD wrote:
> Right now we can use the bits in __y2038_linux_support to indicate
> level of support (when positive) or reasons for not supporting (when
> negative). That's 31 distinct flags.

Rather than trying to shoehorn this into a single central integer or 
bitset that governs everything that could go wrong or right with Y2038, 
how about having a separate boolean (or whatever) variable for each 
feature? That way, only code that is worried about that feature needs to 
know about the variable, and it's easier to add or remove variables as 
the need for them is discovered or abandoned.

>    /* Linux kernel does or does not provide clock_gettime64 syscall.  */
>    #define Y2038_FEATURE_LINUX_CLOCK_GETTIME64 1
>
>    /* Linux kernel does or does not provide clock_settime64 syscall.  */
>    #define Y2038_FEATURE_LINUX_CLOCK_SETTIME64 2

Will there ever be a kernel that provides one syscall but not the other? 
We shouldn't need variables for each theoretically-possible platform, 
only for the platforms that exist, or are likely to.
Albert ARIBAUD Sept. 24, 2018, 9:56 p.m. | #5
Hi Joseph,

On Wed, 19 Sep 2018 13:03:21 +0000, Joseph Myers
<joseph@codesourcery.com> wrote :

> On Wed, 19 Sep 2018, Albert ARIBAUD (3ADEV) wrote:
> 
> > * New function __y2038_get_kernel_support() returns:
> >   * 0 if the underlying kernel does not support Y2038 at all
> >   * > 0 if the underlying kernel has some support for Y2038
> >   * < 0 if the underlying kernel support for Y2038 is broken
> > * New function __y2038_set_kernel_support() allows indicating
> >   a kernel's Y2038 support (or support failure)
> > * Default implementation (covering non-Linux kernels) always
> >   returns 0 (no support).  
> 
> There should be an __ASSUME_* macro that kernel-features.h defines when 
> the minimum kernel version has the required feature.  Calls to these APIs 
> need to become compile-time constants in that case, with the functions / 
> variables not existing in the glibc binaries at all.

Ok, how about __ASSUME_KERNEL_Y2038_SUPPORT?

In case it is not defined, then all Y2038 feature support calls would
return 'no support'.

Considering right now no kernel has 64-bit-time syscalls (there is only
a patch series / development branch which provides some for some
architectures), __ASSUME_KERNEL_Y2038_SUPPORT should remain undefined
(but I will define it for testing with the dev branch).

So what is the best option:

- not define it at all (at the risk of people wondering why I am
  referring to an undefined __ASSUME_*)

- Just #undef it in sysdeps/unix/sysv/linux/kernel-features.h even
  though it is not #define'd elsewhere?

- #define it in sysdeps/unix/sysv/linux/kernel-features.h and then
  #undef it in sysdeps/unix/sysv/linux/*/kernel-features.h, and later
  when some architecture gets Y2038 syscall support, remove its #undef?

> > +  GLIBC_2.29 {
> > +    __y2038_get_kernel_support;
> > +    __y2038_set_kernel_support;
> > +  }  
> 
> I don't think these should be public interfaces (but if they were, the 
> patch would need to update all the ABI test baselines).  If exported for 
> use by other glibc shared libraries, they should be exported at version 
> GLIBC_PRIVATE.  (That does require they are never used in code in 
> *_nonshared.a because that may end up in users' programs / shared 
> libraries, but very little should go in *_nonshared.a.)

Indeed, some glibc shared libs will need those, but there is little
reason that public code should use them. I will switch to GLIBC_PRIVATE
(but the names and number of functions will probably change, see Paul's
comments re Y2038 features).

Cordialement,
Albert ARIBAUD
3ADEV
Albert ARIBAUD Sept. 24, 2018, 10:11 p.m. | #6
Hi Paul,

Le Mon, 24 Sep 2018 14:50:34 -0700, Paul Eggert <eggert@cs.ucla.edu> a
écrit :

> On 9/24/18 2:34 PM, Albert ARIBAUD wrote:
> > Right now we can use the bits in __y2038_linux_support to indicate
> > level of support (when positive) or reasons for not supporting (when
> > negative). That's 31 distinct flags.  
> 
> Rather than trying to shoehorn this into a single central integer or 
> bitset that governs everything that could go wrong or right with Y2038, 
> how about having a separate boolean (or whatever) variable for each 
> feature? That way, only code that is worried about that feature needs to 
> know about the variable, and it's easier to add or remove variables as 
> the need for them is discovered or abandoned.

How would each 'feature' be defined? For instance, right now, either
the Linux kernel has no Y2038-proof syscalls at all, or it has a known
list of them (added in the kernel Y2038 syscall branch). Would that be
one 'feature', on the grounds that later kernels will provide at least
the same set, and possible a larget set, of Y2038 syscalls? Or as many
features as there are syscalls, on the grounds that some of these
syscalls may one day disappear?

> >    /* Linux kernel does or does not provide clock_gettime64 syscall.  */
> >    #define Y2038_FEATURE_LINUX_CLOCK_GETTIME64 1
> >
> >    /* Linux kernel does or does not provide clock_settime64 syscall.  */
> >    #define Y2038_FEATURE_LINUX_CLOCK_SETTIME64 2  
> 
> Will there ever be a kernel that provides one syscall but not the other? 
> We shouldn't need variables for each theoretically-possible platform, 
> only for the platforms that exist, or are likely to.

Those were examples only. Right now, apart from a general "architecture
now has support for Y2038 syscalls" feature, the only feature I can see
will happen is "syscall X has quirk Y  [for architecture Z]". What
other sort of feature should we expect?

Cordialement,
Albert ARIBAUD
3ADEV
Paul Eggert Sept. 25, 2018, 6:19 a.m. | #7
Albert ARIBAUD wrote:
> How would each 'feature' be defined? For instance, right now, either
> the Linux kernel has no Y2038-proof syscalls at all, or it has a known
> list of them (added in the kernel Y2038 syscall branch). Would that be
> one 'feature', on the grounds that later kernels will provide at least
> the same set, and possible a larget set, of Y2038 syscalls? Or as many
> features as there are syscalls, on the grounds that some of these
> syscalls may one day disappear?

The former sounds better, at least for now. It can evolve to the latter if and 
when the syscall set mutates. I see little advantage to starting with the latter 
now.


> Right now, apart from a general "architecture
> now has support for Y2038 syscalls" feature, the only feature I can see
> will happen is "syscall X has quirk Y  [for architecture Z]".

Yes, that's the sort of thing that I expect too. But unless I'm missing 
something, we don't have a strong need for a central repository that catalogs 
these quirks, as they're likely to be local to single modules[
Albert ARIBAUD Sept. 25, 2018, 9:13 a.m. | #8
Hi Paul,

On Mon, 24 Sep 2018 23:19:56 -0700, Paul Eggert <eggert@cs.ucla.edu>
wrote :

> Albert ARIBAUD wrote:
> > How would each 'feature' be defined? For instance, right now, either
> > the Linux kernel has no Y2038-proof syscalls at all, or it has a known
> > list of them (added in the kernel Y2038 syscall branch). Would that be
> > one 'feature', on the grounds that later kernels will provide at least
> > the same set, and possible a larget set, of Y2038 syscalls? Or as many
> > features as there are syscalls, on the grounds that some of these
> > syscalls may one day disappear?  
> 
> The former sounds better, at least for now. It can evolve to the latter if and 
> when the syscall set mutates. I see little advantage to starting with the latter 
> now.
> 
> 
> > Right now, apart from a general "architecture
> > now has support for Y2038 syscalls" feature, the only feature I can see
> > will happen is "syscall X has quirk Y  [for architecture Z]".  
> 
> Yes, that's the sort of thing that I expect too. But unless I'm missing 
> something, we don't have a strong need for a central repository that catalogs 
> these quirks, as they're likely to be local to single modules[

Ok, so:

- one new boolean for every new feature, which libc can read/write.
  Reading happens every time the feature is used.
  Writing happens very rarely, once when first first using / testing for
  the feature (e.g. at application start), once if using the feature
  fails (e.g. a syscall returns ENOSYS).

- two accessors (getter/setter) for every new feature if it must be
  read/set from another glibc library than libc (e.g. librt).

Cordialement,
Albert ARIBAUD
3ADEV
Florian Weimer Sept. 25, 2018, 10:58 a.m. | #9
* Albert ARIBAUD:

> - one new boolean for every new feature, which libc can read/write.
>   Reading happens every time the feature is used.
>   Writing happens very rarely, once when first first using / testing for
>   the feature (e.g. at application start), once if using the feature
>   fails (e.g. a syscall returns ENOSYS).
>
> - two accessors (getter/setter) for every new feature if it must be
>   read/set from another glibc library than libc (e.g. librt).

I'm still surprised that this is needed.  Why can't applications call
the function in question and react to a well-documented error code?

Thanks,
Florian
Albert ARIBAUD Sept. 25, 2018, 4:47 p.m. | #10
Hi Florian,

On Tue, 25 Sep 2018 12:58:25 +0200, Florian Weimer <fweimer@redhat.com>
wrote :

> * Albert ARIBAUD:
> 
> > - one new boolean for every new feature, which libc can read/write.
> >   Reading happens every time the feature is used.
> >   Writing happens very rarely, once when first first using / testing for
> >   the feature (e.g. at application start), once if using the feature
> >   fails (e.g. a syscall returns ENOSYS).
> >
> > - two accessors (getter/setter) for every new feature if it must be
> >   read/set from another glibc library than libc (e.g. librt).  
> 
> I'm still surprised that this is needed.  Why can't applications call
> the function in question and react to a well-documented error code?

These features are for glibc rather than for applications; they are
here for glibc to remember whether a Y2038 feature is available in the
kernel over which it currently runs.

Implementations for 64-bit time interfaces which rely on syscalls need
to be able to fall back to 32-bit-time syscalls if 64-bit-time syscalls
fail. Once a 64-bit-syscall has failed, it makes little sense to try it
again later; glibc can save the effort and directly call the 32-bit
syscall.

Applications, on the other hand, would call the 64-bit-time interface
regardless of the feature state. Whether this call would translate
into 64-bit-time or 32-bit-time syscalls would be invisible to them. 

> Thanks,
> Florian

Cordialement,
Albert ARIBAUD
3ADEV
Joseph Myers Sept. 25, 2018, 5:25 p.m. | #11
On Mon, 24 Sep 2018, Albert ARIBAUD wrote:

> > There should be an __ASSUME_* macro that kernel-features.h defines when 
> > the minimum kernel version has the required feature.  Calls to these APIs 
> > need to become compile-time constants in that case, with the functions / 
> > variables not existing in the glibc binaries at all.
> 
> Ok, how about __ASSUME_KERNEL_Y2038_SUPPORT?
> 
> In case it is not defined, then all Y2038 feature support calls would
> return 'no support'.

Well, normally "not defined" for __ASSUME_* doesn't mean "no support"; it 
means "support may or may not be present, and needs to be tested for at 
runtime if the __NR_* macros in question are defined".

Before we work out what the macro (or macros if more than one is needed) 
is called, and the semantics of it being defined or undefined, we need to 
have a clear understanding of the semantics.  And that in turn requires a 
clear understanding of what the future kernel interfaces will be.

Could you provide a description of what the kernel interfaces will be in 
future for each of the following cases (and any other significantly 
different variants I've missed)?  Then, indicate whether you'd expect the 
__ASSUME_* macro or macros to be defined in each of those cases.  
Hopefully this will help clarify what the interfaces should look like 
within glibc.  (This information will also need to go in the proposed 
glibc commit messages for future versions of the present patch, and quite 
likely some of it should go in comments in glibc code.)


1a. Existing 64-bit architectures, where 64-bit time_t is the only variant 
supported, in both the kernel and (if those architectures already have 
glibc ports) glibc.

My expectation is that these will *not* provide any new syscalls and will 
*not* provide any new __NR_* aliases for existing syscalls.  Is that 
correct?

If so, would the __ASSUME_* macro be defined for those architectures or 
not?  Whether it is or not, there must *not* be any new variables or 
internal functions defined in glibc at all relating to Y2038 support, or 
any additional levels of function calls / wrappers at runtime when 
time-related glibc functions are used, given that there are no Y2038 
problems for those architectures at present anyway.  (Avoiding such extra 
code and data might involve e.g. __TIMESIZE conditionals.  Naturally it's 
*also* desirable to design the implementation internals to reduce the 
number of places needing such conditionals.)


1b. New 64-bit architectures (not currently supported in the kernel).

My expectation is that these will be the same as old ones - they will 
provide the existing syscalls (minus obsolete ones), under their existing 
names, not any new ones that explicitly reference 64-bit time.  Is that 
correct?  If so, I'd expect them to look exactly like case 1a in glibc.


2a. Existing 32-bit architectures, supported in both the kernel and glibc 
with 32-bit time_t.

These will all need to gain new syscalls under new names, with the new 
macro defined when those syscalls are known to be available at runtime.


2b. Existing 32-bit architectures, already supported in the kernel, but 
not supported in glibc until after the 64-bit time support is present in 
both places.

From the point of view of the kernel, these should be exactly like case 
2a.  But from the point of view of glibc, they might be different - we 
might want to support only 64-bit time for them (so __TIMESIZE would be 
64, and _TIME_BITS=64 would do nothing).  Is that what you'd intend for 
such new architectures in glibc?  If so, presumably the __ASSUME_* macro 
would still be defined for them, but the combination of that macro and 
__TIMESIZE == 64 might end up doing different things in some places?  And 
would the glibc port for such an architecture allow runtime fallback to 
32-bit time syscalls, or would it also require a minimum kernel with 
64-bit time support rather than allowing older kernels from before the 
glibc port was added?

(Of course you can't really test this combination; it may fall to whoever 
adds the first such architecture port to glibc to get it working.)

Another consideration for such architectures is whether you end up with 
the combination of 64-bit time and 32-bit file offsets for them (given 
_TIME_BITS=64 requires _FILE_OFFSET_BITS=64, but here you have 64-bit time 
without defining _TIME_BITS).  It might make sense for such architectures 
also to use 64-bit offsets unconditionally, like 64-bit architectures do, 
so that defining _FILE_OFFSET_BITS=64 for them only affects mangling for a 
few types, not layout.


3. New 32-bit architectures (new in both kernel and glibc after the 
addition of 64-bit time support for 32-bit architectures in the kernel).

My expectation is that these will *only* have the new-named syscalls for 
64-bit time, not the old-named syscalls that use 32-bit time on 32-bit 
systems (and not the old syscall names but pointing to syscalls that use 
64-bit time, either).  Is that correct - new-named syscalls only for 
everything involving time on such architectures?

Then I'd expect those to look much like case 2b within glibc, except that 
arch_minimum_kernel would be recent enough that any code that might 
attempt to fall back to 32-bit-time syscalls would be compiled out.

> - Just #undef it in sysdeps/unix/sysv/linux/kernel-features.h even
>   though it is not #define'd elsewhere?

I think this, or a commented-out definition with the comment explaining 
the intended semantics.

> - #define it in sysdeps/unix/sysv/linux/kernel-features.h and then
>   #undef it in sysdeps/unix/sysv/linux/*/kernel-features.h, and later
>   when some architecture gets Y2038 syscall support, remove its #undef?

I'd hope all 32-bit architectures get kernel support at the same time.  
Is that the intent, or is something else intended?

If 64-bit architectures should have the macro undefined, then 
sysdeps/unix/sysv/linux/kernel-features.h will need to have a conditional 
deciding whether to undefine it, based on "is this an architecture for 
which the ordinary time syscalls always use 64-bit time_t?".  That 
conditional is *not* quite __WORDSIZE == 64, in that such a conditional 
would be wrong for x32, but it's also not __TIMESIZE == 64, if the answer 
for cases 2b and 3 above is that they would have __TIMESIZE == 64.  
Supposing that is indeed the case for cases 2b and 3, it would seem 
reasonable to use __WORDSIZE == 64 in the generic kernel-features.h and 
then override it in x86_64/kernel-features.h.  What we *don't* want is a 
situation where all future 32-bit architectures need to have their own 
overrides - the default case for future architectures must be not needing 
their own kernel-features.h file at all.
Albert ARIBAUD Sept. 25, 2018, 7:36 p.m. | #12
Hi Joseph,

CC:ing Arnd re whether all 32-bit architectures will get 64-bit-time
kernel support.

On Tue, 25 Sep 2018 17:25:39 +0000, Joseph Myers
<joseph@codesourcery.com> wrote :

> On Mon, 24 Sep 2018, Albert ARIBAUD wrote:
> 
> > > There should be an __ASSUME_* macro that kernel-features.h defines when 
> > > the minimum kernel version has the required feature.  Calls to these APIs 
> > > need to become compile-time constants in that case, with the functions / 
> > > variables not existing in the glibc binaries at all.  
> > 
> > Ok, how about __ASSUME_KERNEL_Y2038_SUPPORT?
> > 
> > In case it is not defined, then all Y2038 feature support calls would
> > return 'no support'.  
> 
> Well, normally "not defined" for __ASSUME_* doesn't mean "no support"; it 
> means "support may or may not be present, and needs to be tested for at 
> runtime if the __NR_* macros in question are defined".

So, assuming V is the version at which 64-bit-time kernel support is
introduced for all architectures at the same time:

- if the minimal kernel version supported by glibc for a given
  architecture is less than V, then __ASSUME_KERNEL_Y2038_SUPPORT should
  be undefined and glibc should check dynamically whether the actual
  kernel it is running on has 64-bit-time support or not;

- if the minimal kernel version supported by glibc for a given
  architecture is V or greater, then __ASSUME_KERNEL_Y2038_SUPPORT
  should be defined and glibc checks for support should be turned
  into constants so that 64-bit-time syscalls are systematically
  called.

Correct?

> Before we work out what the macro (or macros if more than one is needed) 
> is called, and the semantics of it being defined or undefined, we need to 
> have a clear understanding of the semantics.  And that in turn requires a 
> clear understanding of what the future kernel interfaces will be.
> 
> Could you provide a description of what the kernel interfaces will be in 
> future for each of the following cases (and any other significantly 
> different variants I've missed)?  Then, indicate whether you'd expect the 
> __ASSUME_* macro or macros to be defined in each of those cases.  
> Hopefully this will help clarify what the interfaces should look like 
> within glibc.  (This information will also need to go in the proposed 
> glibc commit messages for future versions of the present patch, and quite 
> likely some of it should go in comments in glibc code.)
> 
> 
> 1a. Existing 64-bit architectures, where 64-bit time_t is the only variant 
> supported, in both the kernel and (if those architectures already have 
> glibc ports) glibc.
> 
> My expectation is that these will *not* provide any new syscalls and will 
> *not* provide any new __NR_* aliases for existing syscalls.  Is that 
> correct?

Yes, that is correct.

> If so, would the __ASSUME_* macro be defined for those architectures or 
> not?  Whether it is or not, there must *not* be any new variables or 
> internal functions defined in glibc at all relating to Y2038 support, or 
> any additional levels of function calls / wrappers at runtime when 
> time-related glibc functions are used, given that there are no Y2038 
> problems for those architectures at present anyway.  (Avoiding such extra 
> code and data might involve e.g. __TIMESIZE conditionals.  Naturally it's 
> *also* desirable to design the implementation internals to reduce the 
> number of places needing such conditionals.)
> 
> 
> 1b. New 64-bit architectures (not currently supported in the kernel).
> 
> My expectation is that these will be the same as old ones - they will 
> provide the existing syscalls (minus obsolete ones), under their existing 
> names, not any new ones that explicitly reference 64-bit time.  Is that 
> correct?  If so, I'd expect them to look exactly like case 1a in glibc.

I think this is correct.

> 2a. Existing 32-bit architectures, supported in both the kernel and glibc 
> with 32-bit time_t.
> 
> These will all need to gain new syscalls under new names, with the new 
> macro defined when those syscalls are known to be available at runtime.

Correct.

> 2b. Existing 32-bit architectures, already supported in the kernel, but 
> not supported in glibc until after the 64-bit time support is present in 
> both places.
> 
> >From the point of view of the kernel, these should be exactly like case   
> 2a.  But from the point of view of glibc, they might be different - we 
> might want to support only 64-bit time for them (so __TIMESIZE would be 
> 64, and _TIME_BITS=64 would do nothing).  Is that what you'd intend for 
> such new architectures in glibc?  If so, presumably the __ASSUME_* macro 
> would still be defined for them, but the combination of that macro and 
> __TIMESIZE == 64 might end up doing different things in some places?  And 
> would the glibc port for such an architecture allow runtime fallback to 
> 32-bit time syscalls, or would it also require a minimum kernel with 
> 64-bit time support rather than allowing older kernels from before the 
> glibc port was added?
> 
> (Of course you can't really test this combination; it may fall to whoever 
> adds the first such architecture port to glibc to get it working.)
> 
> Another consideration for such architectures is whether you end up with 
> the combination of 64-bit time and 32-bit file offsets for them (given 
> _TIME_BITS=64 requires _FILE_OFFSET_BITS=64, but here you have 64-bit time 
> without defining _TIME_BITS).  It might make sense for such architectures 
> also to use 64-bit offsets unconditionally, like 64-bit architectures do, 
> so that defining _FILE_OFFSET_BITS=64 for them only affects mangling for a 
> few types, not layout.

As you point out, I won't test for this combination, but yes, my
opinion is that 32-bit architectures which are supported in the kernel
but not yet in glibc should only use 64-bit time syscalls when glibc
support is added.

> 3. New 32-bit architectures (new in both kernel and glibc after the 
> addition of 64-bit time support for 32-bit architectures in the kernel).
> 
> My expectation is that these will *only* have the new-named syscalls for 
> 64-bit time, not the old-named syscalls that use 32-bit time on 32-bit 
> systems (and not the old syscall names but pointing to syscalls that use 
> 64-bit time, either).  Is that correct - new-named syscalls only for 
> everything involving time on such architectures?

I think this is correct.

> Then I'd expect those to look much like case 2b within glibc, except that 
> arch_minimum_kernel would be recent enough that any code that might 
> attempt to fall back to 32-bit-time syscalls would be compiled out.
> 
> > - Just #undef it in sysdeps/unix/sysv/linux/kernel-features.h even
> >   though it is not #define'd elsewhere?  
> 
> I think this, or a commented-out definition with the comment explaining 
> the intended semantics.

Ok.

> > - #define it in sysdeps/unix/sysv/linux/kernel-features.h and then
> >   #undef it in sysdeps/unix/sysv/linux/*/kernel-features.h, and later
> >   when some architecture gets Y2038 syscall support, remove its #undef?  
> 
> I'd hope all 32-bit architectures get kernel support at the same time.  
> Is that the intent, or is something else intended?

Arnd would know this much better than I do.

> If 64-bit architectures should have the macro undefined, then 
> sysdeps/unix/sysv/linux/kernel-features.h will need to have a conditional 
> deciding whether to undefine it, based on "is this an architecture for 
> which the ordinary time syscalls always use 64-bit time_t?".  That 
> conditional is *not* quite __WORDSIZE == 64, in that such a conditional 
> would be wrong for x32, but it's also not __TIMESIZE == 64, if the answer 
> for cases 2b and 3 above is that they would have __TIMESIZE == 64.  
> Supposing that is indeed the case for cases 2b and 3, it would seem 
> reasonable to use __WORDSIZE == 64 in the generic kernel-features.h and 
> then override it in x86_64/kernel-features.h.  What we *don't* want is a 
> situation where all future 32-bit architectures need to have their own 
> overrides - the default case for future architectures must be not needing 
> their own kernel-features.h file at all.

Cordialement,
Albert ARIBAUD
3ADEV
Arnd Bergmann Sept. 25, 2018, 8:14 p.m. | #13
On Tue, Sep 25, 2018 at 9:36 PM Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
>
> CC:ing Arnd re whether all 32-bit architectures will get 64-bit-time
> kernel support.
>
> On Tue, 25 Sep 2018 17:25:39 +0000, Joseph Myers
> <joseph@codesourcery.com> wrote :
> > On Mon, 24 Sep 2018, Albert ARIBAUD wrote:
> > Before we work out what the macro (or macros if more than one is needed)
> > is called, and the semantics of it being defined or undefined, we need to
> > have a clear understanding of the semantics.  And that in turn requires a
> > clear understanding of what the future kernel interfaces will be.
> >
> > Could you provide a description of what the kernel interfaces will be in
> > future for each of the following cases (and any other significantly
> > different variants I've missed)?  Then, indicate whether you'd expect the
> > __ASSUME_* macro or macros to be defined in each of those cases.
> > Hopefully this will help clarify what the interfaces should look like
> > within glibc.  (This information will also need to go in the proposed
> > glibc commit messages for future versions of the present patch, and quite
> > likely some of it should go in comments in glibc code.)
> >
> >
> > 1a. Existing 64-bit architectures, where 64-bit time_t is the only variant
> > supported, in both the kernel and (if those architectures already have
> > glibc ports) glibc.
> >
> > My expectation is that these will *not* provide any new syscalls and will
> > *not* provide any new __NR_* aliases for existing syscalls.  Is that
> > correct?
>
> Yes, that is correct.

I was undecided on this issue actually: it does make some sense to
me to have the syscall macros be the same in the long run, so that
glibc doesn't have to pick between __NR_clock_gettime and
__NR_clock_gettime64 in a few years, after all supported kernels
support __NR_clock_gettime64. Also, 64-bit architectures won't
reuse the number space that we reserve for the new calls on 32-bit
architectures, so the addition is essentially free.

OTOH, it does seem a bit silly to have two syscall numbers that
point to the same symbol.

I don't have a strong preference here, and can do whichever
you like better in glibc.

> > If so, would the __ASSUME_* macro be defined for those architectures or
> > not?  Whether it is or not, there must *not* be any new variables or
> > internal functions defined in glibc at all relating to Y2038 support, or
> > any additional levels of function calls / wrappers at runtime when
> > time-related glibc functions are used, given that there are no Y2038
> > problems for those architectures at present anyway.  (Avoiding such extra
> > code and data might involve e.g. __TIMESIZE conditionals.  Naturally it's
> > *also* desirable to design the implementation internals to reduce the
> > number of places needing such conditionals.)
> >
> >
> > 1b. New 64-bit architectures (not currently supported in the kernel).
> >
> > My expectation is that these will be the same as old ones - they will
> > provide the existing syscalls (minus obsolete ones), under their existing
> > names, not any new ones that explicitly reference 64-bit time.  Is that
> > correct?  If so, I'd expect them to look exactly like case 1a in glibc.
>
> I think this is correct.

See above.

> > 2a. Existing 32-bit architectures, supported in both the kernel and glibc
> > with 32-bit time_t.
> >
> > These will all need to gain new syscalls under new names, with the new
> > macro defined when those syscalls are known to be available at runtime.
>
> Correct.

Right.

> > 2b. Existing 32-bit architectures, already supported in the kernel, but
> > not supported in glibc until after the 64-bit time support is present in
> > both places.
> >
> > >From the point of view of the kernel, these should be exactly like case
> > 2a.  But from the point of view of glibc, they might be different - we
> > might want to support only 64-bit time for them (so __TIMESIZE would be
> > 64, and _TIME_BITS=64 would do nothing).  Is that what you'd intend for
> > such new architectures in glibc?  If so, presumably the __ASSUME_* macro
> > would still be defined for them, but the combination of that macro and
> > __TIMESIZE == 64 might end up doing different things in some places?  And
> > would the glibc port for such an architecture allow runtime fallback to
> > 32-bit time syscalls, or would it also require a minimum kernel with
> > 64-bit time support rather than allowing older kernels from before the
> > glibc port was added?
> >
> > (Of course you can't really test this combination; it may fall to whoever
> > adds the first such architecture port to glibc to get it working.)
> >
> > Another consideration for such architectures is whether you end up with
> > the combination of 64-bit time and 32-bit file offsets for them (given
> > _TIME_BITS=64 requires _FILE_OFFSET_BITS=64, but here you have 64-bit time
> > without defining _TIME_BITS).  It might make sense for such architectures
> > also to use 64-bit offsets unconditionally, like 64-bit architectures do,
> > so that defining _FILE_OFFSET_BITS=64 for them only affects mangling for a
> > few types, not layout.
>
> As you point out, I won't test for this combination, but yes, my
> opinion is that 32-bit architectures which are supported in the kernel
> but not yet in glibc should only use 64-bit time syscalls when glibc
> support is added.

riscv32 falls into this category: there is preliminary kernel support
for it, but no upstream glibc. The riscv maintainers have indicated a
preference that they would actually want to drop the 32-bit time_t
syscalls from the kernel as well, since nobody is relying on them
today. I don't think it makes a difference to glibc, so we'll discuss this
among the kernel folks.

In general, we don't break established user ABIs as a rule, but we
also have lots of precedent for changing interfaces when we are
sure that there are no users that would complain about the change.

> > 3. New 32-bit architectures (new in both kernel and glibc after the
> > addition of 64-bit time support for 32-bit architectures in the kernel).
> >
> > My expectation is that these will *only* have the new-named syscalls for
> > 64-bit time, not the old-named syscalls that use 32-bit time on 32-bit
> > systems (and not the old syscall names but pointing to syscalls that use
> > 64-bit time, either).  Is that correct - new-named syscalls only for
> > everything involving time on such architectures?
>
> I think this is correct.

Yes, absolutely. Both csky and mips p32 will possibly fall into this
category, but it depends on how soon we can complete the addition
of the 64-bit time_t syscalls.

> > > - #define it in sysdeps/unix/sysv/linux/kernel-features.h and then
> > >   #undef it in sysdeps/unix/sysv/linux/*/kernel-features.h, and later
> > >   when some architecture gets Y2038 syscall support, remove its #undef?
> >
> > I'd hope all 32-bit architectures get kernel support at the same time.
> > Is that the intent, or is something else intended?
>
> Arnd would know this much better than I do.

I have planned to do it that way in the past, but with csky, mips-p32
and rv32 eager to change over as fast as they can, it seems more
likely now that there will be two steps here:

a) some architectures that only support 64-bit time_t from the start,
     possibly in linux-4.21
b) all other architectures supporting 64-bit time_t a little later, possibly
    4.22. This depends on work by Firoz Khan that is still under discussion
    at the moment.

There are also still a few open questions that we would need to resolve
in order to close in on the final ABI:

- The timex  structure for clock_adjtime64. I'd like to use the
   same version that x32 uses today, so we can avoid creating another
   32-bit compat interface for it. If there are any concerns with that,
   please let me know. In glibc, we will then have to change the
   __syscall_slong_t members of timex to a new type that is the
   same length as time_t.

- Whether to update itimerval (setitimer/getitimer) and rusage
  (getrusage, wait4, __kerrnel_waitid) or not. These only carry
  relative times, and they are in an awkward format (timeval).
  If we were to replace them, we'd probably want to use timespec
  on the syscall ABI, but that in turn means that glibc still
  requires a translation between the kernel structure and its
  own POSIX compatible structure. I'd appreciate to hear any
  opinions on this matter, one way or another, or alternative ideas.

- Whether to harmonize the existing syscall tables across all
  architectures while adding the new calls: I think this would be
  a good time to ensure that all architectures support all syscalls
  we have added over time, or at least define the number.
  This includes missing recent additions (io_pgetevents, rseq,
  fsinfo, ...) and those that may only exist as wrappers (ipc,
  socketcall) instead of direct entry points.

- In case we do harmonize the syscall tables, whether to go as
  far as using the same numbers for all of the new calls across
  the traditional architectures. E.g. clock_gettime64 could
  become 400 on x86, sparc, ppc, mips, ia64, etc and be
  followed by other 20 new calls with identical numbers.
  For the generic syscall ABI (arm64, openrisc, riscv, arc, ...)
  we'd probably use lower numbers to avoid a big gap, but at
  least that makes it only two possible numbers instead of 12
  for each call.

       Arnd
Joseph Myers Sept. 25, 2018, 8:16 p.m. | #14
On Tue, 25 Sep 2018, Albert ARIBAUD wrote:

> So, assuming V is the version at which 64-bit-time kernel support is
> introduced for all architectures at the same time:
> 
> - if the minimal kernel version supported by glibc for a given
>   architecture is less than V, then __ASSUME_KERNEL_Y2038_SUPPORT should
>   be undefined and glibc should check dynamically whether the actual
>   kernel it is running on has 64-bit-time support or not;
> 
> - if the minimal kernel version supported by glibc for a given
>   architecture is V or greater, then __ASSUME_KERNEL_Y2038_SUPPORT
>   should be defined and glibc checks for support should be turned
>   into constants so that 64-bit-time syscalls are systematically
>   called.
> 
> Correct?

Yes, subject to the question of what's appropriate on 64-bit architectures 
where time_t always has been 64-bit and the existing names of syscalls, 
not the new ones, are used for all time-related syscalls.  If 
__ASSUME_KERNEL_Y2038_SUPPORT means the syscalls with the new names are 
guaranteed to be present, then it should be undefined in that case because 
only the old names will be present (but also the variable etc. relating to 
runtime tests for support should not be declared at all, so if any code 
with such tests is - wrongly - compiled on such an architecture, it will 
fail to compile).
Joseph Myers Sept. 25, 2018, 8:25 p.m. | #15
On Tue, 25 Sep 2018, Joseph Myers wrote:

> Yes, subject to the question of what's appropriate on 64-bit architectures 
> where time_t always has been 64-bit and the existing names of syscalls, 
> not the new ones, are used for all time-related syscalls.  If 
> __ASSUME_KERNEL_Y2038_SUPPORT means the syscalls with the new names are 
> guaranteed to be present, then it should be undefined in that case because 
> only the old names will be present (but also the variable etc. relating to 
> runtime tests for support should not be declared at all, so if any code 
> with such tests is - wrongly - compiled on such an architecture, it will 
> fail to compile).

There is of course also a possible variant for 64-bit architectures if it 
proves better for the implementation:

* Make a glibc-internal header #define all the __NR_* for the new syscall 
names to point to the old names if the kernel headers don't do so.

* Define __ASSUME_KERNEL_Y2038_SUPPORT unconditionally for such 
architectures, because the syscalls in question are in fact old ones so 
always present at runtime.  (If the kernel headers might define the new 
__NR_* names *and point them to new syscall numbers*, it's more 
complicated, because in that case it would no longer be correct to assume 
the syscalls are available with an old kernel, but it would be completely 
useless to have runtime checks to decide between using old and new syscall 
numbers for the same syscall.  Also, if there are new syscalls that e.g. 
use timespec where existing ones use timeval and so are genuinely new even 
on 64-bit architectures, you'd end up needing to split 
__ASSUME_KERNEL_Y2038_SUPPORT into separate macros for the separate groups 
of syscalls.)
Joseph Myers Sept. 25, 2018, 8:30 p.m. | #16
On Tue, 25 Sep 2018, Arnd Bergmann wrote:

> riscv32 falls into this category: there is preliminary kernel support
> for it, but no upstream glibc. The riscv maintainers have indicated a
> preference that they would actually want to drop the 32-bit time_t
> syscalls from the kernel as well, since nobody is relying on them
> today. I don't think it makes a difference to glibc, so we'll discuss this
> among the kernel folks.
> 
> In general, we don't break established user ABIs as a rule, but we
> also have lots of precedent for changing interfaces when we are
> sure that there are no users that would complain about the change.

Depending on how long the glibc ports take to be ready (previously 
submitted, but without all the other upstream toolchain components being 
ready at the time), it could also apply to ARC and NDS32.  In the ARC 
case, the kernel port has been there for years, so unlike riscv32 I 
presume you couldn't remove the old syscalls from the kernel.
Palmer Dabbelt Sept. 25, 2018, 9:51 p.m. | #17
On Tue, 25 Sep 2018 13:14:38 PDT (-0700), Arnd Bergmann wrote:
> On Tue, Sep 25, 2018 at 9:36 PM Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
>>
>> CC:ing Arnd re whether all 32-bit architectures will get 64-bit-time
>> kernel support.
>>
>> On Tue, 25 Sep 2018 17:25:39 +0000, Joseph Myers
>> <joseph@codesourcery.com> wrote :
>> > On Mon, 24 Sep 2018, Albert ARIBAUD wrote:
>> > Before we work out what the macro (or macros if more than one is needed)
>> > is called, and the semantics of it being defined or undefined, we need to
>> > have a clear understanding of the semantics.  And that in turn requires a
>> > clear understanding of what the future kernel interfaces will be.
>> >
>> > Could you provide a description of what the kernel interfaces will be in
>> > future for each of the following cases (and any other significantly
>> > different variants I've missed)?  Then, indicate whether you'd expect the
>> > __ASSUME_* macro or macros to be defined in each of those cases.
>> > Hopefully this will help clarify what the interfaces should look like
>> > within glibc.  (This information will also need to go in the proposed
>> > glibc commit messages for future versions of the present patch, and quite
>> > likely some of it should go in comments in glibc code.)
>> >
>> >
>> > 1a. Existing 64-bit architectures, where 64-bit time_t is the only variant
>> > supported, in both the kernel and (if those architectures already have
>> > glibc ports) glibc.
>> >
>> > My expectation is that these will *not* provide any new syscalls and will
>> > *not* provide any new __NR_* aliases for existing syscalls.  Is that
>> > correct?
>>
>> Yes, that is correct.
>
> I was undecided on this issue actually: it does make some sense to
> me to have the syscall macros be the same in the long run, so that
> glibc doesn't have to pick between __NR_clock_gettime and
> __NR_clock_gettime64 in a few years, after all supported kernels
> support __NR_clock_gettime64. Also, 64-bit architectures won't
> reuse the number space that we reserve for the new calls on 32-bit
> architectures, so the addition is essentially free.
>
> OTOH, it does seem a bit silly to have two syscall numbers that
> point to the same symbol.
>
> I don't have a strong preference here, and can do whichever
> you like better in glibc.
>
>> > If so, would the __ASSUME_* macro be defined for those architectures or
>> > not?  Whether it is or not, there must *not* be any new variables or
>> > internal functions defined in glibc at all relating to Y2038 support, or
>> > any additional levels of function calls / wrappers at runtime when
>> > time-related glibc functions are used, given that there are no Y2038
>> > problems for those architectures at present anyway.  (Avoiding such extra
>> > code and data might involve e.g. __TIMESIZE conditionals.  Naturally it's
>> > *also* desirable to design the implementation internals to reduce the
>> > number of places needing such conditionals.)
>> >
>> >
>> > 1b. New 64-bit architectures (not currently supported in the kernel).
>> >
>> > My expectation is that these will be the same as old ones - they will
>> > provide the existing syscalls (minus obsolete ones), under their existing
>> > names, not any new ones that explicitly reference 64-bit time.  Is that
>> > correct?  If so, I'd expect them to look exactly like case 1a in glibc.
>>
>> I think this is correct.
>
> See above.
>
>> > 2a. Existing 32-bit architectures, supported in both the kernel and glibc
>> > with 32-bit time_t.
>> >
>> > These will all need to gain new syscalls under new names, with the new
>> > macro defined when those syscalls are known to be available at runtime.
>>
>> Correct.
>
> Right.
>
>> > 2b. Existing 32-bit architectures, already supported in the kernel, but
>> > not supported in glibc until after the 64-bit time support is present in
>> > both places.
>> >
>> > >From the point of view of the kernel, these should be exactly like case
>> > 2a.  But from the point of view of glibc, they might be different - we
>> > might want to support only 64-bit time for them (so __TIMESIZE would be
>> > 64, and _TIME_BITS=64 would do nothing).  Is that what you'd intend for
>> > such new architectures in glibc?  If so, presumably the __ASSUME_* macro
>> > would still be defined for them, but the combination of that macro and
>> > __TIMESIZE == 64 might end up doing different things in some places?  And
>> > would the glibc port for such an architecture allow runtime fallback to
>> > 32-bit time syscalls, or would it also require a minimum kernel with
>> > 64-bit time support rather than allowing older kernels from before the
>> > glibc port was added?
>> >
>> > (Of course you can't really test this combination; it may fall to whoever
>> > adds the first such architecture port to glibc to get it working.)
>> >
>> > Another consideration for such architectures is whether you end up with
>> > the combination of 64-bit time and 32-bit file offsets for them (given
>> > _TIME_BITS=64 requires _FILE_OFFSET_BITS=64, but here you have 64-bit time
>> > without defining _TIME_BITS).  It might make sense for such architectures
>> > also to use 64-bit offsets unconditionally, like 64-bit architectures do,
>> > so that defining _FILE_OFFSET_BITS=64 for them only affects mangling for a
>> > few types, not layout.
>>
>> As you point out, I won't test for this combination, but yes, my
>> opinion is that 32-bit architectures which are supported in the kernel
>> but not yet in glibc should only use 64-bit time syscalls when glibc
>> support is added.
>
> riscv32 falls into this category: there is preliminary kernel support
> for it, but no upstream glibc. The riscv maintainers have indicated a
> preference that they would actually want to drop the 32-bit time_t
> syscalls from the kernel as well, since nobody is relying on them
> today. I don't think it makes a difference to glibc, so we'll discuss this
> among the kernel folks.
>
> In general, we don't break established user ABIs as a rule, but we
> also have lots of precedent for changing interfaces when we are
> sure that there are no users that would complain about the change.

Obviously I'm OK deferring to kernel policy here, but my understanding of the 
rv32 situation is that we decided the rv32 kernel ABI is not stable and will 
not be marked as stable until our glibc port is upstream -- much the same as we 
did for the rv64 port.  This came up outside the context of 32-bit time_t, but 
I forget what the actual issue is.  That's what I've been telling people in 
RISC-V land.

I think I'll just start a Linux thread about this, as like you said there isn't 
a whole lot of glibc involvement here.

>> > 3. New 32-bit architectures (new in both kernel and glibc after the
>> > addition of 64-bit time support for 32-bit architectures in the kernel).
>> >
>> > My expectation is that these will *only* have the new-named syscalls for
>> > 64-bit time, not the old-named syscalls that use 32-bit time on 32-bit
>> > systems (and not the old syscall names but pointing to syscalls that use
>> > 64-bit time, either).  Is that correct - new-named syscalls only for
>> > everything involving time on such architectures?
>>
>> I think this is correct.
>
> Yes, absolutely. Both csky and mips p32 will possibly fall into this
> category, but it depends on how soon we can complete the addition
> of the 64-bit time_t syscalls.
>
>> > > - #define it in sysdeps/unix/sysv/linux/kernel-features.h and then
>> > >   #undef it in sysdeps/unix/sysv/linux/*/kernel-features.h, and later
>> > >   when some architecture gets Y2038 syscall support, remove its #undef?
>> >
>> > I'd hope all 32-bit architectures get kernel support at the same time.
>> > Is that the intent, or is something else intended?
>>
>> Arnd would know this much better than I do.
>
> I have planned to do it that way in the past, but with csky, mips-p32
> and rv32 eager to change over as fast as they can, it seems more
> likely now that there will be two steps here:
>
> a) some architectures that only support 64-bit time_t from the start,
>      possibly in linux-4.21
> b) all other architectures supporting 64-bit time_t a little later, possibly
>     4.22. This depends on work by Firoz Khan that is still under discussion
>     at the moment.
>
> There are also still a few open questions that we would need to resolve
> in order to close in on the final ABI:
>
> - The timex  structure for clock_adjtime64. I'd like to use the
>    same version that x32 uses today, so we can avoid creating another
>    32-bit compat interface for it. If there are any concerns with that,
>    please let me know. In glibc, we will then have to change the
>    __syscall_slong_t members of timex to a new type that is the
>    same length as time_t.
>
> - Whether to update itimerval (setitimer/getitimer) and rusage
>   (getrusage, wait4, __kerrnel_waitid) or not. These only carry
>   relative times, and they are in an awkward format (timeval).
>   If we were to replace them, we'd probably want to use timespec
>   on the syscall ABI, but that in turn means that glibc still
>   requires a translation between the kernel structure and its
>   own POSIX compatible structure. I'd appreciate to hear any
>   opinions on this matter, one way or another, or alternative ideas.
>
> - Whether to harmonize the existing syscall tables across all
>   architectures while adding the new calls: I think this would be
>   a good time to ensure that all architectures support all syscalls
>   we have added over time, or at least define the number.
>   This includes missing recent additions (io_pgetevents, rseq,
>   fsinfo, ...) and those that may only exist as wrappers (ipc,
>   socketcall) instead of direct entry points.
>
> - In case we do harmonize the syscall tables, whether to go as
>   far as using the same numbers for all of the new calls across
>   the traditional architectures. E.g. clock_gettime64 could
>   become 400 on x86, sparc, ppc, mips, ia64, etc and be
>   followed by other 20 new calls with identical numbers.
>   For the generic syscall ABI (arm64, openrisc, riscv, arc, ...)
>   we'd probably use lower numbers to avoid a big gap, but at
>   least that makes it only two possible numbers instead of 12
>   for each call.
>
>        Arnd
Arnd Bergmann Sept. 26, 2018, 7:20 a.m. | #18
On Tue, Sep 25, 2018 at 10:31 PM Joseph Myers <joseph@codesourcery.com> wrote:
>
> On Tue, 25 Sep 2018, Arnd Bergmann wrote:
>
> > riscv32 falls into this category: there is preliminary kernel support
> > for it, but no upstream glibc. The riscv maintainers have indicated a
> > preference that they would actually want to drop the 32-bit time_t
> > syscalls from the kernel as well, since nobody is relying on them
> > today. I don't think it makes a difference to glibc, so we'll discuss this
> > among the kernel folks.
> >
> > In general, we don't break established user ABIs as a rule, but we
> > also have lots of precedent for changing interfaces when we are
> > sure that there are no users that would complain about the change.
>
> Depending on how long the glibc ports take to be ready (previously
> submitted, but without all the other upstream toolchain components being
> ready at the time), it could also apply to ARC and NDS32.  In the ARC
> case, the kernel port has been there for years, so unlike riscv32 I
> presume you couldn't remove the old syscalls from the kernel.

For ARC that is clearly the case, yes. For nds32, we have an
existing uclibc-ng mainline port that uses the current syscall
ABI, which I see as enough precedent that I would not consider
doing an incompatible change any more, but glibc can simply
pretend that the time32 interfaces never existed on this.

       Arnd
Albert ARIBAUD Sept. 26, 2018, 8:06 a.m. | #19
Hi Joseph,

On Tue, 25 Sep 2018 20:25:22 +0000, Joseph Myers
<joseph@codesourcery.com> wrote :

> On Tue, 25 Sep 2018, Joseph Myers wrote:
> 
> > Yes, subject to the question of what's appropriate on 64-bit architectures 
> > where time_t always has been 64-bit and the existing names of syscalls, 
> > not the new ones, are used for all time-related syscalls.  If 
> > __ASSUME_KERNEL_Y2038_SUPPORT means the syscalls with the new names are 
> > guaranteed to be present, then it should be undefined in that case because 
> > only the old names will be present (but also the variable etc. relating to 
> > runtime tests for support should not be declared at all, so if any code 
> > with such tests is - wrongly - compiled on such an architecture, it will 
> > fail to compile).  
> 
> There is of course also a possible variant for 64-bit architectures if it 
> proves better for the implementation:
> 
> * Make a glibc-internal header #define all the __NR_* for the new syscall 
> names to point to the old names if the kernel headers don't do so.
> 
> * Define __ASSUME_KERNEL_Y2038_SUPPORT unconditionally for such 
> architectures, because the syscalls in question are in fact old ones so 
> always present at runtime.  (If the kernel headers might define the new 
> __NR_* names *and point them to new syscall numbers*, it's more 
> complicated, because in that case it would no longer be correct to assume 
> the syscalls are available with an old kernel, but it would be completely 
> useless to have runtime checks to decide between using old and new syscall 
> numbers for the same syscall.  Also, if there are new syscalls that e.g. 
> use timespec where existing ones use timeval and so are genuinely new even 
> on 64-bit architectures, you'd end up needing to split 
> __ASSUME_KERNEL_Y2038_SUPPORT into separate macros for the separate groups 
> of syscalls.)

I don't think 64-bit architectures will get the new __NR_* names, but
if they do, I think that they will point to the old numbers, i.e.,
Y2038 support should not introduce new syscalls on 64-bit
architectures (as these syscalls would basically be the same as
existing ones).

So I would tend to favor your variant approach above, as it makes the
semantics of __ASSUME_KERNEL_Y2038_SUPPORT simpler:

- if defined, we just use the new __NR_* names and 64-bit times, even
  for 64-bit architectures (with new names mapped to old names/numbers
  either by the kernel or by us);

- if undefined, we try the new names and numbers and on ENOSYS we fall
  back to the old names and numbers. 

Cordialement,
Albert ARIBAUD
3ADEV
Florian Weimer Sept. 26, 2018, 8:18 a.m. | #20
* Albert ARIBAUD:

> Hi Florian,
>
> On Tue, 25 Sep 2018 12:58:25 +0200, Florian Weimer <fweimer@redhat.com>
> wrote :
>
>> * Albert ARIBAUD:
>> 
>> > - one new boolean for every new feature, which libc can read/write.
>> >   Reading happens every time the feature is used.
>> >   Writing happens very rarely, once when first first using / testing for
>> >   the feature (e.g. at application start), once if using the feature
>> >   fails (e.g. a syscall returns ENOSYS).
>> >
>> > - two accessors (getter/setter) for every new feature if it must be
>> >   read/set from another glibc library than libc (e.g. librt).  
>> 
>> I'm still surprised that this is needed.  Why can't applications call
>> the function in question and react to a well-documented error code?
>
> These features are for glibc rather than for applications; they are
> here for glibc to remember whether a Y2038 feature is available in the
> kernel over which it currently runs.

Okay, that makes sense.

> Applications, on the other hand, would call the 64-bit-time interface
> regardless of the feature state. Whether this call would translate
> into 64-bit-time or 32-bit-time syscalls would be invisible to them. 

Presumably, there's still the matter of ioctl and ancillary messages on
sockets.

Thanks,
Florian
Arnd Bergmann Sept. 26, 2018, 8:40 a.m. | #21
On Wed, Sep 26, 2018 at 10:19 AM Florian Weimer <fweimer@redhat.com> wrote:
> * Albert ARIBAUD:
> > On Tue, 25 Sep 2018 12:58:25 +0200, Florian Weimer <fweimer@redhat.com>
> > Applications, on the other hand, would call the 64-bit-time interface
> > regardless of the feature state. Whether this call would translate
> > into 64-bit-time or 32-bit-time syscalls would be invisible to them.
>
> Presumably, there's still the matter of ioctl and ancillary messages on
> sockets.

Right, I don't think there is a solution for those; running an application
with 64-bit time_t on an old kernel is something we can't really support.
glibc can make it mostly work, and we can try to backport patches to
device drivers where needed, but this will remain incomplete.

My expectation however is that the kernel can return an appropriate
error code (-ENOTTY, -EINVAL, -ENOSYS) for each such case, so
at least it will be easy enough to debug.

Also, we have to make a hard requirement of using kernel
headers from a fixed version for building the application, so things
like ioctl command numbers, magic mmap() offsets and setsockopt
options can take the right values depending on sizeof(time_t)
to let the kernel know which ABI the user expects.

       Arnd
Albert ARIBAUD Sept. 26, 2018, 8:48 a.m. | #22
Hi Joseph,

On Wed, 19 Sep 2018 13:03:21 +0000, Joseph Myers
<joseph@codesourcery.com> wrote :

> On Wed, 19 Sep 2018, Albert ARIBAUD (3ADEV) wrote:
> 
> > * New function __y2038_get_kernel_support() returns:
> >   * 0 if the underlying kernel does not support Y2038 at all
> >   * > 0 if the underlying kernel has some support for Y2038
> >   * < 0 if the underlying kernel support for Y2038 is broken
> > * New function __y2038_set_kernel_support() allows indicating
> >   a kernel's Y2038 support (or support failure)
> > * Default implementation (covering non-Linux kernels) always
> >   returns 0 (no support).  
> 
> There should be an __ASSUME_* macro that kernel-features.h defines when 
> the minimum kernel version has the required feature.  Calls to these APIs 
> need to become compile-time constants in that case, with the functions / 
> variables not existing in the glibc binaries at all.

If __ASSUME_KERNEL_Y2038_SUPPORT is defined, then variables and
functions should not be defined at all in the glibc binaries, but I
don't think we need to make calls to these APIs compile-constant in
that case, because there should not be any such calls.

Any code which would depend on __ASSUME_KERNEL_Y2038_SUPPORT to call
either the new 64-bit-time syscall or old 32-bit-time syscall would
basically follow this pattern:

  #ifdef __ASSUME_KERNEL_Y2038_SUPPORT
    unconditionally call new __NR_* syscall using 64-bit-time(s),
    with no fallback on ENOSYS;
  #else
    if __y2038_get_kernel_support() indicates support:
      call new __NR_* syscall with 64-bit time(s);
      if ENOSYS:
        call __y2038_set_kernel_support() to indicate failure;
        perform pre-call 64-to-32-bit time conversions if any;
        call old __NR_* syscall with 32-bit time(s);
        perform post-call 32-to-64-bit time conversions if any.
    else:
      perform pre-call 64-to-32-bit time conversions if any;
      call old __NR_* syscall with 32-bit time(s);
      perform post-call 32-to-64-bit time conversions if any.
  #endif

The 'then' part of the '#if' does not contain any calls to
__y2038_{get,set}_kernel_support() because there is no need for them.

More precisely, the utility of __y2038_get_kernel_support() and
__y2038_set_kernel_support() appears only when we could use either
32-bit-time or 64-bit-time syscalls. We want to try the 64-bit-time
syscalls first because we prefer them and they /may/ be available in
the underlying kernel, but as soon as we learn that 64-bit-time
syscalls are not provided, then we want to stop trying them, and go
straight to 32-bit-time syscalls.

So when __ASSUME_KERNEL_Y2038_SUPPORT is defined, we assume the
64-bit-time syscalls /are/ there, and we don't drop into using
32-bit-time-only anymore; and no falling back means no need to remember
whether we need to fall back later -- i.e., we don't need to call
__y2038_{get,set}_kernel_support() at all.

Cordialement,
Albert ARIBAUD
3ADEV
Albert ARIBAUD Sept. 26, 2018, 8:53 a.m. | #23
Hi Arnd,

Le Wed, 26 Sep 2018 10:40:48 +0200, Arnd Bergmann <arnd@arndb.de> a
écrit :

> Also, we have to make a hard requirement of using kernel
> headers from a fixed version for building the application, so things
> like ioctl command numbers, magic mmap() offsets and setsockopt
> options can take the right values depending on sizeof(time_t)
> to let the kernel know which ABI the user expects.

Since Y2038-proof glibc will require a minimum kernel version to
build that is Y2038-proof too (as glibc will need to use the new __NR_*
syscall names defined by the kernel). Isn't that requirement enough? 

Cordialement,
Albert ARIBAUD
3ADEV
Arnd Bergmann Sept. 26, 2018, 9:02 a.m. | #24
On Wed, Sep 26, 2018 at 10:54 AM Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
>
> Hi Arnd,
>
> Le Wed, 26 Sep 2018 10:40:48 +0200, Arnd Bergmann <arnd@arndb.de> a
> écrit :
>
> > Also, we have to make a hard requirement of using kernel
> > headers from a fixed version for building the application, so things
> > like ioctl command numbers, magic mmap() offsets and setsockopt
> > options can take the right values depending on sizeof(time_t)
> > to let the kernel know which ABI the user expects.
>
> Since Y2038-proof glibc will require a minimum kernel version to
> build that is Y2038-proof too (as glibc will need to use the new __NR_*
> syscall names defined by the kernel). Isn't that requirement enough?

Yes, we just have to ensure that the headers contain both the
syscall number definitions and the updated driver headers. It
may be that we get the syscall definitions first (some driver interface
changes are still under discussion, or stalled), and one has to
ensure that they don't install older kernel headers together with
a glibc that has been built against the newer version.

     Arnd
Albert ARIBAUD Sept. 26, 2018, 9:25 a.m. | #25
Hi Arnd,

On Wed, 26 Sep 2018 11:02:55 +0200, Arnd Bergmann <arnd@arndb.de>
wrote :

> On Wed, Sep 26, 2018 at 10:54 AM Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
> >
> > Hi Arnd,
> >
> > Le Wed, 26 Sep 2018 10:40:48 +0200, Arnd Bergmann <arnd@arndb.de> a
> > écrit :
> >  
> > > Also, we have to make a hard requirement of using kernel
> > > headers from a fixed version for building the application, so things
> > > like ioctl command numbers, magic mmap() offsets and setsockopt
> > > options can take the right values depending on sizeof(time_t)
> > > to let the kernel know which ABI the user expects.  
> >
> > Since Y2038-proof glibc will require a minimum kernel version to
> > build that is Y2038-proof too (as glibc will need to use the new __NR_*
> > syscall names defined by the kernel). Isn't that requirement enough?  
> 
> Yes, we just have to ensure that the headers contain both the
> syscall number definitions and the updated driver headers. It
> may be that we get the syscall definitions first (some driver interface
> changes are still under discussion, or stalled), and one has to
> ensure that they don't install older kernel headers together with
> a glibc that has been built against the newer version.

"One" here can only be the end user. The best glibc could do would
be to include usr/include/linux/version.h and check LINUX_VERSION_CODE
against a decided-upon minimum version, but maybe the kernel headers
are not there when the public glibc headers are included by an
application source file, so we can't even do that.

Cordialement,
Albert ARIBAUD
3ADEV
Joseph Myers Sept. 26, 2018, 4:19 p.m. | #26
On Wed, 26 Sep 2018, Albert ARIBAUD wrote:

> I don't think 64-bit architectures will get the new __NR_* names, but
> if they do, I think that they will point to the old numbers, i.e.,
> Y2038 support should not introduce new syscalls on 64-bit
> architectures (as these syscalls would basically be the same as
> existing ones).

This is where Arnd said in 
<https://sourceware.org/ml/libc-alpha/2018-09/msg00452.html> he was 
undecided.

Having new numbers for the old syscalls doesn't provide anything useful to 
glibc since we'd want in some cases to avoid using those new numbers.  
Having new names for the old syscall numbers is fairly harmless; it might 
simplify some code in glibc if it means __ASSUME_KERNEL_Y2038_SUPPORT can 
be defined for 64-bit, but it might also complicate things (glibc would 
need to define the new names to the old ones when building with old kernel 
headers, __ASSUME_KERNEL_Y2038_SUPPORT would probably need to be split 
into two if there are genuinely new syscalls for 64-bit for the itimerval 
/ rusage cases).

> - if undefined, we try the new names and numbers and on ENOSYS we fall
>   back to the old names and numbers. 

With of course compile-time conditionals to handle the case when the new 
names aren't defined at all, so we can only use the old syscalls without 
such runtime conditionals.
Joseph Myers Sept. 26, 2018, 4:24 p.m. | #27
On Wed, 26 Sep 2018, Albert ARIBAUD wrote:

>   #else
>     if __y2038_get_kernel_support() indicates support:
>       call new __NR_* syscall with 64-bit time(s);
>       if ENOSYS:
>         call __y2038_set_kernel_support() to indicate failure;
>         perform pre-call 64-to-32-bit time conversions if any;
>         call old __NR_* syscall with 32-bit time(s);
>         perform post-call 32-to-64-bit time conversions if any.
>     else:

This first part also needs further conditionals to disable it altogether 
if the __NR_* for the new syscall isn't defined.  (Actually it might just 
be the

>     if __y2038_get_kernel_support() indicates support:
>       call new __NR_* syscall with 64-bit time(s);
>       if ENOSYS:
>         call __y2038_set_kernel_support() to indicate failure;

that's conditional in the source code, and maybe some open/close braces, 
so that the logic for using the 32-bit syscalls only appears once.)
Albert ARIBAUD Dec. 5, 2018, 11:49 a.m. | #28
Hi Arnd,

On Tue, 25 Sep 2018 22:14:38 +0200, Arnd Bergmann <arnd@arndb.de>
wrote :

> On Tue, Sep 25, 2018 at 9:36 PM Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
> >
> > CC:ing Arnd re whether all 32-bit architectures will get 64-bit-time
> > kernel support.
> >
> > On Tue, 25 Sep 2018 17:25:39 +0000, Joseph Myers
> > <joseph@codesourcery.com> wrote :  
> > > On Mon, 24 Sep 2018, Albert ARIBAUD wrote:
> > > Before we work out what the macro (or macros if more than one is needed)
> > > is called, and the semantics of it being defined or undefined, we need to
> > > have a clear understanding of the semantics.  And that in turn requires a
> > > clear understanding of what the future kernel interfaces will be.
> > >
> > > Could you provide a description of what the kernel interfaces will be in
> > > future for each of the following cases (and any other significantly
> > > different variants I've missed)?  Then, indicate whether you'd expect the
> > > __ASSUME_* macro or macros to be defined in each of those cases.
> > > Hopefully this will help clarify what the interfaces should look like
> > > within glibc.  (This information will also need to go in the proposed
> > > glibc commit messages for future versions of the present patch, and quite
> > > likely some of it should go in comments in glibc code.)
> > >
> > >
> > > 1a. Existing 64-bit architectures, where 64-bit time_t is the only variant
> > > supported, in both the kernel and (if those architectures already have
> > > glibc ports) glibc.
> > >
> > > My expectation is that these will *not* provide any new syscalls and will
> > > *not* provide any new __NR_* aliases for existing syscalls.  Is that
> > > correct?  
> >
> > Yes, that is correct.  
> 
> I was undecided on this issue actually: it does make some sense to
> me to have the syscall macros be the same in the long run, so that
> glibc doesn't have to pick between __NR_clock_gettime and
> __NR_clock_gettime64 in a few years, after all supported kernels
> support __NR_clock_gettime64. Also, 64-bit architectures won't
> reuse the number space that we reserve for the new calls on 32-bit
> architectures, so the addition is essentially free.
> 
> OTOH, it does seem a bit silly to have two syscall numbers that
> point to the same symbol.

I'd say this double naming would be justified by the will to transition
from the 'old' to the 'new' symbols.

> I don't have a strong preference here, and can do whichever
> you like better in glibc.

There does not seem to have been any other comment on this for a while, 
so, do we go for this approach? That is:

- on 64-bit architectures, the kernel will define _NR symbols identical
  to those added for Y2038, so that, for instance, on X86_64, there
  will be an _NR_clock_gettime64 symbol (which will point to the same
  syscall number as _NR_clock_gettime does).

- on 64-bit architectures, GLIBC will set __ASSUME_KERNEL_Y2038_SUPPORT
  once the minimal kernel supported version for these architectures
  provides the 'new' syscall symbols.

- on all architectures, if __ASSUME_KERNEL_Y2038_SUPPORT is defined,
  then GLIBC assumes the 'new' syscall symbols exist and can be used.

- on all architectures, if __ASSUME_KERNEL_Y2038_SUPPORT is NOT defined,
  then GLIBC will try to use new syscalls for which a _NR symbol is
  provided by the build-time kernel, and on ENOSYS, will fallback to old
  syscalls.

Cordialement,
Albert ARIBAUD
3ADEV
Joseph Myers Dec. 5, 2018, 1:18 p.m. | #29
On Wed, 5 Dec 2018, Albert ARIBAUD wrote:

> - on 64-bit architectures, GLIBC will set __ASSUME_KERNEL_Y2038_SUPPORT
>   once the minimal kernel supported version for these architectures
>   provides the 'new' syscall symbols.
> 
> - on all architectures, if __ASSUME_KERNEL_Y2038_SUPPORT is defined,
>   then GLIBC assumes the 'new' syscall symbols exist and can be used.
> 
> - on all architectures, if __ASSUME_KERNEL_Y2038_SUPPORT is NOT defined,
>   then GLIBC will try to use new syscalls for which a _NR symbol is
>   provided by the build-time kernel, and on ENOSYS, will fallback to old
>   syscalls.

There should be *no* new code in the glibc compiled for 64-bit 
architectures - no ENOSYS fallback, because none is needed.  __ASSUME_* is 
always about features to assume to be present in the kernel used at 
runtime, not about what __NR_* symbols are defined (however, the kernel 
headers used for compiling glibc must always be at least as recent as the 
specified --enable-kernel version).
Arnd Bergmann Dec. 5, 2018, 1:33 p.m. | #30
On Wed, Dec 5, 2018 at 12:49 PM Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
> On Tue, 25 Sep 2018 22:14:38 +0200, Arnd Bergmann <arnd@arndb.de> wrote :
> > On Tue, Sep 25, 2018 at 9:36 PM Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
> > I was undecided on this issue actually: it does make some sense to
> > me to have the syscall macros be the same in the long run, so that
> > glibc doesn't have to pick between __NR_clock_gettime and
> > __NR_clock_gettime64 in a few years, after all supported kernels
> > support __NR_clock_gettime64. Also, 64-bit architectures won't
> > reuse the number space that we reserve for the new calls on 32-bit
> > architectures, so the addition is essentially free.
> >
> > I don't have a strong preference here, and can do whichever
> > you like better in glibc.
>
> There does not seem to have been any other comment on this for a while,
> so, do we go for this approach? That is:
>
> - on 64-bit architectures, the kernel will define _NR symbols identical
>   to those added for Y2038, so that, for instance, on X86_64, there
>   will be an _NR_clock_gettime64 symbol (which will point to the same
>   syscall number as _NR_clock_gettime does).

There are a few new considerations for things that happened over the
last few months, so I'd still like to get more people involved before
we finally decide on this one:

- For cleaning up the kernel headers to make them more easily
  usable in glibc, I think it makes a lot of sense to define the new
  new macro names (as I said above). If we do that, maybe we should
  do it for other system calls (not time related) as well, in particular
  fcntl64, {f,}statfs64, {f,}truncate64, llseek, sendfile64, fstat{at,}64,
  mmap2, and fadvise64 as well as the associated structures.
  I already plan to do it independently for socketcall and ipc, which
  should be replaced with the separate entry points whenever we
  have the recent enough kernel.

- The work that Firoz Khan did for generating the asm/unistd.h
  kernel headers and syscall tables on all architectures makes it
  a little awkward to redirect new syscall macros to existing numbers,
  as the table file format uses the number as the primary key.
  The most logical way to do this in the kernel now is actually to
  have the newly assigned number point to the same syscall
  implementation on all architectures, both 32-bit and 64-bit.
  Not providing the number on 64-bit at all is fairly easy, but the
  redirect would require a permanent workaround on ppc, sparc,
  parisc, s390, and riscv as well as any future 64-bit architectures.

- Any Lutomirksi has some ideas for cleaning up the x86 syscall
  table, which may be relevant here. Adding him to Cc.

> - on 64-bit architectures, GLIBC will set __ASSUME_KERNEL_Y2038_SUPPORT
>   once the minimal kernel supported version for these architectures
>   provides the 'new' syscall symbols.
>
> - on all architectures, if __ASSUME_KERNEL_Y2038_SUPPORT is defined,
>   then GLIBC assumes the 'new' syscall symbols exist and can be used.

We have a couple of system calls that we add even on 64-bit architectures,
including statx() and likely the new version of waitid()/getrusage().
I think for those the logic has to be different, so a 64-bit architecture
will have to e.g. fall back to calling fstatat() when statx() is unavailable
on an older kernel.

> - on all architectures, if __ASSUME_KERNEL_Y2038_SUPPORT is NOT defined,
>   then GLIBC will try to use new syscalls for which a _NR symbol is
>   provided by the build-time kernel, and on ENOSYS, will fallback to old
>   syscalls.

I think it's important that we only do this when we are called from
an application with 64-bit time_t: When a user calls gettimeofday()
with 64-bit time_t, that should try clock_gettime64(2) and fall back
to clock_gettime(2) or gettimeofday(2) if that is unavailable. However
an application using gettimeofday() with a 32-bit time_t should
directly call gettimeofday(2) in the kernel but not try clock_gettime64()
first. Without that distinction, the kernel cannot return -ENOSYS
if we configure it to break compatibility with 32-bit time_t interfaces
and the application might seem to work correctly despite being
broken in 2038.

      Arnd
Joseph Myers Dec. 5, 2018, 1:48 p.m. | #31
On Wed, 5 Dec 2018, Arnd Bergmann wrote:

>   The most logical way to do this in the kernel now is actually to
>   have the newly assigned number point to the same syscall
>   implementation on all architectures, both 32-bit and 64-bit.

If you have (redundant) new numbers on 64-bit, glibc should not use those 
at all on 64-bit until the minimum kernel version is new enough to be sure 
they are available, to avoid unnecessary runtime fallback code.  Cf. how 
on socketcall architectures it made sense to keep using just socketcall 
for accept4 / recvmmsg / sendmmsg, rather than using the separate syscalls 
with runtime fallback to socketcall (in the cases where syscalls were 
added later than socketcall support), unless the configured minimum kernel 
version is recent enough to ensure the syscall is available.

(That does not prevent glibc having local #undef / #define to be able to 
use the new *names* unconditionally while still using the old numbers, if 
that proves useful.)

> I think it's important that we only do this when we are called from
> an application with 64-bit time_t: When a user calls gettimeofday()
> with 64-bit time_t, that should try clock_gettime64(2) and fall back
> to clock_gettime(2) or gettimeofday(2) if that is unavailable. However
> an application using gettimeofday() with a 32-bit time_t should
> directly call gettimeofday(2) in the kernel but not try clock_gettime64()
> first. Without that distinction, the kernel cannot return -ENOSYS
> if we configure it to break compatibility with 32-bit time_t interfaces
> and the application might seem to work correctly despite being
> broken in 2038.

By design, all nontrivial 32-bit time interfaces in glibc for 32-bit 
architectures should end up as simple wrappers round the implementations 
using 64-bit time internally, to avoid duplication of complicated code 
(previous versions of the Y2038 patches e.g. duplicated hundreds of lines 
of pthread_mutex_timedlock implementation, which is clearly not a 
maintainable approach).  That means many 32-bit interfaces *will* end up 
using 64-bit syscalls (with fallback to 32-bit if the 64-bit syscalls are 
unavailable at runtime), even if some simple functions that really are 
just one syscall for 32-bit still call the old syscall.
Arnd Bergmann Dec. 5, 2018, 2:26 p.m. | #32
On Wed, Dec 5, 2018 at 2:48 PM Joseph Myers <joseph@codesourcery.com> wrote:
> On Wed, 5 Dec 2018, Arnd Bergmann wrote:
>
> > I think it's important that we only do this when we are called from
> > an application with 64-bit time_t: When a user calls gettimeofday()
> > with 64-bit time_t, that should try clock_gettime64(2) and fall back
> > to clock_gettime(2) or gettimeofday(2) if that is unavailable. However
> > an application using gettimeofday() with a 32-bit time_t should
> > directly call gettimeofday(2) in the kernel but not try clock_gettime64()
> > first. Without that distinction, the kernel cannot return -ENOSYS
> > if we configure it to break compatibility with 32-bit time_t interfaces
> > and the application might seem to work correctly despite being
> > broken in 2038.
>
> By design, all nontrivial 32-bit time interfaces in glibc for 32-bit
> architectures should end up as simple wrappers round the implementations
> using 64-bit time internally, to avoid duplication of complicated code
> (previous versions of the Y2038 patches e.g. duplicated hundreds of lines
> of pthread_mutex_timedlock implementation, which is clearly not a
> maintainable approach).  That means many 32-bit interfaces *will* end up
> using 64-bit syscalls (with fallback to 32-bit if the 64-bit syscalls are
> unavailable at runtime), even if some simple functions that really are
> just one syscall for 32-bit still call the old syscall.

That would make it very hard to deploy a glibc based system
with strict y2038 requirements. If we can no longer guarantee the
basic assumption that old applications keep using the old system
calls, then I think we instead need a way to build glibc itself without
support for the 32-bit time_t interfaces, e.g. using a --disable-time32
configuration switch to force a link-time error for any application
or library that has not been built against the 64-bit time_t interfaces.

The default would of course remain providing backwards compatibility
with all applications to allow a gradual migration from 32-bit time_t
to 64-bit time_t. If all 32-bit time_t calls are just wrappers around
either the internal implementation using 64-bit time_t or around
a simple system call, then it should at least be easy to make them
optional for users that need them not work.

Would that be something you can do?

      Arnd
Joseph Myers Dec. 5, 2018, 3:26 p.m. | #33
On Wed, 5 Dec 2018, Arnd Bergmann wrote:

> That would make it very hard to deploy a glibc based system
> with strict y2038 requirements. If we can no longer guarantee the
> basic assumption that old applications keep using the old system
> calls, then I think we instead need a way to build glibc itself without
> support for the 32-bit time_t interfaces, e.g. using a --disable-time32
> configuration switch to force a link-time error for any application
> or library that has not been built against the 64-bit time_t interfaces.

(There's never been a guarantee of keeping using the same system calls.  
Cf. people trying to restrict the system calls some code can use and 
running into issues with moves to use e.g. *at syscalls unconditionally on 
all architectures to implement the non-*at functions.)

The set of interfaces that involve 32-bit time_t or other structures 
including it is well-defined; an external checker can examine the dynamic 
symbol table of any dynamically linked 32-bit application or shared 
library to see if it has references to any of the symbols in question, 
without needing to run the code at all (and so detect issues in code that 
might not be frequently executed, not just in whatever code runs when 
you're testing for 32-bit time uses).  (Or if you control the build of the 
whole system, do a local change to make a glibc header use #error if 
_TIME_BITS is not defined to 64.)

I'd expect it to be a long time before we might consider making 32-bit 
time_t (and thus 32-bit off_t) subject to something like 
--enable-obsolete-rpc / --enable-obsolete-nsl being needed to make the 
32-bit interfaces available at (static) link time at all.

Patch

diff --git a/misc/Makefile b/misc/Makefile
index 9a87e81ae5..dd64bf256f 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -71,7 +71,7 @@  routines := brk sbrk sstk ioctl \
 	    fgetxattr flistxattr fremovexattr fsetxattr getxattr \
 	    listxattr lgetxattr llistxattr lremovexattr lsetxattr \
 	    removexattr setxattr getauxval ifunc-impl-list makedev \
-	    allocate_once
+	    allocate_once y2038-support
 
 generated += tst-error1.mtrace tst-error1-mem.out \
   tst-allocate_once.mtrace tst-allocate_once-mem.out
diff --git a/misc/Versions b/misc/Versions
index 900e4ffb79..e242bf7218 100644
--- a/misc/Versions
+++ b/misc/Versions
@@ -158,6 +158,10 @@  libc {
   GLIBC_2.26 {
     preadv2; preadv64v2; pwritev2; pwritev64v2;
   }
+  GLIBC_2.29 {
+    __y2038_get_kernel_support;
+    __y2038_set_kernel_support;
+  }
   GLIBC_PRIVATE {
     __madvise;
     __mktemp;
diff --git a/misc/y2038-support.c b/misc/y2038-support.c
new file mode 100644
index 0000000000..e401cb1112
--- /dev/null
+++ b/misc/y2038-support.c
@@ -0,0 +1,32 @@ 
+/* y2038 general kernel support indication.
+   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/>.  */
+
+/* By default glibc assumes the underlying kernel does not support Y2038 */ 
+int __default_y2038_get_kernel_support (void)
+{
+  return 0;
+}
+weak_alias (__default_y2038_get_kernel_support, __y2038_get_kernel_support)
+
+/* By default glibc just ignores Y2038 support indication setting */ 
+int __default_y2038_set_kernel_support (int new with __attribute__ ((unused)))
+{
+  return 0;
+}
+weak_alias (__default_y2038_set_kernel_support, __y2038_set_kernel_support)
diff --git a/misc/y2038-support.h b/misc/y2038-support.h
new file mode 100644
index 0000000000..ec7891b63b
--- /dev/null
+++ b/misc/y2038-support.h
@@ -0,0 +1,36 @@ 
+/* y2038 general kernel support indication.
+   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/>.  */
+
+/* Get Y2038 kernel support.
+ * 0 means no suppport
+ * > 0 means (some) support
+ * < 0 means support is broken
+ */
+extern int __y2038_get_kernel_support (void);
+
+/* Set Y2038 support.
+ * 0 means no suppport
+ * > 0 means (some) support
+ * < 0 means support is broken
+ * Architectures should call this with new > 0 as soon as they know that
+ * their underlying kernel has Y2038 support.
+ * Implementations should call this with new < 0 as soon as they detect
+ * that a Y2038 kernel support failure occurred.
+ * As a courtesy, the previous support indication is returned. */
+extern int __y2038_set_kernel_support (int new);
diff --git a/sysdeps/unix/sysv/linux/y2038-support.c b/sysdeps/unix/sysv/linux/y2038-support.c
new file mode 100644
index 0000000000..f325efc7d8
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/y2038-support.c
@@ -0,0 +1,40 @@ 
+/* y2038 Linux kernel support indication.
+   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/>.  */
+
+/* By default the underlying Linux kernel is assumed not to support Y2038.
+ * Any Linux architecture may claim Y2038 kernel support by setting
+ * __y2038_linux_support.
+ */
+int __y2038_linux_support = 0;
+
+/* For Linux, Y2038 kernel support is determined by __y2038_linux_support  */
+
+int __linux_y2038_get_kernel_support (void)
+{
+  return __y2038_linux_support;
+}
+strong_alias (__linux_y2038_get_kernel_support, __y2038_get_kernel_support)
+
+int __linux_y2038_set_kernel_support (int new)
+{
+  int previous = __y2038_linux_support;
+  __y2038_linux_support = new;
+  return previous;
+}
+strong_alias (__linux_y2038_set_kernel_support, __y2038_set_kernel_support)
diff --git a/sysdeps/unix/sysv/linux/y2038-support.h b/sysdeps/unix/sysv/linux/y2038-support.h
new file mode 100644
index 0000000000..7dcbe0b313
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/y2038-support.h
@@ -0,0 +1,30 @@ 
+/* y2038 Linux kernel support indication.
+   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/>.  */
+
+/* Indicates Y2038 support.
+ * 0 means no suppport
+ * > 0 means (some) support
+ * < 0 means support is broken
+ * Can be read directly from within libc linux-related files.
+ * Can be written non-zero to indicate support or lack thereof.
+ */
+extern int __y2038_linux_support;
+
+/* As a fallback, provide generic Y2038 support indication */
+#include <misc/y2038-support.h>