Comment allouer atomiquement un périphérique en boucle?

Je suis en train d'écrire des scripts shell pour gérer certaines images de disque, et j'ai besoin d'utiliser des périphériques loop pour accéder à certaines images disque. Cependant, je ne suis pas sûr de savoir comment allouer correctement un périphérique de boucle sans exposer mon programme à une condition de course.

Je sais que je peux utiliser losetup -f pour get le prochain périphérique de boucle non alloué, puis allouer ce périphérique de boucle comme ceci:

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

Cependant, dans le cas où je veux exécuter plusieurs instances du programme en même time, ceci est presque un exemple de manuel d'une condition de course, et cela me dérange beaucoup. Si plusieurs instances de ce programme étaient en cours d'exécution ou si d'autres programmes essayaient d'get un périphérique en boucle, chaque process risquait de ne pas pouvoir allouer le périphérique de boucle avant que le suivant appelle losetup -f , auquel cas les deux process penseraient que le même périphérique de boucle est disponible, mais un seul peut l'get.

Je pourrais utiliser la synchronisation externe pour cela, mais j'aimerais (si possible) éviter la complexité supplémentaire. En outre, d'autres programmes qui utilisent des périphériques en boucle ne respecteront probablement pas la synchronisation que je pourrais find.

Comment puis-je éviter cette condition de course potentielle? Idéalement, j'aimerais être capable de découvrir et de lier le périphérique loop de manière atomique, par exemple avec une command comme:

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

Cependant, quand je le fais, $ld n'est pas assigné au path du périphérique de la boucle, et le déplacement du sudo , comme dans sudo ld=$(losetup -f myfile.img) donne des erreurs d'autorisation.

Il s'agit d'un problème classique en access concurrentiel: lors de l'allocation d'une ressource, vous devez déterminer atomiquement que la ressource est libre et la réserver, sinon un autre process pourrait réserver la ressource entre le moment où vous vérifiez qu'elle est libre et le moment où vous la réservez.

Utilisez le mode d'allocation automatique de losetup ( -f ) et transmettez l'option --show pour qu'elle imprime le path du périphérique de la boucle.

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

Cette option a été présente dans util-linux depuis la version 2.13 ( initialement ajoutée en -s , mais --show a été supscope dans toutes les versions publiées et les versions récentes ont supprimé le nom d'option -s ). Malheureusement, la version BusyBox ne l'a pas.

La version 3.1 du kernel Linux a introduit une méthode pour effectuer l'opération d'allocation de périphérique de boucle directement dans le kernel, via le nouveau périphérique /dev/loop-control . Cette méthode est uniquement prise en charge depuis util-linux 2.21. Avec le kernel <3.1 ou util-linux <2.21, le programme losetup énumère les inputs du périphérique de boucle pour en réserver un. Je ne peux pas voir une condition de course dans le code cependant; il devrait être sûr, mais il pourrait avoir une petite window au cours de laquelle il signalera de manière incorrecte que tous les périphériques sont alloués même si ce n'est pas le cas.

Je l'ai compris. Bien que je ne sois pas sûr de savoir comment le problème avec la permission est, je peux plutôt tirer en premier et requestr plus tard comme ceci:

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

Vous pourriez utiliser flock :

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

L'idée ici est que vous essayez de flock le file périphérique de la boucle; si une autre instance du même script l'acquiert en premier, il appellera losetup $ld myfile.img et flock returnnera 0. Pour le script qui perd la course, losetup ne sera pas appelé et flock returnnera 1, provoquant la boucle répéter.

Pour plus voir l' man flock .

Si tout ce que vous voulez faire avec l'image en tant que périphérique de bouclage est le monter en tant que système de files et travailler avec le contenu, la command mount peut s'en occuper automatiquement.

 mount -o loop myfile.img /tmp/mountpoint