LWN:如何处理硬件出错导致的错误page-cache page?

Linux News搬运工

共 2711字,需浏览 6分钟

 ·

2022-05-22 17:47

关注了就能看到更多这么棒的文章哦~

How to cope with hardware-poisoned page-cache pages

By Jonathan Corbet
May 5, 2022
LSFMM
DeepL assisted translation
https://lwn.net/Articles/893565/

"hardware poisoning" 是一种检测和处理运行系统中出现内存错误的机制。当某一段内存区域内内容不再正确时,它就是 "中毒(poisoned)" 了,对这个区域的后续访问将产生错误。内核对 hardware poisoning 的支持已超过十年,但这并不意味着它就不需要改进了。在 2022 年的 Linux 存储、文件系统、内存管理和 BPF 峰会上,Yang Shi 讨论了当 hardware poisoning 影响到 page cache 所有的内存时该如何处理的问题。

page cache 中存放着后备存储中的文件的一部分 page 的副本。如果 page cache page 产生错误不再能准确地反映文件中的数据,就不应该再被使用了。如果该 page 在从后备存储中读取后就没有被修改过,那么解决方法很简单,直接丢弃然后将数据重新读入能正常工作的内存区域。但是,如果该 page 是 dirty 状态的(被 CPU 写入过),情况就更难处理了。Shi 说,目前该 page 会被从 page cache 中删除,其中的数据都会丢失。除非进程将受影响的 page 映射到了他们的地址空间,否则进程就不会收到通知。

Shi 说,这种行为会导致数据默默地就丢失了。随后对该 page 的访问将产生不正确的数据,而用户却不知道这里出现了问题。这就导致了一些很难 debug 的问题。

为了解决这个问题,他继续说,内核应该把中毒的 page 保留在 page cache 中,而不是丢弃掉。需要把这个问题告知拥有该 page 的文件系统,并且不能尝试将该 page 写回后备存储里。有些操作,如 truncate 或 hole-punching 可以继续允许正常使用,因为相关结果应该是正确的。但如果以其他方式访问该 page 的话必须返回一个错误。

有几种方法可以实现这种行为。一种是在每个访问 page cache 的 page 的路径上检查 hardware-poison flag,这将需要修改大量的代码。另一种方法是,在 cache 中查找 page 时返回 NULL。这样做的好处是,调用者已经能够处理 NULL 的返回值,所以应该不会感到意外,只是返回的错误代码会是 ENOMEM,这可能会让人感到吃惊或误解。最后,page cache 的查找(lookup)动作可以改为返回 EIO,这能更好地表明真正的问题来自哪里。不过,这个改动会有更大的影响,因为调用者没有准备好处理这种返回状态。

Matthew Wilcox 跳出来说,只有第一个选择才是真正可行的方案。poison 问题是按 page 来追踪的,但更高层级的接口正在被转换为 folio,其中可以包含多个 page。一个 folio 中未被破坏的部分应该仍然可以被访问到,所以 page cache 的 lookup 机制需要能保持正常工作。Dan Williams 说,在 DAX 代码中(实现 persistent memory 中的文件的 direct access),他所采取的方法是将错误告知文件系统,并仍然从 page cache 中删除掉该 page。他说,这样就可能给用户返回错误了;这可能也是处理普通内存设备中的错误的一个好方法。

Ted Ts'o 同意 Williams 的观点,他说,如果关于一个损坏的 page 的信息只存在于内存中,那么系统 crash 的时候就会导致这些信息都丢失了,这也会导致相应的数据损坏无人知道。他说,这里提出的解决方案做了大量的工作,只在下一次重启发生之前返回 EIO。还需要文件系统这边做更多工作来维护这些信息,但最终来看可能是更好的方法。他说,有一种方法可以使其更容易,那就是不用关心逐个追踪损坏的 page;相反,可以给文件标记一下它其中有的地方已经损坏了。

Shi 认为,在大型数据中心环境中,内存故障并不是特别罕见的现象,而且他的两种方法任何一种都比什么都不做要好。另外,他说,用户很可能关心文件中的哪一个 page 被损坏了,所以仅仅把文件作为一个整体来标记可能是不够的。

Kent Overstreet 说,除了向用户返回出现问题的标志信息外,这项工作的重点是要避免向磁盘写回垃圾数据。然后,如果系统崩溃,"石板就被擦拭干净了",损坏的内存不再存在。他说,crash 其实可能是最好的情况。Wilcox 回答说,这种 "最好的情况" 也仍然会导致数据损失。

Josef Bacik 说,存储损坏了的数据,对他来说是最有意义的;具体实现方法主要是在通用的文件系统代码中。当被告知有问题时,文件系统代码应该标记出受到影响的 page,拒绝从这些 page 返回任何数据,并注意避免将它们写入后备存储。但他建议,每个文件有一个标志可能就足够了。开发人员(包括用户空间的和内核空间的)全部都不擅长处理错误场景,所以这个机制应该保持简单,特别是在最开始的时候。开发人员可以在以后 "尝试更加花哨的方法",如果看起来确实有必要的话。

David Hildenbrand 反对说,每个文件一个标志的话可能会阻碍虚拟机从存储在单一文件中的镜像来运行。这种情况一个错误就会阻止整个文件的使用了,基本上就会导致虚拟机被 kill。能追踪单个 page 的话可能更适合于这种使用情况。但 Bacik 重申,社区人员一定会写出错误的代码,所以应该先做尽量简单的案例。

随着时间的推移,Wilcox 指出,文件系统可以处理向一个损坏的 page 写入的情况,如果整个 page 都被覆盖的话。在这种情况下,损坏的数据就消失了,而文件又一次处于用户预期的状态了。不过,Goldwyn Rodrigues 指出,对于 copy-on-write 的文件系统来说,情况并不那么简单,它们可能仍然有损坏的 page 在那里。Bacik 说,这种情况正是他反对花哨的解决方案的原因。

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~



浏览 14
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报