应该在每次 fclose 之后使用 fsync 吗?

Should fsync be used after each fclose?

在 Linux(Ubuntu 平台)设备上,我使用文件来保存任务关键数据。

有时(大约 10,000 个案例中会出现一次)文件会因不明原因而损坏。 特别是,文件被截断了(而不是几千字节,它只有大约 100 字节)。

现在,在软件的顺序中

  1. 文件已打开,
  2. 修改和
  3. 关闭。

在那之后,文件可能会再次打开 (4),并且正在执行其他操作。

到目前为止我没有注意到,fflush(在fclose 上调用)不会写入文件系统,而只会写入中间缓冲区。可能是 3) 和 4) 之间的时间太短,2) 的变化还没有写入光盘,所以当我用 4) 重新打开时,我得到一个截断的文件,当它再次关闭时会导致这些数据会永久丢失吗?

在这种情况下,我应该在每次写入文件后使用 fsync() 吗?

停电需要注意什么?数据损坏与断电有关的可能性不大。

fwrite 首先写入内部缓冲区,然后有时(在 fflushfclose 或缓冲区已满时)调用 OS 函数 write.

OS 也在做一些缓冲,写入设备可能会延迟。

fsync 确保 OS 正在将其缓冲区写入设备。

在您打开-写入-关闭的情况下,您不需要fsync。 OS 知道文件的哪些部分尚未写入设备。因此,如果第二个进程想要读取文件,OS 知道它在内存中有文件内容,并且不会从设备读取文件内容。

当然,在考虑停电时,fsync 可能(视情况而定)是一个好主意,以确保将文件内容写入设备(正如安德鲁指出的那样,确实不一定意味着内容被写入光盘,因为设备本身可能会做缓冲)。

Up to now I didn't notice, that fflush (which is called upon fclose) doesn't write to the file system, but only in an intermediate buffer. Could it be, that the time between 3) and 4) is too short and the change from 2) is not yet written to disc, so when I reopen with 4) I get a truncated file which, when it is closed again leads to permanent loss of those data?

没有。以这种方式运行的系统将无法使用。

Should I use fsync() in that case after each file write?

不,那只会减慢速度。

What do I have to consider for power outtages? It is not unlikeley, that the data corruption is related to power down.

使用能够抵抗此类损坏的文件系统。甚至可能考虑使用更安全的修改算法,例如用不同的名称写出文件的新版本,同步,然后在现有文件之上重命名。

如果你正在做的是这样的:

FILE *f = fopen("filename", "w");
while(...) {
    fwrite(data, n, m, f);
}
fclose(f);

然后可能发生的情况是另一个进程可以在写入文件时打开文件(在 C 库在幕后运行的 openwrite 系统调用之间,或者在单独的 write 调用)。然后他们只会看到部分写入的文件。

解决方法是用另一个名称写入文件,rename() 它覆盖实际的文件名。缺点是您需要双倍的 space.

如果您确定文件的打开仅在写入 之后发生,则不会发生这种情况。但是作者和 reader 之间必须有一些同步,这样后者才不会过早开始阅读。

fsync() 告诉系统将更改写入实际存储,这在其他 POSIX 系统调用中有点奇怪,因为我认为没有指定任何内容如果系统崩溃,这是唯一重要的情况,如果某些数据存储在实际存储中,而不是某些缓存中。即使使用 fsync(),存储硬件仍有可能缓存数据,或者当系统崩溃时,不相关的损坏仍然可能破坏文件系统。

如果你愿意让 OS 完成它的工作,并且不需要考虑崩溃,你可以完全忽略 fsync() 并让数据在OS 认为合适。如果您确实关心崩溃,则必须更仔细地研究文件系统提供(或不提供)的保证。例如。至少在某些时候,ext* 开发人员非常要求应用程序也对包含目录执行 fsync()