Wie stellt man sicher, dass alle Prozesse beendet werden, bevor ein Dateisystem ausgehängt wird?

Wie stellt man sicher, dass alle Prozesse beendet werden, bevor ein Dateisystem ausgehängt wird?

Ich versuche, ein ausgelastetes Dateisystem auszuhängen, auf dem durch ein Multithread-Programm fortlaufend E/A-Lese- und Schreibvorgänge stattfinden, weshalb der Befehl „umount“ fehlschlägt.

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))

Nun habe ich versucht, alle Prozesse zu beenden mit

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

Aber gemäßBefehl „fuser“

fuser -k oder -K ist möglicherweise nicht in der Lage, neue Prozesse zu erkennen und zu beenden, die unmittelbar nach dem Start des Programms erstellt werden.

Das ist in meinem Fall der Fall, da einige der Threads möglicherweise gleichzeitig IO-Anfragen gestellt haben. Wenn ich das Dateisystem erneut aushängen möchte, wird erneut angezeigt, dass es beschäftigt ist, und es kommt zu einer Schleife.

Meine Frage ist, wie stelle ich sicher, dass keine neuen Prozesse Lese-/Schreibvorgänge im Dateisystem durchführen können, sobald

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

Der Befehl wird ausgegeben, damit das Dateisystem ordnungsgemäß ausgehängt werden kann.

Antwort1

Hier sind zwei Methoden. Wenn Sie Ihren Anwendungen nicht vertrauen, können Sie direkt zur zweiten Methode übergehen.

1.umount --lazy

Wenn diese störenden Prozesse nicht chdir()in den Einhängepunkt gelangen (verwenden Sie beispielsweise absolute Pfade) und Sie wissen, dass sie irgendwann aufgeben werden, können Sie unter Linux Folgendes verwenden umount --lazy: Der Kernel wird das Dateisystem aus der Verzeichnisstruktur entfernen, sodass es für neue Zugriffe unerreichbar wird, und es automatisch aushängen, wenn die letzte Referenz verschwindet. Die Referenz kann ein offenes FD, ein CWD oder ein Einhängepunkt darin sein (letzterer wäre schlecht) …

Dies hat jedoch keine Auswirkungen auf Prozesse/Threads, die eine Referenz "innen" behalten, z. B. noch offene Dateideskriptoren odercwdinnen. Dann wäre dies noch schwieriger, da das Dateisystem nun nicht mehr erreichbar ist und es noch schwieriger wird, fehlerhafte Prozesse/Threads zu verfolgen (z. B.: fuser -msie werden nicht mehr gefunden). Sie müssen also Prozesse haben, die sich für diese Methode irgendwie korrekt verhalten.

2.Gefrierschrank-Gruppe

Alternative Lösung, die funktionieren sollte fürschlechtes BenehmenProzesse: Gruppieren Sie alle diese Prozesse (und Threads) in derselben Freezer-Cgroup. Frieren Sie sie alle ein, um zu verhindern, dass sie Ressourcennutzung zum Mountpoint hinzufügen (durch Forken/Klonen/Öffnen neuer FDS). Selbst wenn Sie in einer ersten Schleife einige verpassen, werden Sie schließlich alle neuen in nachfolgenden Iterationen abfangen. Da sie jetzt eingefroren sind, wird keine neue Aktivität stattfinden: Sie können sie jetzt alle beenden. Für Cgroups v1, die bereits vom Betriebssystem initialisiert wurden (z. B.: durchsystemdoderAbonnieren, sonst müssen Sie herausfinden, wie SieMounten Sie das Freezer-Cgroup-Subsystem), so etwas sollte funktionieren. Beachten Sie, dass das Schreiben in anscheinend cgroup.procsalle Threads einschließen sollte, die in erscheinen sollten, tasksaber es gab Berichte über unzuverlässiges Verhalten, also iteriere ich für alle Fälle auch über Threads, auch wenn dies wahrscheinlich nicht nötig ist (d. h.: tasksist wahrscheinlich bereits korrekt mit Threads gefüllt, sodass die for tSchleife redundant ist).

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

Dies müsste bei Verwendung von cgroups v2 angepasst werden.

verwandte Informationen