如果我使用O_DIRECT
标志打开文件,那么每当写入(阻塞模式)返回时,数据就保存在磁盘上了吗?
(本答案适用于Linux-其他操作系统可能有不同的注意事项/语义)
让我们从子问题开始:
如果我使用O_DIRECT标志打开一个文件,是否意味着每当对该文件的写入(阻塞模式)返回时,数据就在磁盘上?
不是(如@michael-foukarakis评论所述) - 如果您需要保证数据已经到达非易失性存储器,则必须使用/添加其他内容。
O_DIRECT真正意味着什么?
这是一个提示,表示您希望I/O绕过Linux内核的缓存。实际发生的情况取决于诸如以下因素:
上面的列表不是详尽无遗的。
在“最佳”情况下,设置O_DIRECT
将避免在传输数据时进行额外的数据复制,并且调用将在传输完成后返回。当直接打开“真正”的本地磁盘的块设备时,您更有可能处于此情况。正如先前所述,即使具有此属性也不能保证成功的write()
调用的数据可以在突然断电后存储。如果数据从RAM传输到非易失性存储器(例如,带电池备份的RAID控制器)或RAM本身是持久性存储,则可能会保证数据已达到可在断电时存储的稳定存储。要了解是否为此情况,必须限定硬件堆栈,因此不能总体上假设。O_DIRECT
,后续调用也可能什么也不做。有时,Linux存储堆栈中的某些内容(例如某些文件系统设置)可能会选择忽略它,因为它们必须执行的操作或者因为您没有满足要求(这是合法的),并且只是静默地执行缓冲I/O(即写入缓冲区/从已缓冲数据中读取)。目前尚不清楚是否会付出额外的努力来确保已确认写入的数据至少已经“到达设备”(但在O_DIRECT
和屏障线程Christoph Hellwig发布的帖子中,O_DIRECT
回退将确保数据至少已发送到设备)。更进一步的复杂性在于,使用O_DIRECT
并不意味着文件元数据方面有任何影响,因此,即使通过调用完成,写入数据已经“到达设备”,关键文件元数据(例如文件大小,因为您正在进行附加)可能仍然存在问题。因此,在崩溃后,您可能无法访问您认为已传输的数据(它可能会被截断,或全部为零等)。O_DIRECT
的数据始终意味着数据在写入返回后将存储在磁盘上,但更改事物(例如使用Ext4文件系统而不是XFS)可能会以非常激烈的方式削弱实际实现的内容。
当你提到“保证数据”(而不是元数据)时,也许你正在寻找O_DSYNC
/fdatasync()
?如果你想要保证元数据也被写入,你需要查看O_SYNC
/fsync()
。
O_DIRECT
的内容。open()
调用。O_DIRECT
时,Btrfs将会使用缓冲I/O。O_DIRECT
的语义。此外,还可以查看(截至2020年中期)ZFS on Linux提议的新O_DIRECT
语义(交互复杂,无法简要解释)。O_DIRECT
)write(2)
不会被块层分开(你可能会对阅读https://dev59.com/R3I-5IYBdhLWcg3wHUhB#61832882和https://dev59.com/oGPVa4cB1Zd3GeqP65TH#59403297感兴趣)。此外,如果磁盘支持,你可以合法地写入小于PAGE_SIZE的数据(许多最近的磁盘可能会进行RMW,因此它可以支持512字节的扇区),在考虑到某些Linux平台具有PAGE_SIZE==64k之前... - Anonmax_hw_sectors_kb:2048
和max_sectors_kb:1280``logical_block_size:512
。因此,即使在最新的Linux内核上,对文件的单个write()
操作也永远不会写入超过1280KB?所以提交大于该大小的写入是没有意义的? - Gukki5
O_DIRECT
和O_SYNC
。 - Michael Foukarakis