Como alocar atomicamente um dispositivo de loop?

10

Eu estou escrevendo alguns scripts de shell para lidar com algumas coisas de imagem de disco, e eu preciso usar dispositivos de loop para acessar algumas imagens de disco. No entanto, não tenho certeza de como alocar corretamente um dispositivo de loop sem expor meu programa a uma condição de corrida.

Eu sei que posso usar losetup -f para obter o próximo dispositivo de loop não alocado e, em seguida, alocar esse dispositivo de loop como este:

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

No entanto, no caso em que eu quero executar várias instâncias do programa ao mesmo tempo, isso é quase um exemplo de uma condição de corrida, e isso me incomoda bastante. Se eu tivesse várias instâncias deste programa em execução, ou outros programas tentando também obter um dispositivo de loop, cada processo poderia não ser capaz de alocar o dispositivo de loop antes do próximo chamar losetup -f , caso em que ambos os processos pensariam que o mesmo dispositivo de loop está disponível, mas apenas um pode obtê-lo.

Eu poderia usar a sincronização externa para isso, mas gostaria de (se possível) evitar uma complexidade adicional. Além disso, outros programas que usam dispositivos de loop provavelmente não respeitariam qualquer sincronização que eu pudesse criar.

Como posso evitar essa possível condição de corrida? Idealmente, gostaria de poder descobrir e vincular o dispositivo de loop atomicamente, por exemplo, com um comando como:

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

No entanto, quando faço isso, $ld não é atribuído ao caminho do dispositivo de loop e mover o sudo out, como em sudo ld=$(losetup -f myfile.img) , fornece erros de permissão.

    
por AJMansfield 25.05.2015 / 19:23

4 respostas

13

Esse é um problema clássico de simultaneidade: ao alocar um recurso, você precisa determinar atomicamente que o recurso é gratuito e reservá-lo, caso contrário, outro processo poderia reservar o recurso entre a hora em que você verifica se está livre e a hora da reserva isso.

Use o modo de alocação automática de losetup ( -f ) e passe a opção --show para que imprima o caminho do dispositivo de loop.

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

Esta opção está presente no util-linux desde a versão 2.13 ( inicialmente adicionada como -s , mas o --show foi suportado em todas as versões lançadas e as versões recentes eliminaram o nome da opção -s ). Infelizmente a versão do BusyBox não tem isso.

Versão 3.1 do kernel do Linux introduzido um método para executar a operação de alocação de dispositivos de loop diretamente no kernel, através do novo dispositivo /dev/loop-control . Este método só é suportado desde o util-linux 2.21. Com o kernel < 3.1 ou util-linux < 2.21, o programa losetup enumera as entradas do dispositivo de loop para reservar uma. Eu não posso ver uma condição de corrida no código embora; ele deve ser seguro, mas pode ter uma pequena janela durante a qual ele informará incorretamente que todos os dispositivos estão alocados, mesmo que isso não ocorra.

    
por 25.05.2015 / 21:53
5

Eu percebi isso. Embora eu não tenha certeza de como está o problema com a permissão, posso, em vez disso, fotografar primeiro e perguntar depois assim:

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

Você pode usar flock :

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

A ideia aqui é que você tente e flock o arquivo de dispositivo de loop; se outra instância do mesmo script adquire primeiro, ele irá chamar losetup $ld myfile.img e flock retornará 0. Para o script que perde a corrida, losetup não será chamado e flock retornará 1, fazendo com que o loop se repita.

Para mais informações, consulte man flock .

    
por 25.05.2015 / 20:02
0

Se tudo o que você deseja fazer com a imagem como um dispositivo de loopback é montá-la como um sistema de arquivos e trabalhar com o conteúdo, o comando mount pode cuidar disso automaticamente.

mount -o loop myfile.img /tmp/mountpoint
    
por 25.05.2015 / 23:38