Umount系统调用完成卸载文件系统,umount直接调用sys_umount。
一 sys_umount执行过程
1. 调用__user_walk(fs/namei.c)获取加载点的路径名。查找的结果保存在nameidata定义的nd中。并且检查:
Ø 查找的路径是否是文件系统的挂载点。
Ø 被卸载的文件系统是否被加载。
Ø 用户是否有卸载权限。
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;
2. 调用do_umount,传入参数为加载的文件系统对象和设置的标示。
Ø 从加载的文件系统对象的mnt_sb 域获取超级快的地址。
struct super_block * sb = mnt->mnt_sb;
Ø 如果用户采用强制卸载,那么调用umount_begin超级块操作打断所有正在进行得加载操作。
lock_kernel();
if( (flags&MNT_FORCE) && sb->s_op->umount_begin)
sb->s_op->umount_begin(sb);
unlock_kernel();
Ø 如果被卸载的文件系统是根文件系统,并且用户没有请求分离,那么调用do_remount_sb重新加载只读的根文件系统。
if (mnt == current->fs->rootmnt && !(flags & MNT_DETACH)) {
/*
* Special case for "unmounting" root ...
* we just try to remount it readonly.
*/
down_write(&sb->s_umount);
if (!(sb->s_flags & MS_RDONLY)) {
lock_kernel();
DQUOT_OFF(sb);
retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);
unlock_kernel();
}
up_write(&sb->s_umount);
return retval;
}
Ø 获取当前进程的namespace->sem 读些信号和vfsmount_lock自选锁
down_write(¤t->namespace->sem);
spin_lock(&vfsmount_lock);
Ø 如果加载的文件系统不包括任何子系统的挂载点,或者用户强制断开文件系统,调用umount_tree 写在文件系统。
if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) {
if (!list_empty(&mnt->mnt_list))
umount_tree(mnt);
retval = 0;
}
Ø 释放vfsmount_lock spin 自选锁和namespace->sem 读写信号量。
3. 减少文件系统的根目录和挂载文件系统描述符相应的dentry对象的使用次数。
spin_unlock(&vfsmount_lock);
if (retval)
security_sb_umount_busy(mnt);
up_write(¤t->namespace->sem);
一 sys_umount执行过程
1. 调用__user_walk(fs/namei.c)获取加载点的路径名。查找的结果保存在nameidata定义的nd中。并且检查:
Ø 查找的路径是否是文件系统的挂载点。
Ø 被卸载的文件系统是否被加载。
Ø 用户是否有卸载权限。
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;
2. 调用do_umount,传入参数为加载的文件系统对象和设置的标示。
Ø 从加载的文件系统对象的mnt_sb 域获取超级快的地址。
struct super_block * sb = mnt->mnt_sb;
Ø 如果用户采用强制卸载,那么调用umount_begin超级块操作打断所有正在进行得加载操作。
lock_kernel();
if( (flags&MNT_FORCE) && sb->s_op->umount_begin)
sb->s_op->umount_begin(sb);
unlock_kernel();
Ø 如果被卸载的文件系统是根文件系统,并且用户没有请求分离,那么调用do_remount_sb重新加载只读的根文件系统。
if (mnt == current->fs->rootmnt && !(flags & MNT_DETACH)) {
/*
* Special case for "unmounting" root ...
* we just try to remount it readonly.
*/
down_write(&sb->s_umount);
if (!(sb->s_flags & MS_RDONLY)) {
lock_kernel();
DQUOT_OFF(sb);
retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);
unlock_kernel();
}
up_write(&sb->s_umount);
return retval;
}
Ø 获取当前进程的namespace->sem 读些信号和vfsmount_lock自选锁
down_write(¤t->namespace->sem);
spin_lock(&vfsmount_lock);
Ø 如果加载的文件系统不包括任何子系统的挂载点,或者用户强制断开文件系统,调用umount_tree 写在文件系统。
if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) {
if (!list_empty(&mnt->mnt_list))
umount_tree(mnt);
retval = 0;
}
Ø 释放vfsmount_lock spin 自选锁和namespace->sem 读写信号量。
3. 减少文件系统的根目录和挂载文件系统描述符相应的dentry对象的使用次数。
spin_unlock(&vfsmount_lock);
if (retval)
security_sb_umount_busy(mnt);
up_write(¤t->namespace->sem);