On Wed, Feb 22, 2017 at 4:39 PM, Arnd Bergmann arnd@arndb.de wrote:
I'll comment on the kernel/glibc incompatibilities section tomorrow, need to collect my thoughts there some more.
For build-time dependencies, any changes we do to the kernel headers should only add things for new glibc but leave the existing definitions unchanged as long as _TIME_BITS is not set to 64 on a 32-bit architecture.
In the few cases that can't be handled by simply adding new definitions, we need to replace e.g.
#define SIOCGSTAMPNS_OLD 0x8907
with something like
#define SIOCGSTAMPNS_OLD 0x8907 #define SIOCGSTAMPNS_TIME64 _IOR(0x89, 0x07, struct timespec) #define SIOCGSTAMPNS (sizeof(time_t) == sizeof(__kernel_long_t) ? \ SIOCGSTAMPNS_OLD : SIOCGSTAMPNS_TIME64)
This will define the constant to the traditional value for all existing libc implementations as well as new libc built without __USE_TIME_BITS64, but will use a newly defined value on new glibc with __USE_TIME_BITS64. If anyone tries to use the constant without first having included <time.h>, it will cause a compile-time error, which is probably the best we can do here (better than using an incorrect value).
There are other cases where we actually need to check _TIME_BITS, e.g.
#if defined(__KERNEL__) || \ (defined(_TIME_BITS) && (_TIME_BITS > __BITS_PER_LONG)) struct input_timeval { __u32 tv_sec; /* __u32 overflows in y2106 */ __s32 tv_usec; }; #else #define input_timeval timeval #endif
struct input_event { struct input_timeval time; __u16 type; __u16 code; __s32 value; }; #undef input_timeval
Here, we cannot change the binary layout of input_event as the kernel has no idea what kind of user space is running, but we have to prevent a new user space from using the definition based on an incompatible 'struct timeval'. In this case, it is safe to assume that either _TIME_BITS has been defined (on a new libc after including time.h to see 'struct timeval'), or that we are on an old libc with the traditional definition of timeval. Again, this is broken in a rare corner case: user space that assumes that input_event->time is a struct timeval, but this will cause a compile failure for incompatible types that I see now way around.
Both of the examples above will break silently when using an old version of the kernel header with _TIME_BITS=64. I would suggest to not allow building support for 64-bit time_t on a glibc with old kernel headers because of this, but I don't know how hard that is to do in glibc. It is probably safe to assume that kernel headers that define __NR_CLOCK_GETTIME64 in asm/unistd.h have a reasonable set of definitions in their other headers as well.
For run-time dependencies, glibc can try to support old kernels with new builds, but this support will not cover any interfaces that are not wrapped by glibc. With the above example fo SIOCGSTAMPNS, an application calling this ioctl on an old kernel will run into an error with errno=EINVAL. This can be mitigated by emulating a reasonable subset of the affected ioctl/fcntl/sockopts/etc calls in glibc, but it would be hard to guarantee that this works for every kernel subsystem and device driver.
The other interesting runtime case is a kernel that intentionally drops 32-bit time_t support in combination with an application that uses the _TIME_BITS=32 compatibility interfaces. In this case, we want any syscalls to fail rather than be emulated through the 64-bit calls. This should be the normal behavior with the implementation you describe, but I think it should be documented that this is intentional.
Arnd