ファイルシステムをアンマウントする前にすべてのプロセスが強制終了されていることを確認するにはどうすればよいでしょうか?

ファイルシステムをアンマウントする前にすべてのプロセスが強制終了されていることを確認するにはどうすればよいでしょうか?

マルチスレッド プログラムによって継続的な I/O 読み取りと書き込みが行われているビジー状態のファイル システムをアンマウントしようとしていますが、そのために 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 コマンド

fuser -k または -K は、プログラムの実行開始直後に作成された新しいプロセスを検出して終了できない可能性があります。

私のケースでは、いくつかのスレッドが同時に IO 要求を発行した可能性があるため、このようなことが起こります。ファイル システムを再度アンマウントしようとすると、再びビジー状態であると表示され、ループが発生します。

私の質問は、新しいプロセスがファイルシステムに読み取り/書き込みを実行できないようにするにはどうすればよいかということです。

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

ファイルシステムを正常にアンマウントできるようにコマンドが発行されます。

答え1

ここに 2 つの方法があります。アプリケーションを信頼できない場合は、直接 2 番目の方法に進むことができます。

1.umount --lazy

干渉するプロセスがchdir()マウント ポイントに (絶対パスなどを使用して) 移動せず、最終的に諦めることが分かっている場合は、Linux で を使用できますumount --lazy。カーネルは、ディレクトリ アーボレッセンスからファイル システムをアンマップして、新しいアクセスがアクセスできないようにし、最後の参照が消えると自動的にアンマウントします。参照は、開いている fd、cwd、内部のマウント ポイント (この最後のものは不適切です) などです...

しかし、これは「内部」に参照を保持しているプロセス/スレッドには影響しません。たとえば、ファイル記述子を開いたままにしたり、腹筋内部。そうすると、ファイルシステムにアクセスできなくなり、問題のあるプロセス/スレッドを追跡することがさらに困難になります (例:fuser -m見つけられなくなります)。したがって、何らかの方法で、この方法でプロセスが正しく動作する必要があります。

2.冷凍庫 cgroup

有効な代替ソリューション行儀が悪いプロセス: これらすべてのプロセス (およびスレッド) を同じフリーザー cgroup にグループ化します。すべてをフリーズして、マウントポイントにリソース使用を追加しないようにします (フォーク/クローン/新しい fd を開くことによって)。最初のループでいくつかを見逃したとしても、後続の反復で最終的にすべて新しいものをキャッチします。これらは現在フリーズされているため、新しいアクティビティは発生しません。これですべてを強制終了できます。cgroup v1 の場合、OS によって既に初期化されています (例:システムまたはcgマネージャーそうでなければ、冷凍庫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 を使用する場合はこれを調整する必要があります。

関連情報