Wie ordne ich ein Loop-Gerät atomar zu?

11

Ich schreibe einige Shell-Skripte, um einige Disk-Image-Inhalte zu verarbeiten, und ich muss Loop-Geräte verwenden, um auf einige Disk-Images zuzugreifen. Ich bin mir jedoch nicht sicher, wie ich ein Loop-Gerät richtig zuordnen soll, ohne mein Programm einer Race-Bedingung auszusetzen.

Ich weiß, dass ich losetup -fdas nächste nicht zugewiesene Schleifengerät abrufen und dieses Schleifengerät dann wie folgt zuweisen kann:

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

Wenn ich jedoch mehrere Instanzen des Programms gleichzeitig ausführen möchte, ist dies fast ein Lehrbuchbeispiel für eine Rennbedingung, und das stört mich sehr. Wenn mehrere Instanzen dieses Programms ausgeführt würden oder andere Programme versuchen würden, auch ein Schleifengerät zu erhalten, könnte möglicherweise nicht jeder Prozess das Schleifengerät zuordnen, bevor der nächste Aufruf losetup -ferfolgt. In diesem Fall würden beide Prozesse annehmen, dass dieselbe Schleife vorhanden ist Gerät ist verfügbar, aber nur einer kann es bekommen.

Ich könnte hierfür eine externe Synchronisation verwenden, möchte aber (wenn möglich) zusätzliche Komplexität vermeiden. Auch andere Programme, die Loop-Geräte verwenden, würden wahrscheinlich nicht die Synchronisation berücksichtigen, die ich mir einfallen lassen könnte.

Wie kann ich diese potenzielle Rennbedingung vermeiden? Idealerweise möchte ich das Schleifengerät atomar erkennen und binden können, beispielsweise mit einem Befehl wie:

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

Wenn ich das mache, wird es $ldjedoch nicht dem Loop-Gerätepfad zugewiesen, und das Verschieben des sudoOuts, wie in, sudo ld=$(losetup -f myfile.img)gibt Berechtigungsfehler.

AJMansfield
quelle

Antworten:

13

Dies ist ein klassisches Problem bei der Parallelität: Wenn Sie eine Ressource zuweisen, müssen Sie atomar feststellen, ob die Ressource frei ist, und sie reservieren. Andernfalls kann ein anderer Prozess die Ressource zwischen dem Zeitpunkt, zu dem Sie überprüfen, ob sie frei ist, und dem Zeitpunkt, zu dem Sie sie reservieren, reservieren.

Verwenden Sie losetupden automatischen Zuordnungsmodus ( -f) und übergeben Sie die --showOption, um den Pfad des Schleifengeräts zu drucken.

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

Diese Option ist in Util-Linux seit Version 2.13 vorhanden ( ursprünglich hinzugefügt als-s , wurde jedoch --showin allen veröffentlichten Versionen unterstützt und in neueren Versionen wurde der -sOptionsname gelöscht ). Leider hat die BusyBox-Version es nicht.

In Version 3.1 des Linux-Kernels wurde eine Methode eingeführt , mit der die Schleifengerätezuweisungsoperation direkt im Kernel über das neue /dev/loop-controlGerät ausgeführt werden kann. Diese Methode wird nur seit util-linux 2.21 unterstützt. Bei Kernel <3.1 oder util-linux <2.21 zählt das losetupProgramm die Loop-Geräteeinträge auf, um einen zu reservieren. Ich kann jedoch keine Rennbedingung im Code sehen. Es sollte sicher sein, aber es kann ein kleines Fenster haben, in dem fälschlicherweise gemeldet wird, dass alle Geräte zugewiesen sind, obwohl dies nicht der Fall ist.

Gilles 'SO - hör auf böse zu sein'
quelle
Wofür ist das </dev/tty?
Stéphane Chazelas
1
Das letzte Mal habe ich es versucht, sogar losetup --find --showRennen. for i in {1..100}; do losetup -f -s $i & donegab mir nicht 100 Loop-Geräte. Loop-Geräte sind selten genug, damit sie normalerweise keine Rolle spielen. Wenn dies der Fall ist, können Sie nur Ihre eigenen Sperren erstellen und / oder überprüfen, ob das richtige Schleifengerät nachträglich erstellt wurde.
Frostschutz
@frostschutz schlägt losetupmöglicherweise fehl (z. B. weil Ihnen die Schleifeneinträge ausgegangen sind). Wenn jedoch ein Gerätename gemeldet wird, ist dies das Gerät, das erfolgreich zugewiesen wurde. Hatten frühere Versionen einen Fehler, der dazu führte, dass ein Gerätename geschrieben wurde, obwohl die Zuordnung fehlgeschlagen war? Ich sehe im Quellcode, dass die Schnittstelle für die Zuweisung im Kernel nur seit Kernel 3.1 existiert. Ist es möglicherweise ein Fehler mit der älteren Schnittstelle, für den das losetupDienstprogramm die Suche durchführen muss?
Gilles 'SO - hör auf böse zu sein'
Oh, es scheint tatsächlich in neueren Versionen behoben zu sein. util-linux-2.26.2 scheint zu funktionieren, util-linux-2.24.1 druckt wiederholt /dev/loop14und so und das Gerät kann am Ende insgesamt fehlen. Vielleicht ist das /dev/loop-control/proc/partitions
Update mit
@frostschutz Seit util-linux 2.21 wird losetupverwendet, /dev/loop-controlfalls vorhanden, und das sieht nicht so aus, als ob es eine Race-Bedingung geben könnte: Die Zuweisung erfolgt im Kernel und das Drucken des Gerätepfads ist das Letzte, was das Dienstprogramm tut.
Gilles 'SO - hör auf böse zu sein'
6

Ich habe es herausgefunden. Obwohl ich nicht sicher bin, wie das Problem mit der Erlaubnis ist, kann ich stattdessen zuerst schießen und später so fragen:

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

Sie könnten verwenden flock:

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

Die Idee hier ist, dass Sie versuchen, flockdie Loop-Gerätedatei; Wenn eine andere Instanz desselben Skripts es zuerst abruft, wird es aufgerufen losetup $ld myfile.imgund flockgibt 0 zurück. Für das Skript, das die Rasse verliert, losetupwird es nicht aufgerufen und flockgibt 1 zurück, wodurch sich die Schleife wiederholt.

Weitere Informationen finden Sie unter man flock.

Goldlöckchen
quelle
0

Wenn Sie das Image als Loopback-Gerät nur als Dateisystem bereitstellen und mit dem Inhalt arbeiten möchten, kann der mountBefehl dies automatisch erledigen .

mount -o loop myfile.img /tmp/mountpoint
Random832
quelle
In meinem Fall möchte ich insbesondere, dass es nicht gemountet wird - ich verwende es als Blockgerät, nicht als Dateisystem.
AJMansfield
@AJMansfield Was können Sie mit einem Blockgerät tun, das Sie mit einer Datei nicht tun können, außer es zu mounten?
Random832
Sie können es nicht als Swap Space in einem btrfs-Setup mit voller Festplatte formatieren. Ich hatte vor, die Datei für den Auslagerungsspeicher zu verwenden, da btrfs die für Auslagerungsdateien erforderlichen Vorgänge nicht unterstützt und ich keine echte Auslagerungspartition mit einem btrfs-Setup auf der gesamten Festplatte haben kann.
AJMansfield