Zig*_*saz 6 linux cache block-device
今天我了解到 FreeBSD 完全取消了对块设备的支持。在阅读他们做出决定的理由时,我发现了这一点:
块设备是内核为其提供缓存的磁盘设备。这种缓存使块设备几乎无法使用,或者至少危险地不可靠。缓存将重新排序写入操作的顺序,使应用程序无法在任何时刻及时了解确切的磁盘内容。这使得磁盘上数据结构(文件系统、数据库等)的可预测和可靠的崩溃恢复变得不可能。由于写入可能会延迟,因此内核无法向应用程序报告哪个特定的写入操作遇到了写入错误,这进一步加剧了一致性问题。
(来自https://www.freebsd.org/doc/en_US.ISO8859-1/books/arch-handbook/driverbasics-block.html)
但是我知道 Linux 几乎只使用块设备(尽管一个 CAN 请求一个原始设备)。
那么 Linux 如何规避此引文中提到的问题?还是大多数驱动程序只是请求原始设备?
BSD 的人真的很铁杆,经常做令人惊讶的事情:-) 在我看来,删除块设备层不是问题(例如,nfs 甚至没有底层块设备),但这种推理并不反对块设备,但反对写缓存。在我看来,删除写缓存是一件非常糟糕的事情。如果您的进程向磁盘写入了一些内容,那么在它没有成功之前您不会收回控制权吗?
但我不认为他们不知道他们在做什么。希望有人会在另一个答案中解释他们的原因。
为了清楚地解释这一点,我需要解释一下文件系统是如何工作的。文件系统驱动程序本质上是文件系统操作(目录打开、文件创建、读写、删除等)和块操作之间(例如:“将页面 0xfce2ea31 写入磁盘块 0xc0deebed”)之间的转换层。
但是块操作不会当场到达硬盘。首先,它们将进入块缓存。这意味着,如果文件系统想要将内存页写入磁盘,它首先会写入保留的内存区域。内核的内存管理如果认为它是最优的,就会将这些数据写入硬盘。这可以实现各种速度改进:例如,如果在磁盘的开头和结尾发生许多写操作,内核可以将它们组合在一起,使磁盘头必须尽可能少地重新定位自己。
还有一个改进:如果你的程序写入一个文件,它会经历一个非常快的操作,就像它是一个虚拟磁盘一样。当然,只有在系统的 RAM 未满时才有可能,之后他们必须等待写缓存清空。但只有在一次有大量写入操作时才会发生(例如,您正在复制大文件)。
在文件系统的情况下,在磁盘上运行的文件系统(即块设备)与不在磁盘上运行的文件系统(fe nfs)之间存在很大差异。在第二种情况下,没有块缓存的可能性,因为没有块。在他们的例子中,有一个所谓的“缓冲区缓存”,本质上意味着仍然缓存(读取和写入),但它不是围绕内存块组织的,而是围绕任何大小的 I/O 片段组织的。
是的,在 Linux 中,有“原始”块设备可以在没有块缓存机制的情况下使用磁盘设备。但是这个问题不是他们自己解决的。
取而代之的是所谓的“日志文件系统”。在日志文件系统的情况下,文件系统有机会指示内核,哪些页面必须在其他页面之前写出。如果文件系统中没有日志机制,那么它只会将块写入磁盘(更准确地说:写入块缓存),如果内核认为它是最佳的,则会实际执行真正的写入操作。
你可以把日志文件系统想象成每次写操作都会发生两次:首先,进入一个“日志”,这是磁盘上的一个保留区域,然后才到它的实际位置。在系统崩溃或磁盘错误的情况下,磁盘上一个未损坏状态的内容可以非常快速且轻松地在日志上重建。
但这会显着降低写入性能,因为每次写入都必须进行两次。这就是为什么在现实中日志文件系统以更复杂的方式工作的原因,它们使用各种复杂的数据结构操作来将这种开销降低到几乎不可见的水平。但这很难:例如,ext3 对 ext2 的主要改进是包含了日志,这增加了它的代码大小。
在 Linux 中,块层 API 具有“屏障”机制。文件系统可以在它们的写操作之间设置“屏障”。将阻挡元件,该数据后的屏障将被写入仅磁盘后,每一个数据前的屏障已经写出来。日志文件系统使用屏障机制来指示块层有关实际写入操作所需的顺序。据我所知,他们不使用原始设备映射。
我不知道 FreeBSD 对这个案例做了什么。也许他们消除块设备意味着一切都将使用缓冲区缓存而不是块缓存。或者他们有一些东西,这里没有写。在文件系统内部,*BSD 和 Linux 世界之间存在非常大的差异。