使用 iSCSI 和 systemd 安装多单元卷的竞争条件

使用 iSCSI 和 systemd 安装多单元卷的竞争条件

我已经配置了一个 Linux 系统来挂载通过 iSCSI 提供的卷,从 systemd 挂载单元开始,该挂载单元将 Open-iSCSI 服务作为必需的和先前的单元(即Requires=iscsi.serviceAfter=iscsi.service部分下[Unit])。

该卷跨越多个逻辑单元,并通过 UUID 进行标识以便挂载。

不幸的是,安装操作在启动时并不一致地成功。

我已经确定,在某些启动序列中,尝试挂载操作时至少有一个设备尚未连接。因此出现了竞争条件。

根据各种文档和经验,强烈建议所包含的依赖项应确保等待所有设备都连接后再尝试执行挂载操作。

在尝试执行挂载操作之前,是否有其他目标可以确保所有设备都已连接?

系统运行Linux Mint 21.2,内核为6.2.0。

答案1

首先,上游 open-iscsi 客户端/启动器 systemd 服务不会调用iscsiadm,以便它等到所有登录请求成功后才退出(参考:[1][2])。

所以你可以尝试“最小化”机会你遇到了竞争条件(但并没有真正消除种族本身)ExecStart=通过使用服务代码片段覆盖命令(参见systemctl edit),这样它就不会iscsiadm调用-W

问题是,即使iscsiadm等到所有登录都已完成,AFAICT 也并不意味着它会(甚至不能)等到通用的SCSI 磁盘驱动程序已探测完系统中刚刚填充/虚拟化的所有驱动器。(这就像您完全插入 USB 驱动器的时间并不是内核探测它的时间一样。)

因此,确保多设备 BTRFS 卷的所有设备都存在且已准备好安装该卷的“真正”方法是检查 btrfs 文件系统驱动程序是否已完成扫描/注册它们。

一种方法是拥有如下脚本以及由相应的挂载单元拉取(或者更好的是,拉取)的服务并运行该脚本:

#!/bin/sh
while true; do
  if [ -L /dev/disk/by-uuid/"$1" ] &&
     btrfs device ready /dev/disk/by-uuid/"$1"; then
    break
  fi
done

$1应设置为 UUID用小字母。您甚至可以编写一个 systemd 服务模板并将每个启用实例的服务参数作为脚本参数传递,尽管您可能需要检查连字符的转义规则。)

当然,您需要确保在安装单元之前订购了就绪脚本服务。还要确保使用正确的Type=。(我认为oneshot应该是正确的/没问题。)

此外,您可能想确认您的系统在/dev/disk/by-uuid/first 下创建符号链接。

如果您想使用 ready-script 服务来拉取安装单元,我想您可以依次使用 iscsi 服务来拉取它。

如果多设备卷中的某个设备已被扫描但现在已消失(拔出或其他原因),则PSbtrfs device ready将不会返回,直到您运行。我认为这值得一提,因为当您想在曾经就绪的卷上首先对其进行测试时,该行为可能会让您认为子命令已损坏/无用(就像我一样)。1btrfs device scan -uready

答案2

虽然从逻辑上讲,我的其他答案或评论并没有什么错误,但我确实忽略了显而易见的东西(嗯,不是那么明显)。

默认情况下,systemd 会确保在启动挂载单元之前等待相应的设备单元启动并准备就绪,并且udev 规则这确保了 btrfs(无论是否多设备)卷也是如此。

不幸的是,有一个例外。虽然当您使用例如UUID=...作为 fstab 条目中的第一个字段时,fstab 生成器(将 fstab 条目“翻译”为挂载单元)将转换UUID=.../dev/disk/by-uuid/...设备路径,但如果您使用UUID=...手动编写的挂载单元,systemd 在加载单元文件时不会执行此操作。(但该挂载单元也不会被视为无效。只要将其拉出,systemd 仍会启动它。)

What=使用 egUUID=...而不是设备路径(例如)的结果/dev/disk/by-uuid/...是,挂载单元将不依赖于任何设备单元,因此不会排在任何设备单元之后。因此,它将“尽快”启动。从技术上讲,结果可能是在 UUID 进入系统之前、在组装 btrfs 卷之前或卷准备就绪之后尝试挂载。

因此有两个简单的解决方案:

  • 使用 fstab 条目
  • 在“手写”安装单元中/dev/disk/by-uuid/...使用。What=

没有必要也没有必要向挂载单元添加对 iscsi 服务的依赖/排序。(无论如何iscsiadm工作/要求工作,这都是一个坏主意,因为它可能与默认/隐式依赖和针对目标单元的排序不兼容。即使它不会“弄乱” systemd 的头脑,您也可能会得到错误的期望/假设。更不用说至少在技术上存在的其他探测级别的竞争了。)

PS:我已经提交了上游问题。让我们看看事情会如何发展。

答案3

首先,Requires= 并不意味着 After=。通常两者都需要。

其次,这取决于每个单独的服务何时向 systemd 报告“就绪”。您需要验证 iscsid 是否实现了就绪状态,以表示它已启动并建立了连接,或者它是否仅有的已启动(现在可以接受控制命令)。

由于 iscsid 创建虚拟 /dev/sd 设备,因此依赖在设备上而不仅仅依赖于服务。(换句话说,依赖于实际效果而不是机制。)尽管如此,挂载单元通常已经这样做了,但对于服务,您需要依赖于“dev-disk-bysomething.device”。

相关内容