2016年7月アーカイブ

LinuxでumountしようとしたときにEBUSY(device is busy)で失敗するという話はもはやFAQ的で、その回答もlsof(1)使って使用者見つけてkillしろ、と定番になってて、この話はまぁこれでいいとして。

いくつかのサイトでは回答としてlazyアンマウント(umount(8)の-lオプション)使え、とある。ちょっとまて、それは答えになってないぞ、そもそも何をやっているのかちゃんと理解しているのかと。

umount -lはumountシステムコールのMNT_DETACHです。

遅延アンマウントを行う。マウントポイントに対する新規のアクセスは 不可能となり、実際のアンマウントはマウントポイントがビジーで なくなった時点で行う。
そうです、umount -lは成功してもまだ本当にはumountしてません。これをした以後にプロセスが新しく参照することができなくなり、/proc/mountなどからも見えなくなるものの、それ以前に参照していたプロセスは引き続き参照し続けれるんです。で、参照するプロセスがいなくなった時点ではじめて、umountの実処理が行われるわけです。superブロックの書き出しも最後の参照がなくなってから行われるので、umount -lしただけで満足するのはほとんど意味がないことだと理解できるでしょう。

新しく参照することはできなくなるので意味はあるとはいえ、じゃ本当にumountされたタイミング(最後の参照がなくなったタイミング)を知る方法はないのかと。いつまで待っても参照を外さないプロセスがいたとしたらどうしようもないので、そのケースは除外。結局のところ、参照を外すたびにmntput_no_expireを通るようになってて、ここで最後だった人は、task_workとかdelayed_workとか使って、delayed_mntput()->cleanup_mnt()->deactivate_super()->deactivate_locked_super()->「fs->kill_sb()」という感じでcallされる。

この辺まで調べればしめたもので、ここに来るまでにnotify系関数が多数登場してるのに気づく。とゆーわけで、inotify(7)使えばいけるんじゃね?ってことで実験して動くこと確認して完了と。本当にumountされたタイミングでIN_UNMOUNTイベントが飛んでくるのでこれをハンドルすればOK。まぁ厳密には、umountのMNT_DETACHをするタイミングと、inotifyで監視スタートするタイミングでraceがあるわけで、厳密に厳密を重ねるなら、chdirしてinotifyしてumount MNT_DETACHしてfstatfsしてchdirで戻る、て感じなのかなぁ。同じmount pathに複数mountを重ねられててしかもそれを複数スレッドからmount/umountされるような状況だと厳密な手順は難しいと思う。

ちなみにFreeBSDなんかだと、umount -fで強制アンマウントできたりので、システム管理者的に優しい。Linuxでもfs->kill_sb()を強制的に呼ぶ系を作れば force umount できなくもないだろうけど、それした後でも参照持ったプロセスがinodeにsyscallをつっめそうな設計なので、用意したところで意味がなさそうにみえる。あれか、Filesystemをumountせずにいきなり電源落としても大丈夫という話か?まぁ普通はそうであってほしいよね、うん。

2018/06/24(Sun)追記: プロセスがinodeの参照を持ってなくても、mmapしているだけでbuffer cacheを直接晒していることになるので、やはり強制的にumountするのは簡単ではない。強制的にumoutするには、やはり該当プロセスにsignal送って殺すしかないんじゃないかなぁ。

このアーカイブについて

このページには、2016年7月に書かれたブログ記事が新しい順に公開されています。

前のアーカイブは2016年6月です。

次のアーカイブは2016年9月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

月別 アーカイブ

ウェブページ

Powered by Movable Type 7.9.0