解决 Linux 内核中的 2038 年问题

关于如何防止时间耗尽的探索如何将我带到 Linux 内核的各个角落。
224 位读者喜欢这篇文章。
Penguins with space and stars overlay

原始图片来自维基共享资源。已修改。CC BY-SA 4.0 许可。

由于 Linux 中时间的表示方式,有符号 32 位数字无法支持 2038 年 1 月 19 日 3:14:07 UTC 之后的时间。这个 2038 年问题(Y2038 或 Y2K38)是关于时间数据类型表示的。解决方案是使用 64 位时间戳。

我开始着手解决这个问题,当时我作为 Outreachy 实习生为内核开发人员 Arnd Bergmann 工作。Outreachy 是一个慈善项目,旨在帮助新的程序员进入开源开发。内核项目的导师通常是像 Arnd 这样经验丰富的内核开发人员。

我选择研究 Y2038 问题,因为它让我接触到内核中的所有子系统,甚至更多。这个问题还涉及到用户空间、C 库、POSIX 和 C 标准。我发现这个问题实际上是关于层与层之间的接口。

解决内核中的一个问题很少只涉及一件事;它还涉及到内核中相互关联事物的复杂性(总是在更改之前需要进行更多的清理)以及与社区的互动(对于新手来说尤其如此)。

我们解决的领域之一是虚拟文件系统 (VFS)。VFS 是一个文件系统抽象层。因此,即使某些文件系统(如 ext4)可以在 32 位系统上表示 2038 年之后的时间戳,但如果 VFS 层不支持它们,它们也无法做到这一点。

VFS 的更改是花费最长时间才能达成共识并合并的补丁系列之一。

提出解决方案

问题: 内核中 inode 时间戳的表示形式是 struct timespec,它不是 Y2038 安全的。提出的解决方案: 将表示形式更改为 struct timespec64,它是 Y2038 安全的。

该系列的第一版是由 Arnd 在 2014 年发布的。当时,有一些未解决的问题以及关于添加时间戳范围检查的一些反馈。

在 2016 年 1 月,我发布了第一个关于此事的征求意见稿 (RFC),询问是否有人反对上述方法。这对于内核社区来说不是一个典型的 RFC。该系列求助信解释了拟议的更改,并提供了一些关于如何进行更改的示例。对于我们试图在该系列中表达的内容,存在一些困惑。

我发布了另一个系列(实际上是三个),以三种不同的方式解决问题。这是早期系列的简化版本,仅解决了核心问题。这也是非典型的。内核开发人员 Thomas Gleixner 说他稍微偏爱解决问题的一种方法,所以我们以这种方式完成了所有补丁。

但是我们必须在进行更改之前摆脱一些旧的时间接口。当我发布这个系列时,Linus Torvalds 不喜欢 其中一个接口(current_fs_time(sb)),因为它将超级块作为参数来访问时间戳粒度。但是时间戳实际上是 inode 的一个特性,而不是超级块的特性。所以,我们摆脱了这个 API。

现在必须再次重做原始系列。进行 标志日补丁 似乎是解决问题的一种蛮力方法。但我们最终还是这样做了。我们甚至更进一步,使用了 Coccinelle 脚本。这改变了 80 多个文件。挑战在于使更改尽可能基本,以避免回归。我们最终在 2018 年 6 月 合并了补丁,并且没有听到任何来自更改的回归。

通过整个练习结束时,我们摆脱了三个内核 API,重新排列了一些文件系统时间戳处理,处理了打印格式以支持更大的时间戳,分析了 32 位架构对象转储,并从头开始重写了至少五个版本的系列。这只是我们为内核解决的问题之一。但 Y2038 一直是我最喜欢的项目之一。 


Deepa Dinamani 将在 1 月 21 日至 25 日在 न्यूजीलैंड基督城的 linux.conf.au 上展示 关于如何防止时间耗尽的探索如何将我带到 Linux 内核的各个角落

Avatar
Deepa 是一位计算机科学爱好者。她喜欢思考事物为何如此。她的兴趣是理论计算机科学和操作系统。她之前在圣地亚哥的高通公司工作。目前她在旧金山湾区的谷歌工作。她在那里为数据中心服务器开发系统软件,包括 Linux 内核和相邻层。

6 条评论

很棒的故事。我喜欢阅读关于 Linux 开发以及人们如何解决开发问题。¡谢谢!

为什么有人会把 Y2038 “缩写” 成 Y2K38 呢?

那么,在 2038 年我们必须使用 x64 Linux 系统吗?

感谢您的阅读。我同时使用 32 位和 64 位版本的 Linux。很高兴知道我们处于安全的手中,ext4 文件系统是我的首选。它可以避免很多意外问题。

© 2025 open-source.net.cn. All rights reserved.