如何原子分配循环设备?

如何原子分配循环设备?

我正在编写一些 shell 脚本来处理一些磁盘映像内容,并且我需要使用循环设备来访问一些磁盘映像。但是,我不确定如何正确分配循环设备而不使我的程序面临竞争条件。

我知道我可以用来losetup -f获取下一个未分配的循环设备,然后像这样分配该循环设备:

ld=$(losetup -f)
sudo losetup $ld myfile.img
dostuffwith $ld

然而,在我想同时运行程序的多个实例的情况下,这几乎是竞争条件的教科书示例,这让我很困扰。如果我运行该程序的多个实例,或者其他程序也尝试获取循环设备,则每个进程可能无法在下一个调用之前分配循环设备losetup -f,在这种情况下,两个进程都会认为同一个循环设备可用,但只有一个人可以获得。

我可以为此使用外部同步,但我想(如果可能)避免额外的复杂性。此外,使用循环设备的其他程序不太可能尊重我可能提出的任何同步。

我怎样才能避免这种潜在的竞争状况?理想情况下,我希望能够自动发现并绑定循环设备,例如使用如下命令:

ld=$(sudo losetup -f myfile.img)
dostuffwith $ld

但是,当我这样做时,$ld不会分配给循环设备路径,并且将其移出sudo,如sudo ld=$(losetup -f myfile.img)给出权限错误。

答案1

这是并发中的一个经典问题:分配资源时,您需要自动确定资源是否空闲并保留它,否则另一个进程可能会在您检查资源空闲和保留资源之间保留该资源。

请使用losetup的自动分配模式(-f),并传递--show选项使其打印循环设备路径。

ld=$(sudo losetup --show -f /tmp/1m)

该选项自 2.13 版本以来就存在于 util-linux 中(最初添加为-s,但--show已在所有发布的版本中得到支持,并且最近的版本已删除了-s选项名称)。不幸的是 BusyBox 版本没有它。

Linux 内核版本 3.1介绍一种通过新设备直接在内核中执行循环设备分配操作的方法/dev/loop-control。此方法仅从 util-linux 2.21 开始支持。当 kernel <3.1 或 util-linux <2.21 时,程序losetup会枚举循环设备条目以保留一个。但我在代码中看不到竞争条件;它应该是安全的,但它可能有一个小窗口,在此期间它会错误地报告所有设备都已分配,即使情况并非如此。

答案2

我想到了。虽然我不确定许可问题是如何发生的,但我可以先拍摄,然后再询问,如下所示:

sudo losetup -f myfile.img
ld=$(losetup -j myfile.img | grep -o "/dev/loop[0-9]*")
dostuffwith $ld

答案3

你可以使用flock

  tryagain=1
  while [[ $tryagain -ne 0 ]]; do
    ld=`losetup -f`
    flock -n $ld -c "losetup $ld myfile.img"
    tryagain=$?
  done

这里的想法是你尝试flock循环设备文件;如果同一脚本的另一个实例首先获取它,它将被调用losetup $ld myfile.imgflock返回 0。对于输掉比赛的脚本,losetup将不会被调用并flock返回 1,从而导致循环重复。

更多信息请参见man flock.

答案4

如果您想要将映像作为环回设备进行的操作是将其挂载为文件系统并使用内容,则该mount命令可以自动处理此操作。

mount -o loop myfile.img /tmp/mountpoint

相关内容