O_DIRECT到底是什么意思?

20

如果我使用O_DIRECT标志打开文件,那么每当写入(阻塞模式)返回时,数据就保存在磁盘上了吗?


1
不,手册页面非常明确。有一个单独的部分专门讨论使用同步I/O的O_DIRECTO_SYNC - Michael Foukarakis
谢谢您的回复:-) 我已经阅读了man手册,它说:“I/O是同步的,也就是说,在完成read(2)或write(2)后,数据一定已经传输。”此外,似乎O_SYNC用于确保元数据也被传输。那么,我想知道是否可以通过O_DIRECT来确保数据(而不是元数据)在写入返回时已经传输? - Rainman1985
1
顺便问一下,“transferred”是不是意味着数据在磁盘上? - Rainman1985
4
从手册页面中可以看到:"O_DIRECT..不像O_SYNC标志那样提供 数据 和必要元数据的传输保证"。请查阅与之相关的O_SYNC保证,同时需要注意的是,“传输”不能保证数据已经写入磁盘,这是一个非常复杂的问题,因为底层系统(I/O控制器、总线等)无法完全保证。 - Michael Foukarakis
1个回答

40

(本答案适用于Linux-其他操作系统可能有不同的注意事项/语义)

让我们从子问题开始:

如果我使用O_DIRECT标志打开一个文件,是否意味着每当对该文件的写入(阻塞模式)返回时,数据就在磁盘上?

不是(如@michael-foukarakis评论所述) - 如果您需要保证数据已经到达非易失性存储器,则必须使用/添加其他内容。

O_DIRECT真正意味着什么?

这是一个提示,表示您希望I/O绕过Linux内核的缓存。实际发生的情况取决于诸如以下因素:

  • 磁盘配置
  • 是否打开块设备或文件系统中的文件
  • 如果在文件系统中使用文件
    • 使用的确切文件系统以及文件系统和文件上使用的选项
    • 是否正确对齐了I/O
    • 文件系统是否必须进行新块分配才能满足您的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()

参考资料


你写入的所有字节是否总是在单个写操作中提交,而不像写入套接字那样?即使不是这样,我假设它也永远不会以小于PAGE_SIZE的批次进行写入? - Gukki5
1
@Gukki5 如果我们谈论的是一般情况下的Linux,那么答案是否定的 - 你不能保证普通的write(2)不会被块层分开(你可能会对阅读https://dev59.com/R3I-5IYBdhLWcg3wHUhB#61832882和https://dev59.com/oGPVa4cB1Zd3GeqP65TH#59403297感兴趣)。此外,如果磁盘支持,你可以合法地写入小于PAGE_SIZE的数据(许多最近的磁盘可能会进行RMW,因此它可以支持512字节的扇区),在考虑到某些Linux平台具有PAGE_SIZE==64k之前... - Anon
谢谢!请阅读所有内容。我的NVMe设备具有max_hw_sectors_kb:2048max_sectors_kb:1280``logical_block_size:512。因此,即使在最新的Linux内核上,对文件的单个write()操作也永远不会写入超过1280KB?所以提交大于该大小的写入是没有意义的? - Gukki5

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