Linux虚拟文件系统之文件系统卸载(sys

字体大小: 中小 标准 ->行高大小: 标准
Linux中卸载文件系统由umount系统调用实现,入口函数为sys_umount()。较于文件系统的安装较为简单,下面是具体的实现。 [cpp]
  1. /*sys_umont系统调用*/   SYSCALL_DEFINE2(umount, char __user *, name, int, flags)  
  2. {       struct path path;  
  3.     int retval;       /*找到装载点的vfsmount实例和dentry实例,二者包装 
  4.     在一个nameidata结构中*/       retval = user_path(name, &path);  
  5.     if (retval)           goto out;  
  6.     retval = -EINVAL;       /*如果查找的最终目录不是文件系统的挂载点*/  
  7.     if (path.dentry != path.mnt->mnt_root)           goto dput_and_out;  
  8.     /*如果要卸载的文件系统还没有安装在命名空间中*/       if (!check_mnt(path.mnt))  
  9.         goto dput_and_out;     
  10.     retval = -EPERM;       /*如果用户不具有卸载文件系统的特权*/  
  11.     if (!capable(CAP_SYS_ADMIN))           goto dput_and_out;  
  12.     /*实际umount工作*/       retval = do_umount(path.mnt, flags);  
  13. dput_and_out:       /* we mustn't call path_put() as that would clear mnt_expiry_mark */  
  14.     dput(path.dentry);       mntput_no_expire(path.mnt);  
  15. out:       return retval;  
  16. }  

卸载实际工作

[cpp]
  1. static int do_umount(struct vfsmount *mnt, int flags)   {  
  2.     /*从vfsmount对象的mnt_sb字段检索超级块对象sb的地址*/       struct super_block *sb = mnt->mnt_sb;  
  3.     int retval;       /*初始化umount_list,该链表在后面的释放中会做临时链表 
  4.     用*/       LIST_HEAD(umount_list);  
  5.        retval = security_sb_umount(mnt, flags);  
  6.     if (retval)           return retval;  
  7.        /* 
  8.      * Allow userspace to request a mountpoint be expired rather than       * unmounting unconditionally. Unmount only happens if: 
  9.      *  (1) the mark is already set (the mark is cleared by mntput())       *  (2) the usage count == 1 [parent vfsmount] + 1 [sys_umount] 
  10.      */        /*如果设置了MNT_EXPIRE标志,即要标记挂载点“到期”*/  
  11.     if (flags & MNT_EXPIRE) {           /*若要卸载的文件系统是根文件系统或者同时设置了 
  12.         MNT_FORCE或MNT_DETACH,则返回-EINVAL*/           if (mnt == current->fs->root.mnt ||  
  13.             flags & (MNT_FORCE | MNT_DETACH))               return -EINVAL;  
  14.         /*检查vfsmount的引用计数,若不为2,则返回-EBUSY,          要卸载的文件系统在卸载的时候不能有引用者, 
  15.         这个2代表vfsmount的父vfsmount和sys_umount()对本对象的引用*/           if (atomic_read(&mnt->mnt_count) != 2)  
  16.             return -EBUSY;           /*设置vfsmount对象的mnt_expiry_mark字段为1。*/  
  17.         if (!xchg(&mnt->mnt_expiry_mark, 1))               return -EAGAIN;  
  18.     }     
  19.     /*       * If we may have to abort operations to get out of this 
  20.      * mount, and they will themselves hold resources we must       * allow the fs to do things. In the Unix tradition of 
  21.      * 'Gee thats tricky lets do it in userspace' the umount_begin       * might fail to complete on the first run through as other tasks 
  22.      * must return, and the like. Thats for the mount program to worry       * about for the moment. 
  23.      */        /*如果用户要求强制卸载操作,则调用umount_begin 
  24.      超级块操作中断任何正在进行的安装操作*/       /*当然如果特定的文件系统定义了下面函数则调用它*/  
  25.     if (flags & MNT_FORCE && sb->s_op->umount_begin) {           sb->s_op->umount_begin(sb);  
  26.     }     
  27.     /*       * No sense to grab the lock for this test, but test itself looks 
  28.      * somewhat bogus. Suggestions for better replacement?       * Ho-hum... In principle, we might treat that as umount + switch 
  29.      * to rootfs. GC would eventually take care of the old vfsmount.       * Actually it makes sense, especially if rootfs would contain a 
  30.      * /reboot - static binary that would close all descriptors and       * call reboot(9). Then init(8) could umount root and exec /reboot. 
  31.      */        /*如果要卸载的文件系统是根文件系统,且用户 
  32.      并不要求真正地把它卸载下来(即设置了MNT_DETACH标志,       这个标志仅仅标记挂载点为不能再访问,知道挂载不busy 
  33.      时才卸载),则调用do_remount_sb()重新安装根文件系统为只       读并终止,并返回do_remount_sb()的返回值。*/  
  34.     if (mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) {           /* 
  35.          * Special case for "unmounting" root ...           * we just try to remount it readonly. 
  36.          */           down_write(&sb->s_umount);  
  37.         if (!(sb->s_flags & MS_RDONLY))               retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);  
  38.         up_write(&sb->s_umount);           return retval;  
  39.     }         
  40.     down_write(&namespace_sem);       /*为进行写操作而获取当前进程的namespace_sem读/写信号量和vfsmount_lock自旋锁*/  
  41.     spin_unlock(&vfsmount_lock);       spin_lock(&vfsmount_lock);  
  42.     event++;     
  43.     if (!(flags & MNT_DETACH))           shrink_submounts(mnt, &umount_list);  
  44.        retval = -EBUSY;  
  45.     /*如果已安装文件系统不包含任何子安装文件系统的安装点,或者用户要求强制      卸载文件系统,则调用umount_tree()卸载文件系统(及其所有子文件系统)。*/  
  46.     if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) {           if (!list_empty(&mnt->mnt_list))  
  47.             /*完成实际的底层的卸载文件系统的任务。首先他将mnt的所有孩子移动至kill链表中,              也就是传递进去的umount_list,然后将kill链表中的所有的vfsmount对象的一些字段设为无效状态。 
  48.             */               umount_tree(mnt, 1, &umount_list);  
  49.         retval = 0;       }  
  50.            if (retval)  
  51.         security_sb_umount_busy(mnt);       /*释放vfsmount_lock自旋锁和当前进程的namespace_sem读/写信号量*/  
  52.     up_write(&namespace_sem);       /*减小相应文件系统根目录的目录项对象和已经安装文件系统 
  53.     描述符的引用计数器值,这些计数器值由path_lookup()增加*/       release_mounts(&umount_list);  
  54.     return retval;   }  

此文章由 http://www.ositren.com 收集整理 ,地址为: http://www.ositren.com/htmls/57752.html