Як атомно виділити циклічний пристрій?


11

Я пишу кілька скриптів оболонки для обробки деяких зображень диска, і мені потрібно використовувати петльові пристрої для доступу до деяких зображень диска. Однак я не впевнений, як правильно розподілити циклічний пристрій, не піддаючи програмі перегоновий стан.

Я знаю, що можу 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)помилках дозволу.

Відповіді:


13

Це класична проблема паралельності: при розподілі ресурсу вам потрібно атомно визначити, що ресурс вільний і резервувати його, інакше інший процес може зарезервувати ресурс між часом, коли ви перевіряєте, що він вільний, і тим часом, коли ви його резервуєте.

Використовуйте losetupавтоматичний режим розподілу ( -f) і передайте --showпараметр, щоб він надрукував шлях пристрою циклу.

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

Ця опція присутня в util-linux з версії 2.13 ( спочатку додається як-s , але --showпідтримується у всіх випущених версіях, а останні версії скинули назву -sпараметра). На жаль, у версії BusyBox його немає.

Версія 3.1 ядра Linux представила метод виконання операції розподілу пристрою циклу безпосередньо в ядрі через новий /dev/loop-controlпристрій. Цей метод підтримується лише з моменту util-linux 2.21. З ядром <3.1 або util-linux <2.21, losetupпрограма перераховує записи пристрою циклу для резервування. Я не можу бачити умову гонки в коді; це повинно бути безпечним, але воно може мати невелике вікно, під час якого буде неправильно повідомлятися про те, що всі пристрої призначені, хоча це не так.


Для чого </dev/tty?
Стефан Шазелас

1
Востаннє я пробував, навіть losetup --find --showгонки. for i in {1..100}; do losetup -f -s $i & doneне дав мені 100 петельних пристроїв. Петльові пристрої досить рідкісні, щоб вони не мали значення нормально; якщо це єдиний ваш варіант - зробити власні замки та / або перевірити, чи правильно створений пристрій циклу, як задум.
frostschutz

@frostschutz losetupможе вийти з ладу (наприклад, через те, що у вас закінчилися записи циклу), але якщо він повідомляє ім'я пристрою, це пристрій, який він успішно виділив. Чи мали попередні версії помилку, яка змусила її виписати ім’я пристрою, навіть якщо розподіл не відбувся? Я бачу у вихідному коді, що інтерфейс для розподілу в ядрі існує лише з ядра 3.1, чи можливо помилка зі старшим інтерфейсом, який вимагає losetupутиліти для пошуку?
Жиль "ТАК - перестань бути злим"

О, це, мабуть, фіксується в більш нових версіях. util-linux-2.26.2, здається, працює, util-linux-2.24.1 багаторазово друкує, /dev/loop14і подібне, і в кінцевому підсумку пристрій може взагалі відсутній. Можливо, виправлення люб'язно /dev/loop-control, воно раніше просто /proc/partitions
дивилося

@frostschutz Оскільки util-linux 2.21 losetupвикористовує, /dev/loop-controlякщо він присутній, і це не схоже на те, що він може мати перегоновий стан: розподіл відбувається в ядрі, а друк шляху пристрою - це останнє, що робить утиліта.
Жил "ТАК - перестань бути злим"

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.imgі flockповерне 0. Для скрипту, який програє гонку, losetupне буде викликано і flockповерне 1, викликаючи повтор циклу.

Детальніше див man flock.


0

Якщо все, що ви хочете зробити із зображенням, як пристроєм зворотного зв'язку, - це встановити його як файлову систему та працювати зі вмістом, mountкоманда може подбати про це автоматично.

mount -o loop myfile.img /tmp/mountpoint

Насправді в моєму випадку я, зокрема, хочу, щоб він не був встановлений - я використовую його як блок пристрою, а не файлову систему.
AJMansfield

@AJMansfield Окрім монтажу, що ви можете зробити із блочним пристроєм, який ви не можете зробити з файлом?
Випадково832

Ви не можете відформатувати його як простір під час налаштування btrfs з повним диском. Я мав намір використати файл для простору swap, оскільки btrfs не підтримує операції, необхідні для файлів підкачки, і я не можу мати справжній розділ swap з налаштуванням btrfs з повним диском.
AJMansfield
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.