块设备提供缓冲。这意味着write()
在内核将数据写入设备之前,块设备上可以返回成功。程序可以通过调用来等待所有缓冲的写入fsync()
。
我已经使用dd
(或cat
)将文件系统映像写入设备。这些命令默认不调用fsync()
。
接下来,假设我要将mount
写入的块设备作为文件系统。
我认为sync
在安装它之前使用该命令是最安全的。但是如果我不同步块设备怎么办?文件系统是否有可能尝试读取一些尚未写入设备的块?那么它可以读取设备的旧内容,而不是文件系统映像中的正确数据吗?
我的主要兴趣是 Linux 行为。(而且 StackExchange 鼓励我提出一个具体问题。不过,我也可以对任何替代或历史行为表示赞同 :-)。
当程序关闭块设备文件时,Linux 会刷新相关的缓存,迫使程序等待。然而,这只适用于最后一个
close()
。如果其他东西仍然打开块设备,则不会发生这种情况。包括同一块设备的任何分区是否仍然打开。所以在一般情况下,最好以某种方式同步设备。
为了安全起见,您应该同步设备的方式是
dd
使用选项运行您的命令conv=fsync
。没有这个,内核将不会返回写入错误。dmesg
因此,如果您查看内核日志 ( ) ,您只会注意到一个错误。除了等待所有缓存的写入之外,最后一个
close()
还丢弃所有缓存 (kill_bdev()
)。通过查看命令的输出,我已经为自己验证了这一点free
。linux-4.20/fs/block_dev.c:1778
如果您不熟悉 C 代码,上面的最后一个块相当于:
您只需要
sync
/fsync
来正确处理系统崩溃。内核为您提供一致性。任何写入都将在脏缓冲区中,直到刷新到磁盘,并且任何读取都将首先从这些脏缓冲区中得到响应。
但是,如果您在同步之前断电,内核缓冲区就会消失,并且您的 dd(1) 的一部分将不会被持久化。那可能很尴尬。
除了崩溃之外,您基本上可以忘记缓冲,因为内核透明地处理它。