实际上在 linux 2.6 下,o_direct 是同步的,参见手册页:
打开的联机帮助页,有 2 部分关于它..
2.4以下不保证
O_DIRECT(自 Linux 2.4.10 起)尝试最小化该文件的 I/O 对缓存的影响。一般来说,这会降低性能,但在特殊情况下很有用,例如当应用程序进行自己的缓存时。文件 I/O 直接与用户空间缓冲区进行。O_DIRECT 标志自己努力同步传输数据,但不提供 O_SYNC 标志的保证,即传输数据和必要的元数据。为了保证同步 I/O,除了 O_DIRECT 之外,还必须使用 O_SYNC。有关进一步讨论,请参见下面的注释。
raw(8) 中描述了块设备的语义相似(但已弃用)的接口。
但在 2.6 以下是有保证的,请参阅
O_DIRECT
O_DIRECT 标志可能会对用户空间缓冲区的长度和地址以及 I/O 的文件偏移量施加对齐限制。在 Linux 中,对齐限制因文件系统和内核版本而异,并且可能完全不存在。然而,目前没有独立于文件系统的接口供应用程序发现给定文件或文件系统的这些限制。一些文件系统为此提供了自己的接口,例如 xfsctl(3) 中的 XFS_IOC_DIOINFO 操作。
在 Linux 2.4 下,传输大小,以及用户缓冲区和文件偏移的对齐方式都必须是文件系统逻辑块大小的倍数。在 Linux 2.6 下,对齐到 512 字节边界就足够了。
如果内存缓冲区是私有映射(即使用 mmap(2) MAP_PRIVATE 标志创建的任何映射;这包括在堆上分配的内存和静态分配的内存,则 O_DIRECT I/O 不应与 fork(2) 系统调用同时运行分配的缓冲区)。任何此类 I/O,无论是通过异步 I/O 接口还是从进程中的另一个线程提交,都应在调用 fork(2) 之前完成。如果不这样做,可能会导致父进程和子进程中的数据损坏和未定义的行为。当 O_DIRECT I/O 的内存缓冲区是使用带有 MAP_SHARED 标志的 shmat(2) 或 mmap(2) 创建的时,此限制不适用。当使用 madvise(2) 将内存缓冲区建议为 MADV_DONTFORK 时,此限制也不适用,确保在 fork(2) 之后它对子级不可用。
O_DIRECT 标志是在 SGI IRIX 中引入的,它具有类似于 Linux 2.4 的对齐限制。IRIX 还有一个 fcntl(2) 调用来查询适当的对齐方式和大小。FreeBSD 4.x 引入了同名标志,但没有对齐限制。
在 Linux 内核版本 2.4.10 中添加了 O_DIRECT 支持。较旧的 Linux 内核只是忽略此标志。一些文件系统可能没有实现该标志,并且如果使用 open() 将失败并显示 EINVAL。
应用程序应避免将 O_DIRECT 和普通 I/O 混合到同一文件中,尤其是同一文件中的重叠字节区域。即使文件系统在这种情况下正确处理了一致性问题,总体 I/O 吞吐量也可能比单独使用任何一种模式都要慢。同样,应用程序应避免将具有直接 I/O 的文件的 mmap(2) 混合到相同的文件中。
NFS 的 O_DIRECT 行为将不同于本地文件系统。较旧的内核或以某些方式配置的内核可能不支持这种组合。NFS 协议不支持将标志传递给服务器,因此 O_DIRECT I/O 只会绕过客户端上的页面缓存;服务器可能仍会缓存 I/O。客户端要求服务器使 I/O 同步以保留 O_DIRECT 的同步语义。在这些情况下,某些服务器的性能会很差,尤其是在 I/O 大小很小的情况下。一些服务器也可能被配置为向客户端谎称 I/O 已达到稳定存储;这将避免在服务器电源故障时对数据完整性造成一定风险的性能损失。Linux NFS 客户端对 O_DIRECT I/O 没有对齐限制。
总之,O_DIRECT 是一个潜在的强大工具,应谨慎使用。建议应用程序将 O_DIRECT 的使用视为默认禁用的性能选项。
“O_DIRECT 一直困扰着我的一点是,整个界面简直是愚蠢的,而且可能是由一只发疯的猴子在一些严重的精神控制物质上设计的。”---Linus