系统相关
首页 > 系统相关> > linux – 写入内存映射文件后更新mtime的内容是什么?

linux – 写入内存映射文件后更新mtime的内容是什么?

作者:互联网

我在Linux上使用XFS并且有一个内存映射文件,我每秒写一次.我注意到文件mtime(由watch ls –full-time显示)会定期更改但不规则. mtimes之间的差距似乎在2到20秒之间,但并不一致.在系统上运行的其他东西很少 – 特别是我的文件只有一个程序,还有一个读数.

同一个程序更频繁地写入其他一些mmapped文件,并且它们的mtime每30秒更改一次.

我没有使用msync()(在调用时会更新mtime).

我的问题:

>什么更新mtime?
>更新间隔是否可配置?
>为什么有些mtimes每30秒才更新一次,但是我写的频率较低的一些文件有更新鲜(不规则但总是不到30秒)的时间?

解决方法:

当您映射文件时,您基本上是在进程和内核的页面缓存之间直接共享内存 – 与保存从磁盘读取的文件数据相同的缓存,或者等待写入磁盘的缓存.页面缓存中的页面与磁盘上的页面不同(因为它已被写入)被称为“脏”.

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

另一组变量是dirty_writeback_centisecs,dirty_background_ratio和dirty_ratio. dirty_writeback_centisecs控制内核线程检查脏页的频率,默认为500(5秒).如果脏页的百分比(作为可用于缓存的内存的一小部分)小于dirty_background_ratio则没有任何反应;如果它超过dirty_background_ratio,那么内核将开始将一些页面写入磁盘.最后,如果脏页的百分比超过dirty_ratio,那么任何尝试写入的进程都将阻塞,直到脏数据量减少.这确保了未写入数据的数量不会无限制地增加;最终,生成数据的过程比磁盘写入的速度要快,因此必须减速以匹配磁盘的速度.

关于如何更新mtime的问题与内核如何首先知道页面是否脏的问题有关.对于mmap,答案是内核将映射的页面设置为只读.这并不意味着你不能写它们,但这意味着你第一次这样做,它会在内存管理单元中触发一个由内核处理的异常.异常处理程序(至少)做了四件事:

>将页面标记为脏,以便将其写回.
>更新文件mtime.
>将页面标记为读写,以便写入成功.
>跳回到程序中写入mmaped页面的指令,此时成功.

因此,当您将数据写入干净页面时,它会导致mtime更新,但它也会导致页面变为读写,因此进一步写入不会导致异常(或mtime更新)注释1.但是,当脏页被刷新到磁盘,它变得干净,并且再次变为“只读”,因此对它的任何进一步写入将触发另一个最终的磁盘写入,以及另一个mtime更新.

所以现在,通过一些假设,我们可以开始拼凑这个难题.

首先,dirty_background_ratio和dirty_ratio可能不会发挥作用.如果您的写入速度足够快以触发后台刷新,那么很可能您会在所有文件上看到“不规则”行为.

其次,“不规则”文件和“30秒”文件之间的区别是页面访问模式.我猜测“不规则”文件是以某种附加模式或循环缓冲方式写入的,这样你就可以每隔几秒就开始写一个新的页面.每次弄脏以前未触及的页面时,都会触发mtime更新.但对于显示30秒模式的文件,您只能写入一个页面(可能是一页或更短的页面).在这种情况下,mtime会在第一次写入时更新,然后不会再次更新,直到文件通过超过dirty_expire_centisecs(即30秒)刷新到磁盘.

注1:从技术上讲,这种行为是错误的.这是不可预测的,但标准允许一定程度的不可预测性.但它们确实要求mtime在最后一次写入文件时或之后,以及msync(如果有)之前或之后.如果页面在刷新到磁盘之前的间隔内多次写入,则不会发生这种情况 – mtime获取第一次写入的时间戳.这已经讨论过,但a patch that would have fixed it未被接受.因此,使用mmap时,mtimes可能会出错. dirty_expire_centisecs限制该错误,但只是部分限制,因为其他磁盘流量可能导致刷新必须等待,扩展写入窗口以进一步绕过mtime.

标签:linux,mmap,xfs,memory-mapped-files
来源: https://codeday.me/bug/20190519/1133222.html