|Benefits for LWN subscribers|
The primary benefit from subscribing to LWN is helping to keep us publishing, but, beyond that, subscribers get immediate access to all site content and access to a number of extra site features. Please sign up today!
In January 2038, the 32-bit time_t value used on many Unix-like systems will run out of bits and be unable to represent the current time. This may seem like a distant problem, but, as Tom Scott recently observed, the year-2038 apocalypse is now closer to the present than the year-2000 problem. The fact that systems being deployed now will still be operating in 2038 adds urgency to the issue as well. The good news is that work has been underway for years to prepare Linux for this date, so there should be no need to call developers out of retirement in 2037 in a last-minute panic. Some of the final steps in this transition for the core kernel have been posted, and seem likely to be merged for 5.1.
There have been numerous phases to this work, which has been carried out primarily by Arnd Bergmann and Deepa Dinamani. Timekeeping within the kernel has been reworked to use 64-bit values throughout, even on 32-bit systems, for example. A lot of work was required to get there, but that was, in some sense, the easy part; since the changes were all internal to the kernel, the developers involved were free to change interfaces when needed. Life becomes more difficult when it comes to the system-call interface, since that cannot be changed at whim without breaking user-space applications.
The approach that has been taken here, for many of the relevant system calls, is to recognize that most systems already have a 64-bit solution for 32-bit applications. Most 64-bit kernels are able to run 32-bit processes; to do so, they provide a set of compatibility (or "compat") system calls to perform impedance matching. Typically, these compat calls simply reformat 32-bit types into their 64-bit equivalent, then pass the result to the native 64-bit implementations. In other words, the compat calls do exactly what is needed to connect a user space process using 32-bit times to a kernel that uses 64-bit times throughout.
Much of the work that has been done to this point, thus, has been promoting these compat system calls to become the native 32-bit system calls. User space sees no changes, but the kernel is able to leave 32-bit times behind entirely. To that end, one of the key changes in this patch set posted by Bergmann is to take the compat calls and define them as proper system calls for 32-bit systems. In the process, these calls are renamed; futex() becomes futex_time32(), for example. Then, 32-bit architectures are switched over to use the new _time32() calls.
The only remaining problem, of course, is that user space is still using 32-bit times, so things will still explode on schedule in 2038. Fixing that problem is not something that the kernel can do on its own, but it can provide the infrastructure to make the transition possible. In particular, for all of the _time32() calls described above, the patch set also exposes the 64-bit versions with _time64() suffixes. So, once this patch is applied, both the (broken) 32-bit and (fixed) 64-bit interfaces are available in 32-bit systems.
At this point, the ball moves into the court of the C library and distribution developers. A new C library release can define the system-call interfaces with 64-bit time values, and implement those interfaces with calls to the _time64() versions. Older binaries, instead, will continue to use the 32-bit versions. For many applications, all that will be needed at this point is a rebuild and they will be prepared to survive the 2038 transition. Others, of course, will require more work. Distributors have the option of rebuilding everything they ship for 64-bit time, then disabling 32-bit times entirely by turning off the COMPAT_32BIT_TIME configuration variable. Most distributors, though, are likely to support both modes for some time yet.
For the curious, the system calls affected are: adjtimex(), clock_adjtime(), clock_getres(), clock_gettime(), clock_nanosleep(), clock_settime(), futex(), io_getevents(), io_pgetevents(), mq_timedsend(), mq_timedreceive(), nanosleep(), ppoll(), pselect6(), recvmmsg(), rt_sigtimedwait(), sched_rr_get_interval(), semtimedop(), timer_gettime(), timer_settime(), timerfd_gettime(), timerfd_settime(), and utimensat(). The plan for the GNU C Library transition has been posted in great detail as well.
These changes fix the core kernel system-call interfaces, but that is not the end of the story. There are many other places in the kernel's user-space API where time values appear, and many of them need to be fixed as well. Those are slowly being addressed. Consider, for example, the SO_TIMESTAMP socket option (described in this man page); it enables the reception of control messages with network timestamp values. Those values are specified using struct timeval, which is not year-2038 safe.
This patch set from Dinamani addresses that problem by adding a new set of options that are year-2038 safe. An application can request SO_TIMESTAMP_NEW to get a new control-message format with 64-bit times; the SO_TIMESTAMPNS and SO_TIMESTAMPING options have seen a similar treatment. Socket timeout values also have a year-2038 problem; this patch series adds SO_RCVTIMEOU_NEW and SO_SNDTIMEO_NEW to address it. Once again, libraries and (possibly) applications will need to be changed to be able to make use of these new options.
Once this work gets in, the kernel community, at least, can begin to think
that there is some light at the end of the tunnel. Problems will remain,
mostly in filesystem timestamps and time values that are passed to
ioctl() calls, but the work as a whole can be seen as entering the
clean-up phase. For library developers and distributors, though, the real
work is just beginning. The good news is that they still have some time to
get their piece of the work done so that systems deployed in the near
future will be ready for the not-so-near (but approaching rapidly) 2038
(Log in to post comments)