linux内核umount源代码分析
之前我们讲过mount的内核源代码,今天我们来一起看一下umount系统调用的内核源代码实现吧。
首先看sys_umount函数,定义在fs/namespace.c,定义如下
asmlinkage long sys_umount(char __user * name, int flags)
{
struct nameidata nd;
int retval;
/*之前讲过的,格局传入的路径名返回文件的inode和vfsmount结构体*/
retval = __user_walk(name, LOOKUP_FOLLOW, &nd);
/*如果失败了就返回错误代码*/
if (retval)
goto out;
retval = -EINVAL;
/*如果传入的umount点不是对应的挂载文件系统的根节点,也返回*/
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_on_umount(&nd);
out:
return retval;
}
我们继续看do_umount函数,do_umount函数定义在fs/namespace.c,定义如下
static int do_umount(struct vfsmount *mnt, int flags)
{
/*挂载点的超级块*/
struct super_block *sb = mnt->mnt_sb;
int retval;
LIST_HEAD(umount_list);
/*安全操作,可以不必管*/
retval = security_sb_umount(mnt, flags);
if (retval)
return retval;
/*如果挂载时间到了 */
if (flags & MNT_EXPIRE) {
/*当前进程的根节点不能umount*/
if (mnt == current->fs->rootmnt ||
flags & (MNT_FORCE | MNT_DETACH))
return -EINVAL;
/*如果有其他进程子啊用,不能umount*/
if (atomic_read(&mnt->mnt_count) != 2)
return -EBUSY;
/*expiry位标识是否超时*/
if (!xchg(&mnt->mnt_expiry_mark, 1))
return -EAGAIN;
}
/*调用超级块的函数umount_begin做对应的初始工作,以ext2文件系统为例,ext2没有umount_begin函数,所以这个函数视不同的文件系统而不同*/
lock_kernel();
if (sb->s_op->umount_begin)
sb->s_op->umount_begin(mnt, flags);
unlock_kernel();
/*如果卸载的是当前进程的根文件系统根节点,并且不是卸载,是remount,修改某些flag*/
if (mnt == current->fs->rootmnt && !(flags & MNT_DETACH)) {
/*调用do_remount_sb更改flags*/
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;
}
down_write(&namespace_sem);
spin_lock(&vfsmount_lock);
event++;
retval = -EBUSY;
if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) {
if (!list_empty(&mnt->mnt_list))
/*把vfsmount结构体从链表上去除*/
umount_tree(mnt, 1, &umount_list);
retval = 0;
}
spin_unlock(&vfsmount_lock);
/*安全操作,可以不管*/
if (retval)
security_sb_umount_busy(mnt);
up_write(&namespace_sem);
release_mounts(&umount_list);
return retval;
}
还没有评论,来说两句吧...