在ext4文件系统中,覆盖一个小文件是否具有原子性?

5
假设我们有一个大小为FILE_SIZE字节的文件,并且:
  • FILE_SIZE <= min(page_size,physical_block_size);
  • 文件大小不会改变(即不执行truncate()或追加write());
  • 仅通过完全覆盖其内容来修改文件:

    pwrite(fd,buf,FILE_SIZE,0);
    

ext4上是否保证:

  1. 这样的写入与并发读取相对应是原子性的吗?
  2. 这样的写入在系统崩溃时是事务性的吗?

    (即,在崩溃后,文件的内容完全来自某个以前的写入,我们永远不会看到部分写入或空文件)

第二点是否正确:

  • 使用data=ordered
  • 使用data=journal或单个文件启用日志记录?

    (使用ioctl(fd,EXT4_IOC_SETFLAGS,EXT4_JOURNAL_DATA_FL)

  • physical_block_size<FILE_SIZE<=page_size时?


我找到了相关问题(链接),其中包含2011年的讨论。但是:

  • 我没有找到对我的问题2的明确答案。
  • 我想知道,如果上述内容是真实的,它是否已经在某个地方记录下来了?

Ext4 在使用 data=ordered 或者 data=journal 时不是原子的。只有在使用 data=writeback 时,写操作才会发生在同一个地方。 - Irfan Latif
2个回答

7

根据我的实验,它并不是原子性的。

基本上,我的实验是有两个进程,一个写进程和一个读进程。写进程在循环中向文件写入数据,读进程从该文件读取数据。

写进程:

char buf[][18] = {
    "xxxxxxxxxxxxxxxx",
    "yyyyyyyyyyyyyyyy"
};
i = 0;
while (1) {
   pwrite(fd, buf[i], 18, 0);
   i = (i + 1) % 2;
}

读取器进程

while(1) {
    pread(fd, readbuf, 18, 0);
    //check if readbuf is either buf[0] or buf[1]
}

运行这两个进程一段时间后,我发现readbuf的值要么是xxxxxxxxxxxxxxxxyy,要么是yyyyyyyyyyyyyyyyxx。因此可以明确地看出写操作不是原子性的。在我的情况下,16字节的写操作总是原子性的。
答案是:除了管道外,POSIX没有强制规定写入/读取的原子性。我看到的16字节原子性是特定于内核的,未来可能会发生变化。
有关答案的详细信息,请参见实际帖子: write(2)/read(2) atomicity between processes in linux

3
我熟悉文件系统的理论知识,但不了解Ext4的实现细节。这只是我的猜测。
是的,我相信一个扇区的读写操作将是原子性的。
  • 您提供的链接引用了“当前并发读/写仅在单个页面方面是原子的,但在系统调用方面不是。”
  • 磁盘扇区(512字节)的写入是根据Stephen Tweedie的说法是原子的。在与他的私人邮件交流中,他承认这种保证只有硬件可以做到。
  • Ext文件系统会就地覆盖数据,没有写时复制。没有分配。
  • 一些工作正在实现内联数据,非常小的文件数据可以适合于inode本身。如果您只需要存储几个字节,则可能会产生影响。

不确定一页,但在完全日志记录模式下,在提交之前发送少于一页的内容将毫无意义。


感谢您的回答。 - gavv
顺便说一下,现在大多数磁盘使用4 KiB扇区。 - rich remer

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