open(2)中的O_SYNC和O_DIRECT标志是不同的/相似的?

O_SYNC和O_DIRECT标志的使用和效果非常混乱,并且在各个平台之间似乎有所不同。 从Linux手册页(请参阅此处的示例),O_DIRECT提供了同步I / O,最大限度地减less了caching效应,并且需要您自己处理块大小alignment。 O_SYNC只保证同步I / O。 尽pipe两者都保证数据写入硬盘caching,但我相信直接I / O操作应该比简单的同步I / O更快,因为它们绕过了页面caching(虽然FreeBSD的open(2)手册页声明当使用O_SYNC时,高速caching被旁路,见这里 )。

O_DIRECT和O_SYNC标志之间的区别究竟是什么? 一些实现build议使用O_SYNC | O_DIRECT。 为什么?

O_DIRECT独自承诺内核将避免将数据从用户空间复制到内核空间,而是直接通过DMA(直接存储器访问;如果可能的话)直接写入。 数据不会进入caching。 没有严格的保证,只有在所有数据传输完毕后,函数才会返回。

O_SYNC保证在所有数据传输到磁盘之前调用不会返回 (就操作系统而言)。 这仍然不能保证数据不在硬盘写入caching中的某个位置,但是它和操作系统可以保证的一样多。

O_DIRECT | O_SYNC是这些的组合,即“DMA +保证”。

请参阅这篇文章,了解O_DIRECT和O_SYNC的angular色及其对数据完整性的影响:

https://lwn.net/Articles/457667/

在Linux 2.6下的Actuall,o_direct是同步的,请参阅手册页:

打开的manpage,有关于它的2节

在2.4以下,不能保证

O_DIRECT(从Linux 2.4.10开始)尽量减lessI / O对这个文件的caching效应。 一般而言,这会降低性能,但在特殊情况下非常有用,例如应用程序执行自己的caching时。 文件I / O直接进入/来自用户空间缓冲区。 O_DIRECT标志本身会尽力同步传输数据,但不能保证传输数据和必要的元数据的O_SYNC标志。 为了保证同步I / O,除了O_DIRECT之外,还必须使用O_SYNC。 进一步讨论见下面的注释。

(8)中描述了块设备的语义相似(但不赞成使用)的接口。

但在2.6以下保证,请参阅

O_DIRECT

O_DIRECT标志可能对用户空间缓冲区的长度和地址以及I / O的文件偏移量施加alignment限制。 在Linux中,alignment限制因文件系统和内核版本而异,可能完全不存在。 但是,目前没有文件系统无关的接口来让应用程序发现给定文件或文件系统的这些限制。 有些文件系统提供了自己的接口,例如xfsctl(3)中的XFS_IOC_DIOINFO操作。

在Linux 2.4下,传输大小以及用户缓冲区和文件偏移量的alignment方式都必须是文件系统逻辑块大小的倍数。 在Linux 2.6下,alignment到512字节的边界就足够了。

如果内存缓冲区是私有映射(即,使用mmap(2)MAP_PRIVATE标志创build的任何映射,那么O_DIRECT I / O不应与fork(2)系统调用同时运行;这包括分配在堆上的内存和静态分配缓冲区)。 任何这样的I / O,无论是通过asynchronousI / O接口还是从进程中的另一个线程提交,都应在fork(2)被调用之前完成。 如果不这样做,可能会导致父进程和subprocess中的数据损坏和未定义的行为。 当使用shmat(2)或mmap(2)和MAP_SHARED标志创buildO_DIRECT I / O的内存缓冲区时,此限制不适用。 当内存缓冲区被madvise(2)build议为MADV_DONTFORK时,这个限制也不适用,确保它在fork(2)之后不会被子对象使用。

SGI IRIX中引入了O_DIRECT标志,它具有类似于Linux 2.4的alignment限制。 IRIX还有一个fcntl(2)调用来查询适当的路线和尺寸。 FreeBSD 4.x引入了一个同名的标志,但没有alignment限制。

在内核版本2.4.10的Linux下添加了O_DIRECT支持。 较老的Linux内核只是忽略这个标志。 某些文件系统可能无法实现该标志,如果使用了EINVAL,open()将会失败。

应用程序应该避免将O_DIRECT和正常I / O混合到同一个文件,特别是在同一个文件中重叠的字节区域。 即使文件系统在这种情况下正确处理一致性问题,总体I / O吞吐量可能比单独使用任一模式都要慢。 同样,应用程序应避免将具有直接I / O的文件的mmap(2)混合到相同的文件中。

O_DIRECT与NFS的行为将不同于本地文件系统。 较老的内核或以某种方式configuration的内核可能不支持这种组合。 NFS协议不支持将标志传递给服务器,所以O_DIRECT I / O只会绕过客户端上的页面caching; 服务器可能仍然cachingI / O。 客户端请求服务器使I / O同步以保留O_DIRECT的同步语义。 有些服务器在这种情况下性能会很差,尤其是在I / O规模较小的情况下。 某些服务器也可能被configuration为向客户说谎已经达到稳定存储的I / O; 这将在服务器电源故障时避免性能损失对数据完整性造成一定风险。 Linux NFS客户端对O_DIRECT I / O没有alignment限制。

总之,O_DIRECT是一个潜在的强大工具,应谨慎使用。 build议应用程序使用O_DIRECT作为默认禁用的性能选项。

“O_DIRECT总是让我感到不安的是,整个界面只是愚蠢的,而且很可能是由一群精神错乱的猴子在一些严肃的控制精神的物质上devise的。”— Linus

AFAIK,O_DIRECT绕过页面caching。 O_SYNC使用页面caching,但立即同步。 页面caching在进程之间共享,所以如果有另一个进程在同一个文件上工作而没有O_DIRECT标志,可以读取正确的数据。