Jak atomowo przydzielić urządzenie pętli?

11

Piszę kilka skryptów powłoki, aby obsłużyć niektóre obrazy dysków, i muszę korzystać z urządzeń pętlowych, aby uzyskać dostęp do niektórych obrazów dysków. Nie jestem jednak pewien, jak prawidłowo przydzielić urządzenie pętlowe bez narażania mojego programu na wyścig.

Wiem, że mogę użyć losetup -fnastępnego nieprzydzielonego urządzenia pętli, a następnie przydzielić to urządzenie pętli w następujący sposób:

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

Jednak w przypadku, gdy chcę uruchomić wiele instancji programu w tym samym czasie, jest to prawie podręcznikowy przykład warunków wyścigu, co mnie bardzo niepokoi. Gdybym miał uruchomione wiele wystąpień tego programu lub inne programy próbujące również uzyskać urządzenie pętlowe, to każdy proces może nie być w stanie przydzielić urządzenia pętlowego przed następnym wywołaniem losetup -f, w którym to przypadku oba procesy będą myśleć, że ta sama pętla urządzenie jest dostępne, ale tylko jeden może je zdobyć.

Mógłbym do tego użyć zewnętrznej synchronizacji, ale chciałbym (jeśli to możliwe) uniknąć dodatkowej złożoności. Ponadto inne programy korzystające z urządzeń pętlowych prawdopodobnie nie będą szanować synchronizacji, jaką wymyślę.

Jak mogę uniknąć tego potencjalnego wyścigu? Idealnie chciałbym móc atomowo wykryć i powiązać urządzenie pętli, na przykład za pomocą polecenia:

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

Jednak gdy to robię, $ldnie zostaje przypisany do ścieżki urządzenia pętli i przeniesienie się na sudozewnątrz, ponieważ w sudo ld=$(losetup -f myfile.img)daje błędy uprawnień.

AJMansfield
źródło

Odpowiedzi:

13

Jest to klasyczny problem w przypadku współbieżności: przy przydzielaniu zasobu musisz atomowo ustalić, że zasób jest wolny i zarezerwować go, w przeciwnym razie inny proces może zarezerwować zasób między czasem sprawdzenia, czy jest on wolny, a czasem zarezerwowania.

Skorzystaj z losetuptrybu automatycznej alokacji ( -f) i przekaż --showopcję drukowania ścieżki urządzenia pętli.

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

Ta opcja jest obecna w programie ut-linux od wersji 2.13 ( początkowo dodana jako-s , ale --showbyła obsługiwana we wszystkich wydanych wersjach, a ostatnie wersje usunęły -snazwę opcji). Niestety wersja BusyBox go nie ma.

W wersji 3.1 jądra Linuksa wprowadzono metodę wykonywania operacji przydzielania urządzeń pętli bezpośrednio w jądrze, za pośrednictwem nowego /dev/loop-controlurządzenia. Ta metoda jest obsługiwana tylko od wersji util-linux 2.21. W przypadku jądra <3.1 lub util-linux <2.21 losetupprogram wylicza wpisy urządzeń pętli, aby je zarezerwować. Nie widzę jednak warunków wyścigu w kodzie; powinien być bezpieczny, ale może mieć małe okno, w którym niepoprawnie zgłasza, że ​​wszystkie urządzenia są przydzielone, chociaż tak nie jest.

Gilles „SO- przestań być zły”
źródło
Co to jest </dev/ttyza?
Stéphane Chazelas,
1
Ostatnim razem próbowałem, nawet losetup --find --showwyścigi. for i in {1..100}; do losetup -f -s $i & donenie dał mi 100 urządzeń z pętlą. Urządzenia pętlowe są na tyle rzadkie, że nie mają znaczenia normalnie; jeśli tak, jedyną opcją jest wykonanie własnych blokad i / lub sprawdzenie, czy poprawne urządzenie pętli zostało utworzone w późniejszym czasie.
frostschutz
@frostschutz losetupmoże się nie powieść (np. ponieważ zabrakło Ci wpisów w pętli), ale jeśli zgłasza nazwę urządzenia, to urządzenie, które pomyślnie przydzieliło. Czy wcześniejsze wersje zawierały błąd, który spowodował, że wypisała nazwę urządzenia, mimo że alokacja nie powiodła się? Widzę w kodzie źródłowym, że interfejs do alokacji w jądrze istnieje tylko od jądra 3.1. Czy to może być błąd w starszym interfejsie, który wymaga losetupnarzędzia do wyszukiwania?
Gilles „SO- przestań być zły”
Och, to wydaje się być naprawione w nowszych wersjach. util-linux-2.26.2 wydaje się działać, util-linux-2.24.1 wielokrotnie drukuje /dev/loop14i takie, a na końcu może brakować urządzenia. Być może poprawka jest dostępna dzięki uprzejmości /dev/loop-control, zwykła tylko patrzeć na /proc/partitions...
frostschutz
@frostschutz Od util-linux 2.21 losetupużywa, /dev/loop-controljeśli jest obecny, i to nie wygląda na to, że może mieć warunek wyścigu: alokacja odbywa się w jądrze, a drukowanie ścieżki urządzenia jest ostatnią rzeczą, jaką robi narzędzie.
Gilles „SO - przestań być zły”
6

Rozgryzłem to. Chociaż nie jestem pewien, na czym polega problem z pozwoleniem, mogę zamiast tego najpierw strzelać i pytać w następujący sposób:

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

Możesz użyć flock:

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

Chodzi o to, że próbujesz i flockplik urządzenia pętli; jeśli pierwsza instancja tego samego skryptu ją zdobędzie, najpierw zadzwoni losetup $ld myfile.imgi flockzwróci 0. W przypadku skryptu, który przegra wyścig, losetupnie zostanie wywołany i flockzwróci 1, co spowoduje powtórzenie pętli.

Więcej patrz man flock.

Złotowłosa
źródło
0

Jeśli wszystko, co chcesz zrobić z obrazem jako urządzeniem pętli zwrotnej, to zamontuj go jako system plików i pracuj z zawartością, mountpolecenie może zająć się tym automatycznie.

mount -o loop myfile.img /tmp/mountpoint
Losowo 832
źródło
Właściwie w moim przypadku szczególnie chcę, aby nie był zamontowany - używam go jako urządzenia blokowego, a nie systemu plików.
AJMansfield,
@AJMansfield Oprócz montażu, co możesz zrobić z urządzeniem blokowym, którego nie można zrobić z plikiem?
Random832
Nie można sformatować go jako przestrzeni wymiany w konfiguracji btrfs na pełnym dysku. Zamierzałem użyć tego pliku do wymiany przestrzeni, ponieważ btrfs nie obsługuje operacji wymaganych dla plików wymiany i nie mogę mieć prawdziwej partycji wymiany z instalacją btrfs na pełnym dysku.
AJMansfield