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

我在担任内核开发人员Arnd Bergmann的Outreachy实习生时开始解决这个问题。 Outreachy 是一个仁慈的程序,可以帮助新程序员进入开源开发。内核项目的导师通常是像 Arnd 这样经验丰富的内核开发人员。

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

更多 Linux 资源

  • Linux 命令备忘单

  • 高级 Linux 命令备忘单

  • 免费在线课程:RHEL 技术概述

  • Linux 网络备忘单

  • SELinux 备忘单

  • Linux 常用命令备忘单

  • 什么是 Linux 容器?

  • 我们最新的 Linux 文章

解决内核中的一个问题很少只涉及一件事。它还涉及内核中相关事物的复杂性(在更改之前总是需要进行一次清理)以及与社区的交互(尤其是作为新手)。

我们处理的领域之一是虚拟文件系统 (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 将在[linux.conf.aulinux.conf.au,1 月 21 日至 25 日在新西兰克赖斯特彻奇介绍防止时间耗尽的追求如何引导我了解 Linux 内核的各个角落。

Logo

更多推荐