抽象的
有时,Linux 内核不知道外部 USB 存储设备的驱动器上写入缓存。在这种情况下是否有必要在分离这些设备之前显式刷新这些缓存?
例子
我使用 WD Elements 外置 USB 硬盘,上面hdparm -I
写着
...
Commands/features:
Enabled Supported:
...
* Write cache
...
和hdparm -W
:
...
write-caching = 1 (on)
另一方面,当我插入驱动器时,我收到以下内核消息:
... No Caching mode page found
... Assuming drive cache: write through
根据这个答案作者:Kyle Jones,这些内核消息表明内核假设其写入操作将直接进入盘片。
文件的“write_cache (RW)”部分文档/块/queue-sysfs.txtLinux 内核文档中描述了内核假设写入缓存模式的含义(感谢韦恩·康拉德):
...“直写”,...还将消除内核发出的缓存刷新。
问题
到目前为止,我从 Linux 系统中分离外部 USB 存储设备的标准方法是卸载其上所有已安装的分区,等待驱动器的 LED 停止闪烁,以物理方式拔下 USB 连接器,如果这不能关闭 USB 存储设备的电源,设备(有些有单独的电源),以显式关闭其电源。
这种方法是否安全,或者是否意味着存在丢失驱动器上写入缓存中未刷新数据的风险,特别是在内核不知道该缓存的情况下?
在后一种情况下,似乎建议在卸载后通过发送 SCSI 同步命令来显式刷新驱动器上的写入缓存。例如,可以使用sg_sync
sg3-utils 附带的命令来完成此操作:
sg_sync <device>
这能解决问题吗?或者应该通过向设备发出 SCSI 停止命令来补充这一点?
后者可以使用(同样是 sg3-utils):
sg_start 0 -r <device>
sg_sync
是否是sg_start
用于此目的的正确工具,或者最好使用我在下面“相关方法”部分中提到的工具和方法之一,还是采取其他措施来处理问题?
要指出这个问题的相关性,请参阅这条评论通过确认。
请注意:我并不是在寻找一种主要通过软件来降低硬盘转速或关闭硬盘电源的方法——拔掉驱动器插头并使用电源开关已被证明在这方面相当可靠。相反,我正在寻找一种方法,确保在驱动器关闭之前所有写入的数据都已写入非易失性存储,包括驱动器上缓存的数据。
相关方法
在下文中,我对我发现的与刷新驱动器缓存或更一般的与可移动存储设备的“安全删除”相关的方法进行了一些评论。一方面是现有 Linux 系统上所涉及工具的可用性。这很重要,因为并不总是可以简单地安装缺失的软件。
桌面环境:某些桌面环境提供用于“安全删除”外部 USB 存储设备的小部件。例如,请参阅以下问题:
”弹出/安全删除与卸载” 作者:LGenzelis,
”Gnome 中的“弹出 USB 驱动程序”如何工作?“作者:k.Cyborg。
以及相关帖子。
根据实现的不同,这些小部件似乎会关闭设备电源,但我没有找到任何参考来阐明它们是否会导致设备提前刷新其缓存,特别是在内核不知道外部驱动器缓存的情况下。
另外,很多Linux系统(例如纯服务器)没有安装任何桌面环境。所以这个方法并不总是可用。
优盘:根据这个答案通过吉米,udisks
由 Freedesktop.org 提供可以从命令行使用“安全删除”外部 USB 存储设备:
udisks --unmount /dev/sda1
udisks --detach /dev/sda
这很好的答案Totor 描述了该udisks --detach
命令的作用:
- 发送 SCSI 同步缓存命令,
- 发送 SCSI 停止命令,
- 解除USB存储内核驱动程序的绑定,
- 暂停USB设备(电源),
- 从逻辑上禁用/从 USB 端口删除它。
因此它明确地处理驱动器上的缓存。然而,udisks
它只适用于我必须处理的大约一半的 Linux 系统。
乌迪斯克特尔:udisks 的最新版本提供了该程序udisksctl
,可用于替代udisks
上面显示的命令。这又是根据吉米的回答:
udisksctl unmount -b <partition>
udisksctl power-off -b <device>
power-off
同样的答案还引用了命令中的描述udisksctl(1) 手册页:
关闭电源
安排安全移除驱动器并关闭电源。在操作系统方面,这包括确保没有进程正在使用驱动器,然后请求将运行中的缓冲区和缓存提交到稳定的存储。
不幸的是,这并没有指定“运行中的缓冲区和高速缓存”是否包括内核不知道的外部驱动器上的高速缓存。但在这方面它很可能udisksctl
遵循其前身。udisks
不幸的是,在现有系统上的可用性相当低(例如,udisksctl
与 的可用性相比)方面,它确实遵循了它的前身。umount
喷射:根据它的手册页,命令行工具eject
可用于在软件控制下弹出可移动介质。受影响的分区将根据需要提前卸载。
尽管此工具出现在有关可移动媒体的“安全删除”的多个讨论中,但请参见示例这个问题由 LGenzelis 和这个问题k.Cyborg 表示,没有什么表明它在这方面比卸载更多。
此外,我怀疑该工具更多地关注媒体和媒体托盘而不是设备。这可能是它直接死掉并显示错误消息的原因
eject: unable to eject
当它应用于我在上面的介绍性示例中提到的 WD Elements USB 驱动器时。但是,它在某些 USB 记忆棒上成功。
尽管如此,作为 linux-utils 的一部分,这个工具是高度可用的。
sg3-utils:这些程序sg_sync
已经sg_start
在上面讨论过。
这条评论Ubuntu 错误报告表明udisks
内部使用 sg3-utils 将其 SCSI 同步和停止命令发送到设备。
在我看来,sg3-utils 比 udisk 具有更广泛的可用性。但这只是一个模糊的个人印象。
sdparm: 这个网页作者:Yan Li 讨论了“在 Linux 中安全删除 USB 硬盘驱动器”的过程。为此,它建议一个脚本原则上使用以下sdparm
命令来刷新驱动器上的缓存并停止(旋转?)USB HDD:
sdparm --command=sync <device>
sdparm --command=stop <device>
这些似乎与上面讨论的sg_sync
和sg_start
命令相当,并且可以用作后者的替代品。
hdparm:作为一个管理 ATA 驱动器的工具,hdparm
在某种意义上对于 USB 驱动器来说是一个异物,因为后者在 Linux 中主要被视为 SCSI 设备。在像我们的 WD Elements 示例这样的情况下,SCSI 到 ATA 转换层(SAT 层)后面有一个 ATA HDD。看这个答案作者:Mikko Rantalainen 了解更多详情。根据 SAT 的实现,hdparm
可以使用有限的功能来操纵这些驱动器。
如果支持,可以使用以下命令
hdparm -F <device>
hdparm -Y <device>
刷新驱动器上的缓存并停止驱动器。如果这是不可能的,人们可能会考虑使用
hdparm -W0 <device>
作为刷新缓存的解决方法。但请注意:此命令实际上旨在关闭驱动器上的写入缓存。因此,应该确保它确实刷新而不是简单地删除到目前为止积累的缓存内容。
对于 WD Elements 驱动器,这些命令都不起作用:相反,它们会报告bad/missing sense data
.
系统文件系统:网络上散布着一些方法,可以将外部 USB 驱动器与其驱动程序解除绑定,从系统中取消驱动器的注册,或者通过操作 Linux 内核在其 sysfs 中公开的设备属性来关闭驱动器。
这是一个例子这个帖子通过 Debian 论坛中的 bash:
echo "auto" > "/sys/bus/usb/devices/usb1/1-5/power/level"
echo "1-5:1.0" > /sys/bus/usb/devices/1-5\:1.0/driver/unbind
和
echo "1" > "/sys/bus/usb/devices/usb1/1-5/remove"
或来自这个答案作者:托尼·乔治
echo 'offline' > /sys/block/sdb/device/state
echo '1' > /sys/block/sdb/device/delete
我对内核开发人员心中关于这些属性的使用的概念知之甚少,无法判断这些代码片段。但我有些怀疑它们是否有助于刷新内核不知道的驱动器上的写入缓存。
此外,这些食谱中至少有一些似乎已经过时了。关于这一点,请参见“系统文件系统规则截至 2019 年 1 月 25 日的内核文档中:
内核导出的 sysfs 导出内部内核实现细节,并依赖于内部内核结构和布局。内核开发人员一致认为Linux内核不提供稳定的内部API。因此,sysfs 接口的某些方面可能在各个内核版本之间不稳定。
卸载并等待:这是我在上面的问题中提到的方法:它包括卸载和随后的等待,直到驱动器上的(大概)写入活动最终停止。下一步也是最后一步是希望在此过程中刷新驱动器上的写入缓存。
这个问题的要点是澄清这是否是一种安全的方法(对于数据)。
无论如何,这种方法有一个很大的优点,那就是它很简单,它可以在我所知道的任何 Linux 系统上使用,而且命令的语法umount
几十年来没有改变。
进一步阅读
关于 USB 或其他外部存储设备的“弹出”和“安全移除”的一些一般性讨论可以在以下问题的上下文中找到:
”在 Linux 上删除 USB 驱动器的最安全方法 [重复]” 由 Pkkm 提供,
”弹出 USB 驱动器/弹出命令“乔·巴尔著,
”什么时候可以安全地断开外部硬盘驱动器?”,作者:jcora。
此外,路易斯·阿尔瓦拉多 (Luis Alvarado) 在这个答案Ubuntu 桌面环境提供的“卸载”、“弹出”和“安全删除驱动器”选项之间的差异,特别是“安全删除驱动器”不仅仅是卸载。关于后者,另见
许多贡献都认为,一旦卸载了外部存储设备,就可以“安全地删除”它。这里有一些例子:
除了卸载之外,一些贡献还侧重于降低外部 HDD 的转速。参见示例这个问题通过温彻登斯普林斯。在这条评论,sourcejedi 指出,降低 USB 驱动器的转速可以降低其受到机械干扰的脆弱性。
其他人的目标是关闭 USB 驱动器:
在以下贡献中,关于存储设备的“安全删除”明确提到了驱动器上的缓存:
后者是我发现的唯一贡献,它指出了由于内核对外部驱动器上写入缓存的错误假设而可能引起的损害。这正是这个问题的焦点。根据该评论,仅仅卸下驱动器不足以防止这种损坏。进一步的细节和可能的正确方法将受到高度赞赏。
答案1
首先,这是一个很棒且写得很好的问题。给OP竖起大拇指!不幸的是,我无法投票赞成这个问题,因为我没有足够的积分。
以下是根据我所了解的官方 SD 标准,对 microSD 卡的行为方式进行的简要总结。当然,这不适用于 USB 存储设备,但可以很好地洞察潜在问题。
简而言之,microSD 卡可以被告知准备移除,但它仍然可能有一些“不可见”的内部写入缓存,即使在卡响应“准备移除”后,这些缓存也可能不会完全刷新。命令。 SD 标准将此类行为留给卡制造商自行决定。因此,一般来说,microSD 卡在移除之前应该有一段相当不确定的时间,以刷新其“不可见”的写入缓存。归根结底就是等待 20 秒左右。
另一个例子是英特尔官方对其部分 PCI Express 扩展卡形式的企业级 SSD 的说法:通电后大约半分钟(或一分钟,我忘记了具体时间)不要重新打开系统向下。 SSD可能会使用板载电容器作为电源自行执行一些内部维护,这不能被主机系统开机并要求SSD执行某些操作而中断。
考虑到所有这些,我想说,最好在运行umount(8)
并使用 USB 存储设备后等待一段时间,然后再拔出 USB 存储设备eject(1)
。我就是这么做的,尽管跑步就eject(1)
足够了。看,即使您能够找到关于刷新写入缓存(可见或不可见)如何在特定 USB 存储设备上工作的官方低级解释,另一个 USB 存储设备几乎肯定会在内部以至少略有不同的方式运行,使得这一切都不能普遍使用。
请注意,您可以运行eject -v
看看它实际上做了什么。
答案2
这实际上是一个更大的问题,并且已经有解决方案。由于这些磁盘写入缓存而执行速度更快的数据库无法控制它们何时以不协调的方式消失,即内核:在典型的系统中,当磁盘写入缓存丢失时,数据库不会处于循环中,这是由于关键事件。
数据库系统尝试通过在 NMI 上实现处理程序来解决开放系统上的责任与控制之间的差距,NMI 是在大多数(如果不是全部)这些事件(恐慌、机器检查、BIOS 异常等)发生时执行的不可屏蔽中断。 )。不处理 100% 的失败,比这更糟糕的是:永远不要让完美成为优秀的敌人。
该处理程序将首先对所有磁盘缓存执行刷新,然后在稳定时间后通过本地多播向集群中的合作伙伴节点发送一条“I’m Dying”消息,以消除这些节点上的多秒超时。系统必须重新就该节点是否真正启动达成共识(通过加密可以使它们的死亡消息绝对可信)。当多播消息因网络故障而被捕获时,您仍然需要心跳。
这样做的结果是,集群中该节点丢失的分布式恢复可以在少量毫秒内生效(大多数情况下),并且该节点上的磁盘在从磁盘丢失中恢复方面几乎不需要做任何事情缓存。
时间很重要。
Availability = MTBF/(MTBF + MTTR)
[MTBF == 发生故障前的平均时间,MTTR == 平均修复时间。]
当 MTTR 接近零时,可用性接近 1,排除所有无数潜在的故障源:因此 MTTR 是首先要解决的问题。
当然,如果您的数据库具有出色的日志恢复功能(例如免费的 PostgreSQL 等),并且不仅仅依赖于备份,因此永远不会与故障时的数据库状态一致地恢复,那么您可以给自己超低的 MTTR 和超低的 MTTR。崩溃一致数据库的高可用性。
答案3
我一直在互联网上寻找有关通过 USB 连接的外部驱动器上写入缓存的启动错误的答案。要回答第一个问题,a)是的,在拔出 USB 之前刷新缓冲区/缓存非常重要。我建议,无论您喜欢与否,您都需要卸载外部 USB 驱动器,以便操作系统可以确保所有内容都写入硬盘驱动器。 b)阅读我读过的所有内容,并发现答案就在我面前。 “我相信关于未找到缓存页面代码的错误,假设是直写”(在使用journalctl -b命令时发现)是通过USB连接外部硬盘驱动器启动系统所固有的。这是一个好的设计问题! USB设备可以随时拔出。如果他们没有操作系统的意识或没有足够的时间准备,数据就会损坏!因此,journalctl 记录的错误将被我忽略,因为它是设计的一部分。对我来说,避免这些错误的唯一方法是不要通过 /etc/fstab 挂载它们并让它在插入时自动挂载。