`O_DIRECT | 有啥区别? O_SYNC` + write() 和 `O_DIRECT` + write() + fsync()

Posted

技术标签:

【中文标题】`O_DIRECT | 有啥区别? O_SYNC` + write() 和 `O_DIRECT` + write() + fsync()【英文标题】:What is the difference between `O_DIRECT | O_SYNC` + write() and `O_DIRECT` + write() + fsync()`O_DIRECT | 有什么区别? O_SYNC` + write() 和 `O_DIRECT` + write() + fsync() 【发布时间】:2021-04-25 22:43:24 【问题描述】:

我想知道两者的区别

    char *text = (char *)malloc(4096);
    memset(text, 'a', 4096);

    int fd = open(filepath, O_RDWR | O_CREAT | O_DIRECT);

    for(int i=0; i<1000; i++) 
        write(fd, (void *)text, 4096);
        fsync(fd);
    

    close (fd);

    char *text = (char *)malloc(4096);
    memset(text, 'a', 4096);

    int fd = open(filepath, O_RDWR | O_CREAT | O_DIRECT | O_SYNC); //<----Difference

    for(int i=0; i<1000; i++) 
        write(fd, (void *)text, 4096);
        // fsync(fd);  <--------------------------------------------------Difference
    

    close (fd);

上面代码的性能比下面的要慢。

【问题讨论】:

可能没有区别 - 由于您不检查返回值,因此两者都未检测到失败;-)。 在更严重的方面,根据 open(2) 手册页,在使用 O_SYNC 标志打开的文件上,写入应该可以工作“就像每次 write(2) 之后都调用 fsync (2)",就是你做的,所以两者应该是等价的。不知道为什么会有差异。智能驱动程序是否仍然可以组合连续的 write()(但如果有中间的 fsync() 则不能)?这在我的书中会违反 O_SYNC 语义保证。 我发现另一件值得注意的事情是文件系统/驱动程序似乎确实也刷新了磁盘缓存。 sync(2) 手册页警告说,由于写入延迟和磁盘缓存,当调用返回时,数据实际上可能尚未在磁盘上。这显然与 fsync() 不同。 循环后的 fsync 可能会大大增加吞吐量,但是,正如已经评论的那样,写入后的 fsync 基本上是 O_SYNC 所做的(不考虑内核的智慧) 感谢您的回答!我的两个 SSD(三星 860 evo 和 980 pro)都出现了巨大的性能差异。我正在考虑通过hdparm -W0 /dev/860evo SATA SSD 来禁用磁盘缓存,但这里还有一个问题:如何禁用 NVMe SSD 的磁盘缓存? 【参考方案1】:

一方面不应该有任何区别,因为在这两种情况下都必须进行相似的工作量(假设没有欺骗,然后写入磁盘刷新)。另一方面,第一种情况必须执行两倍的系统调用,因此(理论上)有更多的开销(特别是如果进行系统调用所花费的时间是执行操作所需的总时间的重要部分)。很可能这取决于磁盘/内核/CPU/I/O的大小等。两者之间是否存在差异以及哪个更快。也许在第二种情况下,内核可以发送设置了 FUA 位的写入,这意味着差异可能取决于您打开的文件/设备(因为这可能控制是否可以进行这种优化)...

使用O_SYNC 也会在write() 调用的返回上出现错误,但正如在其他 cmets 中所指出的那样,您没有检查返回代码...

【讨论】:

以上是关于`O_DIRECT | 有啥区别? O_SYNC` + write() 和 `O_DIRECT` + write() + fsync()的主要内容,如果未能解决你的问题,请参考以下文章

O_DIRECT 的真正含义是啥?

jffs2 Linux 文件系统上的 O_DIRECT 支持

Direct IO

O_DIRECT 与 AIO_RAW

Arch LINux 上未定义 O_DIRECT

关于O_DIRECT的那些事儿