O_DIRECT 的真正含义是啥?
Posted
技术标签:
【中文标题】O_DIRECT 的真正含义是啥?【英文标题】:What does O_DIRECT really mean?O_DIRECT 的真正含义是什么? 【发布时间】:2017-05-06 13:47:33 【问题描述】:如果我打开带有O_DIRECT
标志的文件,是否意味着每当对该文件的写入(阻塞模式)返回时,数据就在磁盘上?
【问题讨论】:
没有。手册页对此非常明确。有一个单独的部分专门讨论具有同步 I/O 的O_DIRECT
和 O_SYNC
。
感谢您的回复:-) 我阅读了手册页,它说“I/O 是同步的,也就是说,在读(2)或写(2)完成时,数据保证已被传输。”并且似乎使用 O_SYNC 来保证元数据也被传输。那么,我想知道 O_DIRECT 能否保证在写入返回时数据(而不是元数据)已传输?
顺便问一下,“传输”是指数据在磁盘上吗?
来自手册页:“O_DIRECT..不提供 O_SYNC 标志的保证,即 数据 和必要的元数据被传输”。阅读 O_SYNC 以了解 Linux 做出的相关保证。此外,“传输”永远不能保证数据在磁盘上。这是一个非常复杂的问题,由于底层系统(I/O 控制器、总线等),永远无法完全保证
【参考方案1】:
(此答案适用于 Linux - 其他操作系统可能有不同的警告/语义)
让我们从子问题开始:
如果我打开一个带有 O_DIRECT 标志的文件,这是否意味着每当对该文件的写入(阻塞模式)返回时,数据就在磁盘上?
否(如@michael-foukarakis commented) - 如果您需要保证您的数据已进入非易失性存储,您必须使用/添加其他内容。
O_DIRECT 的真正含义是什么?
这是一个提示,您希望您的 I/O 绕过 Linux 内核 的缓存。实际会发生什么取决于以下情况:
磁盘配置 打开的是块设备还是文件系统中的文件 如果使用文件系统中的文件 使用的确切文件系统以及文件系统和文件上使用的选项 您的 I/O 是否正确对齐 文件系统是否必须进行新的块分配以满足您的 I/O 如果底层磁盘是本地磁盘,在到达磁盘块设备之前,您的内核存储堆栈中有哪些层 Linux 内核版本 ...上面的列表并不详尽。
在“最佳”情况下,设置O_DIRECT
将避免在传输数据时制作额外的数据副本,并且调用将在传输完成后返回。在直接打开“真实”本地磁盘的块设备时,您更有可能出现这种情况。如前所述,即使此属性也不能保证成功调用write()
的数据在突然断电后仍能幸免于难。如果数据是从 RAM DMA 到非易失性存储(例如电池支持的 RAID 控制器)或 RAM 本身是持久性存储,那么您可以保证数据到达稳定的存储,可以在电力损失中幸存下来。要知道是否是这种情况,您必须限定您的硬件堆栈,这样您就不能普遍假设。
在“最坏”的情况下,O_DIRECT
可能毫无意义,即使设置它没有被拒绝并且后续调用“成功”。有时,Linux 存储堆栈中的某些东西(例如 某些 文件系统设置)可以选择忽略它,因为它们必须做的事情或者因为您不满足要求(这是合法的)而只是默默地做而是缓冲 I/O(即写入缓冲区/满足从已缓冲数据的读取)。目前尚不清楚是否会做出额外的努力来确保确认写入的数据至少“与设备一起”(但在O_DIRECT
和屏障线程中,Christoph Hellwig 发布了the O_DIRECT
fallback will ensure data has at least been sent to the device)。更复杂的是,使用O_DIRECT
并不意味着文件元数据,所以即使通过调用完成写入 data 是“与设备”,关键文件元数据(比如文件的大小,因为你正在做附加)可能不是。因此,您实际上可能无法获取您认为在崩溃后传输的数据(它可能会出现截断,或全为零等)。
虽然简短的测试可以使它看起来像单独使用 O_DIRECT
的数据总是意味着数据将在写入返回后存储在磁盘上,但更改内容(例如,使用 Ext4 文件系统而不是 XFS)可能会大大削弱实际实现的效果方式。
当您提到“保证数据”(而不是元数据)时,也许您正在寻找O_DSYNC
/fdatasync()
?如果你想保证元数据也被写入,你必须查看O_SYNC
/fsync()
。
参考文献
Ext4 Wiki: Clarifying Direct IO's Semantics。还包含有关O_DIRECT
在一些非 Linux 操作系统上的作用的注释。
“[PATCH 1/1 linux-next] ext4:向补丁添加兼容性标志检查”LKML 线程有来自 Ext4 首席开发人员 Ted Ts'o 的回复,他谈到了 filesystems can fallback to buffered I/O for O_DIRECT
rather than failing the open()
call 的方法。
在“ubifs:允许 O_DIRECT”LKML 线程中,Btrfs 首席开发人员 Chris Mason 指出 Btrfs resorts to buffered I/O when O_DIRECT
is requested on compressed files。
ZFS on Linux commit message discussing the semantics of O_DIRECT
in different scenarios。另请参阅(在 2020 年年中撰写本文时)proposed new O_DIRECT
semantics for ZFS on Linux(交互很复杂,无法简要解释)。
Linux open(2) man page(在Description section 和Notes section 中搜索O_DIRECT
)
Ensuring data reaches diskLWN文章
臭名昭著的Linus Torvalds O_DIRECT LKML thread summary(有关更多上下文,您可以查看full LKML thread)
【讨论】:
与写入套接字不同,您写入的所有字节是否总是在一次写入中提交?我假设即使不是,它也永远不会写至少 PAGE_SIZE 个批次? @Gukki5 如果我们在一般情况下谈论 Linux,答案是否定的 - 你不能保证普通的write(2)
不会被块层分开(你可能是有兴趣阅读***.com/a/61832882/2732969 和***.com/a/59403297/2732969)。此外,如果磁盘支持它,您可以合法地写入小于 PAGE_SIZE(许多最近的磁盘可能会执行 RMW,因此它可以支持 512 字节的扇区),这是在您考虑 some Linux platforms have PAGE_SIZE==64k...
谢谢!阅读一切。我的 NVMe 设备有 max_hw_sectors_kb:2048
和 max_sectors_kb:1280
logical_block_size:512
。所以即使在最前沿的 Linux 内核上,一个文件的单个write()
永远不会写入超过 1280KB?所以提交比这更大的写入没有意义?以上是关于O_DIRECT 的真正含义是啥?的主要内容,如果未能解决你的问题,请参考以下文章