Because of the way time is represented in Linux, a signed 32-bit number can't support times beyond January 19, 2038 after 3:14:07 UTC. This Year 2038 (Y2038 or Y2K38) problem is about the time data type representation. The solution is to use 64-bit timestamps.
I started working on the problem while working as an Outreachy intern for kernel developer Arnd Bergmann. Outreachy is a benevolent program that helps new programmers get into open source development. The mentors for the kernel projects are usually experienced kernel developers like Arnd.
I chose to work on the Y2038 problem because it let me touch all the subsystems in the kernel—and even more than that. The problem also involves user space, C library, POSIX, and C standards. I found that the problem is really about interfaces between layers.
Solving one problem in the kernel rarely involves just one thing; it also involves the complexity of interrelated things in the kernel (there is always one more cleanup needed before the change) and interactions with the community (especially true as a newcomer).
One of the areas we tackled was the virtual file system (VFS). VFS is a filesystem abstraction layer. So, even if some of the filesystems, like ext4, can represent timestamps beyond the year 2038 on a 32-bit system, they cannot do so without the VFS layer supporting them.
The change to VFS was one of the patch series that took the longest to get consensus and get merged in.
Proposing a solution
The problem: The in-kernel representation of inode timestamps was in struct timespec, which is not Y2038 safe. The proposed solution: Change the representation to struct timespec64, which is Y2038 safe.
The first version of the series was posted by Arnd in 2014. At the time, there were a few open issues and some feedback about adding timestamp range-checking.
In January 2016, I posted the first request for comments (RFC) for this, asking if there was any opposition to the approach described above. This was not a typical RFC for the kernel community. The series cover letter explained the proposed change and provided a few examples of how the changes would be done. There was some confusion about what we were trying to get across in the series.
I posted another series (actually three) for solving the problem in three separate ways. This was a pared-down version of the earlier series that addressed only the core issue. This was also atypical. Kernel developer Thomas Gleixner said he slightly preferred one of the approaches to solving the problem, so we had all the patches done this way.
But we had to get rid of some old time interfaces before we could do the change. When I posted a series of this, Linus Torvalds did not like one of the interfaces (current_fs_time(sb)) because it took the superblock as an argument to access timestamp granularity. But the timestamps are really a feature of the inode, not the superblock. So, we got rid of this API.
Now the original series had to be redone again. Doing a flag day patch seemed like a brute-force approach to the problem. But we ended up doing just that. We even went a step further by using a Coccinelle script. This changed more than 80 files. The challenge was to make the changes rudimentary to avoid regressions. We finally ended up merging the patches in June 2018 and haven't heard of any regressions from the change.
By the end of this whole exercise, we got rid of three in-kernel APIs, rearranged some of the filesystem timestamp handling, handled print formats to support larger timestamps, analyzed 32-bit architecture object dumps, and rewrote at least five versions of the series from scratch. And this was just one of the problems we solved for the kernel. But Y2038 has been one of my favorite projects yet.
Deepa Dinamani will present How the quest to prevent time from running out has led me to all corners of the Linux kernel at linux.conf.au, January 21-25 in Christchurch, New Zealand.
6 Comments