如何自动分配回路设备?


11

我正在编写一些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)权限错误。

Answers:


13

这是并发性中的经典问题:分配资源时,您需要原子确定资源是否可用并保留,否则,另一个过程可能会在您检查其是否可用与保留时间之间保留该资源。

请使用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开始仅支持此方法。对于内核<3.1或util-linux <2.21,该losetup程序枚举循环设备条目以保留一个。我在代码中看不到竞争条件;它应该是安全的,但是它可能会有一个很小的窗口,在该窗口中,即使不是这种情况,它也会错误地报告已分配所有设备。


有什么</dev/tty
斯特凡Chazelas

1
上次我尝试甚至losetup --find --show比赛。for i in {1..100}; do losetup -f -s $i & done没有给我100个循环设备。环路设备非常罕见,以至于不能正常工作。如果这样做,您唯一的选择是进行自己的锁定和/或检查是否创建了正确的循环设备,这是事后才想到的。
弗罗斯特斯2015年

@frostschutz losetup可能会失败(例如,因为循环条目用完了),但是如果报告了设备名称,则表示已成功分配了该设备。即使分配失败,早期版本是否存在导致其写出设备名称的错误?我在源代码中看到内核内部分配的接口仅在内核3.1以后才存在,这是否可能是较旧的接口的错误,需要该losetup实用程序进行搜索?
吉尔斯(Gillles)“所以-别再作恶了”

哦,它的确似乎在最新版本中已修复。util-linux-2.26.2似乎可以正常工作,util-linux-2.24.1反复打印/dev/loop14等,最终设备可能完全丢失。也许修复是有礼貌的/dev/loop-control,它过去只是看/proc/partitions……
frostschutz

@frostschutz从util-linux 2.21开始,losetup使用/dev/loop-controlif(如果存在),并且看起来不像是竞争条件:分配发生在内核中,并且打印设备路径是该实用程序要做的最后一件事。
吉尔斯(Gilles)'所以

6

我想到了。虽然我不确定权限问题的严重性,但我可以先拍摄然后再问:

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

2

您可以使用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


0

如果要将映像用作回送设备,只需将其挂载为文件系统并使用其内容,该mount命令将自动处理此问题。

mount -o loop myfile.img /tmp/mountpoint

实际上,就我而言,我特别希望它挂载-我将其用作块设备而不是文件系统。
AJMansfield

@AJMansfield除了挂载它之外,您还可以使用无法处理文件的块设备做什么?
Random832

您不能在全盘btrfs设置上将其格式化为交换空间。我打算将文件用于交换空间,因为btrfs不支持交换文件所需的操作,并且我无法通过全盘btrfs安装程序来创建真正的交换分区。
AJMansfield
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.