Как гарантировать завершение всех процессов перед размонтированием файловой системы?

Как гарантировать завершение всех процессов перед размонтированием файловой системы?

Я пытаюсь размонтировать загруженную файловую систему, в которой многопоточная программа непрерывно выполняет операции ввода-вывода, чтения и записи, из-за чего команда umount завершается ошибкой.

root@ubuntu:~ # umount /mount/v1
umount: /mount/v1: target is busy.
        (In some cases useful info about processes that use
         the device is found by lsof(8) or fuser(1))

Теперь я попытался завершить все процессы с помощью

/sbin/fuser -m /mount/v1 -k

Но согласноКоманда фьюзера

fuser -k или -K может оказаться неспособным обнаружить и завершить новые процессы, созданные сразу после запуска программы.

что и происходит в моем случае, так как некоторые потоки могли выдать запрос ввода-вывода в одно и то же время. Когда я снова пытаюсь размонтировать файловую систему, она снова говорит, что занята, и это становится циклом.

Мой вопрос в том, как гарантировать, что ни один новый процесс не сможет выполнять чтение/запись в файловую систему после

/sbin/fuser -m /mount/v1 -k

выдается команда, позволяющая корректно размонтировать файловую систему.

решение1

Вот два метода. Если вы не доверяете своим приложениям, вы можете сразу перейти ко второму методу.

1.umount --lazy

Если эти мешающие процессы не chdir()) в точке монтирования (например, используйте абсолютные пути) и вы знаете, что они в конечном итоге сдадутся, то в Linux вы можете использовать umount --lazy: ядро ​​отключит отображение файловой системы от древовидной структуры каталогов, сделав ее недоступной для новых обращений, и автоматически размонтирует ее, когда исчезнет последняя ссылка. Ссылка может быть открытым fd, cwd, точкой монтирования внутри (последнее будет плохим)...

Но это не повлияет на процессы/потоки, сохраняющие ссылку «внутри», например, на все еще открытые файловые дескрипторы или имеющиеcwdвнутри. Тогда это будет еще сложнее, так как теперь файловая система больше недоступна, и становится еще сложнее отслеживать нарушающие процессы/потоки (например: fuser -mбольше не будет их находить). Так что каким-то образом вам нужно, чтобы процессы вели себя правильно для этого метода.

2.морозильник cgroup

Альтернативное решение, которое должно подойтиплохо себя ведетпроцессы: сгруппируйте все эти процессы (и потоки) в одну и ту же замороженную cgroup. Заморозьте их все, не давая им добавлять использование ресурсов к точке монтирования (путем разветвления/клонирования/открытия новых fds). Даже если вы пропустите несколько в первом цикле, вы в конечном итоге поймаете все новые в последующих итерациях. Поскольку они теперь заморожены, никакой новой активности не произойдет: теперь вы можете убить их все. Для cgroups v1, уже инициализированных ОС (например:системдилиcgmanager, иначе вам придется придумать, каксмонтировать подсистему cgroup морозильника), что-то вроде этого должно работать. Обратите внимание, что, по-видимому, запись в cgroup.procsдолжна включать все потоки, которые должны появляться в, tasksно были сообщения о ненадежном поведении, поэтому на всякий случай я также перебираю потоки, даже если это, вероятно, не нужно (т. е.: tasksвероятно, уже правильно заполнен потоками, поэтому for tцикл избыточен).

mkdir -p /sys/fs/cgroup/freezer/prepareumount

echo FROZEN > /sys/fs/cgroup/freezer/prepareumount/freezer.state

for i in $(seq 1 10); do
    for p in $(fuser -m /mount/v1 2>/dev/null); do
        echo $p > /sys/fs/cgroup/freezer/prepareumount/cgroup.procs
        for t in $(ps -L -o tid= -p $p); do
            echo $t > /sys/fs/cgroup/freezer/prepareumount/tasks
        done
    done
done

#give time to an overloaded kernel to freeze everything (FREEZING->FROZEN)
while ! cat /sys/fs/cgroup/freezer/prepareumount/freezer.state | grep -q FROZEN; do
    sleep 0.1
done

# kills, delayed
for i in $(cat /sys/fs/cgroup/freezer/prepareumount/cgroup.procs); do
    kill -KILL $i
done

# actual kills happen now, at once
echo THAWED > /sys/fs/cgroup/freezer/prepareumount/freezer.state

sleep 1
umount /mount/v1

Это необходимо будет адаптировать при использовании cgroups v2.

Связанный контент