This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
kernel/libc uapi changes for y2038
- From: Arnd Bergmann <arnd at arndb dot de>
- To: linux-api at vger dot kernel dot org
- Cc: libc-alpha at sourceware dot org, linux-kernel at vger dot kernel dot org, y2038 at lists dot linaro dot org, musl at lists dot openwall dot com, klibc at zytor dot com, cferris at google dot com, enh at google dot com, Rich Felker <dalias at libc dot org>, "Joseph S. Myers" <joseph at codesourcery dot com>
- Date: Mon, 18 May 2015 11:53:56 +0200
- Subject: kernel/libc uapi changes for y2038
- Authentication-results: sourceware.org; auth=none
In the patch series I posted recently [1], I introduce new system calls to deal
with modified data structures, but left the question open on how these should
be best accessed from libc. The patches introduce a new __kernel_time64_t type
and based on that five new data structured: struct __kernel_timespec,
struct __kernel_itimerspec, struct __kernel_stat, struct __kernel_rusage,
and struct __kernel_timex. This works fine for the case when all libc
implementations provide their own definitions to user space, but not for
the simplest case (e.g. klibc) where the user-visible structures come directly
from the kernel uapi headers.
I still don't know what model the various libc developers prefer, so here is
an alternative approach, as a patch on top of the previous series:
Now, we rename the original structures to struct __old_kernel_*, and use a
macro to define either the __old_kernel_* or the __kernel_* structure name
to the name we actually want in user space, based on a __KERNEL_TIME_BITS
macro that can be set to either 32 or 64 for 32-bit architectures by
the libc. Depending on that macro, the compiler will either see one
of these combinations (for each of the five structures):
a) __BITS_PER_LONG == 32 && __KERNEL_TIME_BITS == 32:
struct timespec based on 32-bit __kernel_time_t
struct __kernel_timespec based on 64-bit __kernel_time64_t
b) __BITS_PER_LONG == 64 && __KERNEL_TIME_BITS == 64:
struct timespec based on 64-bit __kernel_time_t
struct __kernel_timespec based on 64-bit __kernel_time64_t
c) __BITS_PER_LONG == 32 && __KERNEL_TIME_BITS == 64:
struct __old_kernel_timespec based on 32-bit __kernel_time_t
struct timespec based on 64-bit __kernel_time64_t
Would this work for everyone? Any alternative suggestions?
Arnd
[1] http://git.kernel.org/cgit/linux/kernel/git/arnd/playground.git/log/?h=y2038-syscalls
https://lwn.net/Articles/643407/
diff --git a/include/uapi/asm-generic/bitsperlong.h b/include/uapi/asm-generic/bitsperlong.h
index 23e6c416b85f..ecdaf4f77f35 100644
--- a/include/uapi/asm-generic/bitsperlong.h
+++ b/include/uapi/asm-generic/bitsperlong.h
@@ -12,4 +12,13 @@
#define __BITS_PER_LONG 32
#endif
+/*
+ * Traditionally we define defines 'time_t' as 'long', but we need to
+ * migrate to a 64-bit type until 2038. This one is designed to be
+ * overridden by user space if it's prepared to handle 64-bit time_t.
+ */
+#ifndef __KERNEL_TIME_BITS
+#define __KERNEL_TIME_BITS __BITS_PER_LONG
+#endif
+
#endif /* _UAPI__ASM_GENERIC_BITS_PER_LONG */
diff --git a/include/uapi/asm-generic/kernel_stat.h b/include/uapi/asm-generic/kernel_stat.h
index d1db22583046..3693496c78aa 100644
--- a/include/uapi/asm-generic/kernel_stat.h
+++ b/include/uapi/asm-generic/kernel_stat.h
@@ -1,6 +1,14 @@
#ifndef __ASM_GENERIC_KERNEL_STAT_H
#define __ASM_GENERIC_KERNEL_STAT_H
+#include <asm/bitsperlong.h>
+
+#if __KERNEL_TIME_BITS == 32 || __BITS_PER_LONG == 64
+#define __old_kernel_stat2 stat
+#else
+#define __kernel_stat stat
+#endif
+
/*
* The new structure that works on both 32-bit and 64-bit and survives y2038
* The layout matches 'struct stat' from asm-generic/stat.h on 64-bit
diff --git a/include/uapi/asm-generic/stat.h b/include/uapi/asm-generic/stat.h
index 64c32ba7c1a9..f66b28b96c8d 100644
--- a/include/uapi/asm-generic/stat.h
+++ b/include/uapi/asm-generic/stat.h
@@ -22,7 +22,7 @@
#define STAT_HAVE_NSEC 1
-struct stat {
+struct __old_kernel_stat2 {
unsigned long st_dev; /* Device. */
unsigned long st_ino; /* File serial number. */
unsigned int st_mode; /* File mode. */
diff --git a/include/uapi/linux/resource.h b/include/uapi/linux/resource.h
index c4f3ba44db00..9a3876cc4436 100644
--- a/include/uapi/linux/resource.h
+++ b/include/uapi/linux/resource.h
@@ -3,10 +3,16 @@
#include <linux/time.h>
#include <linux/types.h>
+#include <asm/bitsperlong.h>
/*
* Resource control/accounting header file for linux
*/
+#if __KERNEL_TIME_BITS == 32 || __BITS_PER_LONG == 64
+#define __old_kernel_rusage rusage
+#else
+#define __kernel_rusage rusage
+#endif
/*
* Definition of struct rusage taken from BSD 4.3 Reno
@@ -20,7 +26,7 @@
#define RUSAGE_BOTH (-2) /* sys_wait4() uses this */
#define RUSAGE_THREAD 1 /* only the calling thread */
-struct rusage {
+struct __old_kernel_rusage {
struct timeval ru_utime; /* user time used */
struct timeval ru_stime; /* system time used */
__kernel_long_t ru_maxrss; /* maximum resident set size */
diff --git a/include/uapi/linux/time.h b/include/uapi/linux/time.h
index 72d894df3013..b3988606128f 100644
--- a/include/uapi/linux/time.h
+++ b/include/uapi/linux/time.h
@@ -6,11 +6,24 @@
#ifndef _STRUCT_TIMESPEC
#define _STRUCT_TIMESPEC
-struct timespec {
+
+#if __KERNEL_TIME_BITS == 32 || __BITS_PER_LONG == 64
+#define __old_kernel_timespec timespec
+#else
+#define __kernel_timespec timespec
+#endif
+#endif
+
+#if __KERNEL_TIME_BITS == 32 || __BITS_PER_LONG == 64
+#define __old_kernel_itimerspec itimerspec
+#else
+#define __kernel_itimerspec itimerspec
+#endif
+
+struct __old_kernel_timespec {
__kernel_time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
-#endif
struct timeval {
__kernel_time_t tv_sec; /* seconds */
@@ -31,7 +44,7 @@ struct timezone {
#define ITIMER_VIRTUAL 1
#define ITIMER_PROF 2
-struct itimerspec {
+struct __old_kernel_itimerspec {
struct timespec it_interval; /* timer period */
struct timespec it_value; /* timer expiration */
};
diff --git a/include/uapi/linux/timex.h b/include/uapi/linux/timex.h
index 9b131f107ada..3cfa50caa77d 100644
--- a/include/uapi/linux/timex.h
+++ b/include/uapi/linux/timex.h
@@ -54,14 +54,22 @@
#define _UAPI_LINUX_TIMEX_H
#include <linux/time.h>
+#include <asm/bitsperlong.h>
+
+#if __KERNEL_TIME_BITS == 32 || __BITS_PER_LONG == 64
+#define __old_kernel_timex timex
+#else
+#define __kernel_timex timex
+#endif
#define NTP_API 4 /* NTP API version */
+
/*
* syscall interface - used (mainly by NTP daemon)
* to discipline kernel clock oscillator
*/
-struct timex {
+struct __old_kernel_timex {
unsigned int modes; /* mode selector */
__kernel_long_t offset; /* time offset (usec) */
__kernel_long_t freq; /* frequency offset (scaled ppm) */
diff --git a/arch/arm/include/uapi/asm/stat.h b/arch/arm/include/uapi/asm/stat.h
index 537a12553dd8..18ff0e2383ad 100644
--- a/arch/arm/include/uapi/asm/stat.h
+++ b/arch/arm/include/uapi/asm/stat.h
@@ -19,7 +19,7 @@ struct __old_kernel_stat {
#define STAT_HAVE_NSEC
-struct stat {
+struct __old_kernel_stat2 {
#if defined(__ARMEB__)
unsigned short st_dev;
unsigned short __pad1;
diff --git a/arch/avr32/include/uapi/asm/stat.h b/arch/avr32/include/uapi/asm/stat.h
index 2b528ca17985..5df389890f8a 100644
--- a/arch/avr32/include/uapi/asm/stat.h
+++ b/arch/avr32/include/uapi/asm/stat.h
@@ -24,7 +24,7 @@ struct __old_kernel_stat {
unsigned long st_ctime;
};
-struct stat {
+struct __old_kernel_stat2 {
unsigned long st_dev;
unsigned long st_ino;
unsigned short st_mode;
diff --git a/arch/blackfin/include/uapi/asm/stat.h b/arch/blackfin/include/uapi/asm/stat.h
index 99ee343aec23..cd417baf51fc 100644
--- a/arch/blackfin/include/uapi/asm/stat.h
+++ b/arch/blackfin/include/uapi/asm/stat.h
@@ -9,7 +9,7 @@
#include <asm-generic/kernel_stat.h>
-struct stat {
+struct __old_kernel_stat2 {
unsigned short st_dev;
unsigned short __pad1;
unsigned long st_ino;
diff --git a/arch/cris/include/uapi/asm/stat.h b/arch/cris/include/uapi/asm/stat.h
index 4837884cd2d3..38d1dba3ea6a 100644
--- a/arch/cris/include/uapi/asm/stat.h
+++ b/arch/cris/include/uapi/asm/stat.h
@@ -22,7 +22,7 @@ struct __old_kernel_stat {
#define STAT_HAVE_NSEC 1
-struct stat {
+struct __old_kernel_stat2 {
unsigned long st_dev;
unsigned long st_ino;
unsigned short st_mode;
diff --git a/arch/frv/include/uapi/asm/stat.h b/arch/frv/include/uapi/asm/stat.h
index 5448b198fbb6..5ff15ccef6c3 100644
--- a/arch/frv/include/uapi/asm/stat.h
+++ b/arch/frv/include/uapi/asm/stat.h
@@ -18,7 +18,7 @@ struct __old_kernel_stat {
};
/* This matches struct stat in uClibc/glibc. */
-struct stat {
+struct __old_kernel_stat2 {
unsigned char __pad1[6];
unsigned short st_dev;
diff --git a/arch/m32r/include/uapi/asm/stat.h b/arch/m32r/include/uapi/asm/stat.h
index d0ffa70f73c0..03531561b8cd 100644
--- a/arch/m32r/include/uapi/asm/stat.h
+++ b/arch/m32r/include/uapi/asm/stat.h
@@ -20,7 +20,7 @@ struct __old_kernel_stat {
#define STAT_HAVE_NSEC 1
-struct stat {
+struct __old_kernel_stat2 {
unsigned short st_dev;
unsigned short __pad1;
unsigned long st_ino;
diff --git a/arch/m68k/include/uapi/asm/stat.h b/arch/m68k/include/uapi/asm/stat.h
index 6f455db47b4e..f7936ed51c09 100644
--- a/arch/m68k/include/uapi/asm/stat.h
+++ b/arch/m68k/include/uapi/asm/stat.h
@@ -17,7 +17,7 @@ struct __old_kernel_stat {
unsigned long st_ctime;
};
-struct stat {
+struct __old_kernel_stat2 {
unsigned short st_dev;
unsigned short __pad1;
unsigned long st_ino;
diff --git a/arch/mips/include/uapi/asm/stat.h b/arch/mips/include/uapi/asm/stat.h
index 53e58fbd83fa..c0b82a1ccf17 100644
--- a/arch/mips/include/uapi/asm/stat.h
+++ b/arch/mips/include/uapi/asm/stat.h
@@ -16,7 +16,7 @@
#if (_MIPS_SIM == _MIPS_SIM_ABI32) || (_MIPS_SIM == _MIPS_SIM_NABI32)
-struct stat {
+struct __old_kernel_stat2 {
unsigned st_dev;
long st_pad1[3]; /* Reserved for network id */
ino_t st_ino;
@@ -90,7 +90,7 @@ struct stat64 {
#if _MIPS_SIM == _MIPS_SIM_ABI64
/* The memory layout is the same as of struct stat64 of the 32-bit kernel. */
-struct stat {
+struct __old_kernel_stat2 {
unsigned int st_dev;
unsigned int st_pad0[3]; /* Reserved for st_dev expansion */
diff --git a/arch/mn10300/include/uapi/asm/stat.h b/arch/mn10300/include/uapi/asm/stat.h
index af3b4d6b7b7a..ab507885dd05 100644
--- a/arch/mn10300/include/uapi/asm/stat.h
+++ b/arch/mn10300/include/uapi/asm/stat.h
@@ -17,7 +17,7 @@ struct __old_kernel_stat {
unsigned long st_ctime;
};
-struct stat {
+struct __old_kernel_stat2 {
unsigned long st_dev;
unsigned long st_ino;
unsigned short st_mode;
diff --git a/arch/parisc/include/uapi/asm/stat.h b/arch/parisc/include/uapi/asm/stat.h
index f06ce7ba0115..d632b5453628 100644
--- a/arch/parisc/include/uapi/asm/stat.h
+++ b/arch/parisc/include/uapi/asm/stat.h
@@ -4,7 +4,7 @@
#include <linux/types.h>
#include <asm-generic/kernel_stat.h>
-struct stat {
+struct __old_kernel_stat2 {
unsigned int st_dev; /* dev_t is 32 bits on parisc */
unsigned int st_ino; /* 32 bits */
unsigned short st_mode; /* 16 bits */
diff --git a/arch/powerpc/include/uapi/asm/stat.h b/arch/powerpc/include/uapi/asm/stat.h
index 248d8072267f..4b62b30ed12c 100644
--- a/arch/powerpc/include/uapi/asm/stat.h
+++ b/arch/powerpc/include/uapi/asm/stat.h
@@ -7,6 +7,13 @@
* 2 of the License, or (at your option) any later version.
*/
#include <linux/types.h>
+#include <asm/bitsperlong.h>
+
+#if __KERNEL_TIME_BITS == 32 || __BITS_PER_LONG == 64
+#define __old_kernel_stat2 stat
+#else
+#define __kernel_stat stat
+#endif
#define STAT_HAVE_NSEC 1
@@ -26,7 +33,7 @@ struct __old_kernel_stat {
};
#endif /* !__powerpc64__ */
-struct stat {
+struct __old_kernel_stat2 {
unsigned long st_dev;
ino_t st_ino;
#ifdef __powerpc64__
@@ -78,7 +85,7 @@ struct stat64 {
unsigned int __unused5;
};
-/* this matches the powerpc64 'struct stat' for compat tasks */
+/* this matches the powerpc64 'struct __old_kernel_stat2' for compat tasks */
struct __kernel_stat {
unsigned long long st_dev;
unsigned long long st_ino;
@@ -101,6 +107,5 @@ struct __kernel_stat {
unsigned long long __unused5;
unsigned long long __unused6;
};
#endif /* _ASM_POWERPC_STAT_H */
diff --git a/arch/s390/include/uapi/asm/stat.h b/arch/s390/include/uapi/asm/stat.h
index d4c2711249dd..5f40f51ecdab 100644
--- a/arch/s390/include/uapi/asm/stat.h
+++ b/arch/s390/include/uapi/asm/stat.h
@@ -7,6 +7,14 @@
#ifndef _S390_STAT_H
#define _S390_STAT_H
+#include <asm/bitsperlong.h>
+
+#if __KERNEL_TIME_BITS == 32 || __BITS_PER_LONG == 64
+#define __old_kernel_stat2 stat
+#else
+#define __kernel_stat stat
+#endif
+
#ifndef __s390x__
struct __old_kernel_stat {
unsigned short st_dev;
@@ -22,7 +30,7 @@ struct __old_kernel_stat {
unsigned long st_ctime;
};
-struct stat {
+struct __old_kernel_stat2 {
unsigned short st_dev;
unsigned short __pad1;
unsigned long st_ino;
@@ -75,7 +83,7 @@ struct stat64 {
#else /* __s390x__ */
-struct stat {
+struct __old_kernel_stat {
unsigned long st_dev;
unsigned long st_ino;
unsigned long st_nlink;
diff --git a/arch/sh/include/uapi/asm/stat.h b/arch/sh/include/uapi/asm/stat.h
index a13ffbcccd50..0d3358037558 100644
--- a/arch/sh/include/uapi/asm/stat.h
+++ b/arch/sh/include/uapi/asm/stat.h
@@ -18,7 +18,7 @@ struct __old_kernel_stat {
};
#if defined(__SH5__) || defined(CONFIG_CPU_SH5)
-struct stat {
+struct __old_kernel_stat2 {
unsigned short st_dev;
unsigned short __pad1;
unsigned long st_ino;
@@ -77,7 +77,7 @@ struct stat64 {
unsigned long __unused2;
};
#else
-struct stat {
+struct __old_kernel_stat2 {
unsigned long st_dev;
unsigned long st_ino;
unsigned short st_mode;
diff --git a/arch/sparc/include/uapi/asm/stat.h b/arch/sparc/include/uapi/asm/stat.h
index 6d19c7bdc641..8ace4436a31f 100644
--- a/arch/sparc/include/uapi/asm/stat.h
+++ b/arch/sparc/include/uapi/asm/stat.h
@@ -2,6 +2,13 @@
#define __SPARC_STAT_H
#include <linux/types.h>
+#include <asm/bitsperlong.h>
+
+#if __KERNEL_TIME_BITS == 32 || __BITS_PER_LONG == 64
+#define __old_kernel_stat2 stat
+#else
+#define __kernel_stat stat
+#endif
#if defined(__sparc__) && defined(__arch64__)
/* 64 bit sparc */
@@ -48,7 +55,8 @@ struct stat64 {
#else
/* 32 bit sparc */
-struct stat {
+
+struct __old_kernel_stat2 {
unsigned short st_dev;
ino_t st_ino;
mode_t st_mode;
diff --git a/arch/x86/include/uapi/asm/stat.h b/arch/x86/include/uapi/asm/stat.h
index 5d5754fc3d36..5fa5beeafd86 100644
--- a/arch/x86/include/uapi/asm/stat.h
+++ b/arch/x86/include/uapi/asm/stat.h
@@ -2,11 +2,18 @@
#define _ASM_X86_STAT_H
#include <asm/posix_types.h>
+#include <asm/bitsperlong.h>
#define STAT_HAVE_NSEC 1
+#if __KERNEL_TIME_BITS == 32 || __BITS_PER_LONG == 64
+#define __old_kernel_stat2 stat
+#else
+#define __kernel_stat stat
+#endif
+
#ifdef __i386__
-struct stat {
+struct __old_kernel_stat2 {
unsigned long st_dev;
unsigned long st_ino;
unsigned short st_mode;
@@ -73,7 +80,7 @@ struct stat64 {
#else /* __i386__ */
-struct stat {
+struct __old_kernel_stat2 {
__kernel_ulong_t st_dev;
__kernel_ulong_t st_ino;
__kernel_ulong_t st_nlink;
diff --git a/arch/xtensa/include/uapi/asm/stat.h b/arch/xtensa/include/uapi/asm/stat.h
index 8d9c1d9d82d0..94e40d22eb88 100644
--- a/arch/xtensa/include/uapi/asm/stat.h
+++ b/arch/xtensa/include/uapi/asm/stat.h
@@ -15,7 +15,7 @@
#define STAT_HAVE_NSEC 1
-struct stat {
+struct __old_kernel_stat2 {
unsigned long st_dev;
unsigned long st_ino;
unsigned int st_mode;