写入内存映射文件后,是什么更新了mtime?

5
我在Linux上使用XFS,并有一个内存映射文件,每秒钟写入一次。我注意到文件的修改时间(由watch ls --full-time显示)会不规则地周期性地更改。mtimes之间的间隔似乎在2到20秒之间,但并不一致。系统上几乎没有其他程序正在运行--特别是只有我的一个程序在写该文件,还有一个在读取。
同样的程序更频繁地写入其他一些内存映射文件,它们的mtime每30秒更新一次。
我没有使用msync()(调用后会更新mtime)。
我的问题:
1.什么会更新mtime?
2.是否可以配置更新间隔?
3.为什么某些文件会每30秒更新一次,但我较少写入的某些文件的mtime更新速度更快(不规则但始终小于30秒)?
1个回答

10
当您使用 mmap 映射一个文件时,实际上是在您的进程和内核页缓存之间直接共享内存 —— 内核页缓存保存了从磁盘中读取的文件数据,或等待写入磁盘的数据。缓存中与磁盘上不同的页面(因为已经被写入)称为“脏”页面。

有一个内核线程扫描脏页面并将其写回磁盘,在多个参数的控制下进行。其中一个重要的参数是 dirty_expire_centisecs。如果文件的任何页面脏时间超过了 dirty_expire_centisecs,那么该文件的所有脏页面都将被写入。默认值为 3000 个厘秒(30 秒)。

另一组变量是 dirty_writeback_centisecsdirty_background_ratiodirty_ratiodirty_writeback_centisecs 控制内核线程检查脏页面的频率,并默认为 500 (5 秒)。如果脏页面占分配给缓存的内存的比例小于 dirty_background_ratio,则什么也不会发生;如果大于 dirty_background_ratio,则内核将开始向磁盘写入一些页面。最后,如果脏页面的百分比超过 dirty_ratio,则任何尝试写入的进程都会被阻塞,直到脏数据量减少。这确保未写入数据量不能无限制地增加;最终,产生数据速度比磁盘写入速度快的进程将必须放慢速度以与磁盘同步。

更新 mtime 的问题与内核如何知道页面是脏的问题相关。在 mmap 的情况下,答案是内核将映射的页面设置为只读。这并不意味着您不能写入它们,但它意味着第一次写入时会触发内存管理单元中的异常处理程序,并由内核处理。异常处理程序执行(至少)四个操作:

  1. 标记页面为脏,以便将其写回。
  2. 更新文件的 mtime。
  3. 将页面标记为读写,以便写入可以成功。
  4. 跳回到程序中写入 mmap 页面的指令,这次成功执行。

因此,当您向干净的页面写入数据时,会导致 mtime 更新,但它还会使页面变得可写,以便进一步的写入不会引发异常(或 mtime 更新)注1。但是,当脏页面被刷新到磁盘时,它会变得干净,并再次变成“只读”,因此对其进行任何进一步的写入都将触发另一个最终的磁盘写入,以及另一个 mtime 更新。

所以现在,在做出一些假设的情况下,我们可以开始拼凑这个谜题了。

首先,dirty_background_ratiodirty_ratio可能并没有发挥作用。如果您的写入速度足够快以触发后台刷新,则很可能会在所有文件上看到“不规则”行为。
其次,“不规则”文件与“30秒”文件之间的区别在于页面访问模式。我推测,“不规则”文件是以某种追加模式或循环缓冲区方式进行写入的,因此您每隔几秒钟就开始写入新的页面。每次脏一个以前未触及的页面,它都会触发mtime更新。但对于显示30秒模式的文件,您只写入一个页面(也许长度为一页或更少)。在这种情况下,mtime在第一次写入时更新,然后直到文件通过超过dirty_expire_centisecs被刷新到磁盘时才会再次更新,该值为30秒。
注意1:从技术上讲,这种行为是错误的。它是不可预测的,但标准允许一定程度的不可预测性。但是,它们要求mtime在文件的最后一次写入时或之后,在msync(如果有)之前或之后的某个时间点上。在一个页面在刷新到磁盘之前的时间段内被多次写入的情况下,不会发生这种情况 - mtime会获得第一个写入的时间戳。这已经被讨论过,但是修复该问题的补丁并未被接受。因此,在使用mmap时,mtime可能存在错误。dirty_expire_centisecs在某种程度上限制了该错误,但仅在其他磁盘流量可能导致刷新需要等待的情况下,进一步延长了写入绕过mtime的时间窗口。

1
顺便说一下,我已经使用Linux 18年了,读过RML的书,并进行了一些非常轻量级的内核开发,但我不是专家,特别是在mm方面,所以我可能犯了一些错误。欢迎纠正。 - hobbs
哇,这是很多有用的信息!谢谢你。你对不同的写入模式影响mtime行为的理论很有趣...但也有点令人困惑,因为具有不规则mtime步骤的文件确实是以追加方式进行编写,但速度是恒定的(每秒一个固定大小记录)。如果像文本日志文件那样不断添加,我可以理解为什么会在不规则的时间间隔遇到新页面,但在我的情况下,写入速率是恒定的(对于那些特定的文件)。具有一致时间步长的文件确实较小且随机。 - John Zwinck
1
@JohnZwinck,对于这个问题我再多想了一下,如果你的记录大小不能整除页面大小,那么在mtime更新之间可能会出现+/- 1秒的变化,但是我不知道如何解决更大的差异 :) - hobbs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接