umount
Rev.1を表示中。最新版はこちら。
umountのシステムコールは、__NR_umountのumount()と、__NR_umount2のumount2()の2つあります。umount()は、umount2()のflagを0でコールしているだけです。asmlinkage long sys_oldumount(char __user * name) { return sys_umount(name,0); }sys_umount()内が実際のumountの入り口となるわけです。__user_walk()でumount先のパスのstruct nameidataを取得します。LOOKUP_FOLLOWは、「リンクもたどれ。」と言う指定です。
if (nd.dentry != nd.mnt->mnt_root)は、dentryがマウントポイントかどうかのチェックだと思いますが・・・。check_mnt()でカレントプロセスのネームスペース下のファイルシステムをチェックし、do_umount()をコールします。
asmlinkage long sys_umount(char __user * name, int flags) { struct nameidata nd; int retval; retval = __user_walk(name, LOOKUP_FOLLOW, &nd); if (retval) goto out; retval = -EINVAL; if (nd.dentry != nd.mnt->mnt_root) goto dput_and_out; if (!check_mnt(nd.mnt)) goto dput_and_out; retval = -EPERM; if (!capable(CAP_SYS_ADMIN)) goto dput_and_out; retval = do_umount(nd.mnt, flags); dput_and_out: path_release(&nd); out: return retval; }do_umount()が主たる処理となります。MNT_FORCEでスーパブロックのumount_begin()コールバック関数がコールされます。スーパブロックオペレーションでumount_beginが定義されているのは、ntfsだけで、そこでの処理は、ntfsに繋がっているクライアントへ終了する旨の掛かる処理のようです。
アンマウントがrootのファイルシステムで、MNT_DETACHが設定されてないと、RDONLYで再マウントします。原則マウント先としてのルートは、物理的にアンマウトしないと言う事のようです。
if (atomic_read(&sb->s_active) == 1)は、このスーパブロックのファイルシステムをumountとすると、このスーパブロックが解放されるということで(たぶん)、acct_auto_close()でプロセス・アカウンティングファイルが、このファイルシステム下にある場合、ファイルをクローズして、プロセス・アカウンティングを不可にしています。
プロセス・アカウンティングは、CONFIG_BSD_PROCESS_ACCTカーネルオプション時に有効となり、acct("アカウンティングファイル")として、アカウンティングファイルにプロセス終了毎に、プロセスID を含め実行時間等のプロセス情報が書き込まれるようです。
alloc_vfsmn()でスラブからstruct vfsmountを取得する時、mnt->mnt_count=1で初期化されます。そしてマウントされるなりそのマウントポイントとなるdentryを参照するなりする毎に、mnt_countはインクリメントされていきまます。従って2と言うことは、このファイルシステムは、他から参照されていない。ということです。なお、他から参照されていても、MNT_DETACHが指定されているなら、アンマウントの処理となります。
mntは複数の位置にマウントする事が可能です。従ってマウントされる度に、自分自身のmnt_listに、mnt_childをリストしていました。従ってmnt->mnt_listが空でない。ということは、何処かにマウントされていると言うことです。で、umount_tree()をコールする事で、実際のアンマウントを行います。
static int do_umount(struct vfsmount *mnt, int flags) { struct super_block * sb = mnt->mnt_sb; int retval; retval = security_sb_umount(mnt, flags); if (retval) return retval; lock_kernel(); if( (flags&MNT_FORCE) && sb->s_op->umount_begin) sb->s_op->umount_begin(sb); unlock_kernel(); if (mnt == current->fs->rootmnt && !(flags & MNT_DETACH)) { down_write(&sb->s_umount); if (!(sb->s_flags & MS_RDONLY)) { lock_kernel(); retval = do_remount_sb(sb, MS_RDONLY, 0, 0); unlock_kernel(); } up_write(&sb->s_umount); return retval; } down_write(¤t->namespace->sem); spin_lock(&vfsmount_lock); if (atomic_read(&sb->s_active) == 1) { spin_unlock(&vfsmount_lock); lock_kernel(); DQUOT_OFF(sb); acct_auto_close(sb); unlock_kernel(); security_sb_umount_close(mnt); spin_lock(&vfsmount_lock); } retval = -EBUSY; if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) { if (!list_empty(&mnt->mnt_list)) umount_tree(mnt); retval = 0; } spin_unlock(&vfsmount_lock); if (retval) security_sb_umount_busy(mnt); up_write(¤t->namespace->sem); return retval; }
追記
manによると、MNT_FORCEは使用中 (busy) でも強制的にアンマウントを実行するで、umount -fに相当するようです。MNT_DETACHは遅延アンマウント(遅延ってどういう事?)を行うで、umount -lに相当するようです。ようわからん説明ですが、MNT_FORCEとMNT_DETACHの意味合いが、なんか逆のようにも思うのですが。