Linux中卸载文件系统由umount系统调用实现,入口函数为sys_umount()。较于文件系统的安装较为简单,下面是具体的实现。
-
- SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
- {
- struct path path;
- int retval;
-
-
- retval = user_path(name, &path);
- if (retval)
- goto out;
- retval = -EINVAL;
-
- if (path.dentry != path.mnt->mnt_root)
- goto dput_and_out;
-
- if (!check_mnt(path.mnt))
- goto dput_and_out;
-
- retval = -EPERM;
-
- if (!capable(CAP_SYS_ADMIN))
- goto dput_and_out;
-
- retval = do_umount(path.mnt, flags);
- dput_and_out:
-
- dput(path.dentry);
- mntput_no_expire(path.mnt);
- out:
- return retval;
- }
卸载实际工作
- 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) {
-
-
- if (mnt == current->fs->root.mnt ||
- flags & (MNT_FORCE | MNT_DETACH))
- return -EINVAL;
-
-
-
- if (atomic_read(&mnt->mnt_count) != 2)
- return -EBUSY;
-
- if (!xchg(&mnt->mnt_expiry_mark, 1))
- return -EAGAIN;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
- if (flags & MNT_FORCE && sb->s_op->umount_begin) {
- sb->s_op->umount_begin(sb);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- if (mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) {
-
-
-
-
- down_write(&sb->s_umount);
- if (!(sb->s_flags & MS_RDONLY))
- retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);
- up_write(&sb->s_umount);
- return retval;
- }
-
- down_write(&namespace_sem);
-
- spin_unlock(&vfsmount_lock);
- spin_lock(&vfsmount_lock);
- event++;
-
- if (!(flags & MNT_DETACH))
- shrink_submounts(mnt, &umount_list);
-
- retval = -EBUSY;
-
-
- if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) {
- if (!list_empty(&mnt->mnt_list))
-
-
-
- umount_tree(mnt, 1, &umount_list);
- retval = 0;
- }
-
- if (retval)
- security_sb_umount_busy(mnt);
-
- up_write(&namespace_sem);
-
-
- release_mounts(&umount_list);
- return retval;
- }
从内核链表中脱离
-
-
-
- void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
- {
- struct vfsmount *p;
-
- for (p = mnt; p; p = next_mnt(p, mnt))
- list_move(&p->mnt_hash, kill);
-
- if (propagate)
- propagate_umount(kill);
-
- list_for_each_entry(p, kill, mnt_hash) {
- list_del_init(&p->mnt_expire);
- list_del_init(&p->mnt_list);
- __touch_mnt_namespace(p->mnt_ns);
- p->mnt_ns = NULL;
- list_del_init(&p->mnt_child);
- if (p->mnt_parent != p) {
- p->mnt_parent->mnt_ghosts++;
- p->mnt_mountpoint->d_mounted--;
- }
- change_mnt_propagation(p, MS_PRIVATE);
- }
- }
释放引用计数
- void release_mounts(struct list_head *head)
- {
- struct vfsmount *mnt;
- while (!list_empty(head)) {
- mnt = list_first_entry(head, struct vfsmount, mnt_hash);
- list_del_init(&mnt->mnt_hash);
- if (mnt->mnt_parent != mnt) {
- struct dentry *dentry;
- struct vfsmount *m;
- spin_lock(&vfsmount_lock);
- dentry = mnt->mnt_mountpoint;
- m = mnt->mnt_parent;
- mnt->mnt_mountpoint = mnt->mnt_root;
- mnt->mnt_parent = mnt;
- m->mnt_ghosts--;
- spin_unlock(&vfsmount_lock);
-
- dput(dentry);
- mntput(m);
- }
-
- mntput(mnt);
- }
- }