歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> Linux教程

Linux虛擬文件系統之文件系統卸載(sys_umount())

Linux中卸載文件系統由umount系統調用實現,入口函數為sys_umount()。較於文件系統的安裝較為簡單,下面是具體的實現。 [cpp]
  1. /*sys_umont系統調用*/  
  2. SYSCALL_DEFINE2(umount, char __user *, name, int, flags)  
  3. {  
  4.     struct path path;  
  5.     int retval;  
  6.     /*找到裝載點的vfsmount實例和dentry實例,二者包裝 
  7.     在一個nameidata結構中*/  
  8.     retval = user_path(name, &path);  
  9.     if (retval)  
  10.         goto out;  
  11.     retval = -EINVAL;  
  12.     /*如果查找的最終目錄不是文件系統的掛載點*/  
  13.     if (path.dentry != path.mnt->mnt_root)  
  14.         goto dput_and_out;  
  15.     /*如果要卸載的文件系統還沒有安裝在命名空間中*/  
  16.     if (!check_mnt(path.mnt))  
  17.         goto dput_and_out;  
  18.   
  19.     retval = -EPERM;  
  20.     /*如果用戶不具有卸載文件系統的特權*/  
  21.     if (!capable(CAP_SYS_ADMIN))  
  22.         goto dput_and_out;  
  23.     /*實際umount工作*/  
  24.     retval = do_umount(path.mnt, flags);  
  25. dput_and_out:  
  26.     /* we mustn't call path_put() as that would clear mnt_expiry_mark */  
  27.     dput(path.dentry);  
  28.     mntput_no_expire(path.mnt);  
  29. out:  
  30.     return retval;  
  31. }  

卸載實際工作

[cpp]
  1. static int do_umount(struct vfsmount *mnt, int flags)  
  2. {  
  3.     /*從vfsmount對象的mnt_sb字段檢索超級塊對象sb的地址*/  
  4.     struct super_block *sb = mnt->mnt_sb;  
  5.     int retval;  
  6.     /*初始化umount_list,該鏈表在後面的釋放中會做臨時鏈表 
  7.     用*/  
  8.     LIST_HEAD(umount_list);  
  9.   
  10.     retval = security_sb_umount(mnt, flags);  
  11.     if (retval)  
  12.         return retval;  
  13.   
  14.     /* 
  15.      * Allow userspace to request a mountpoint be expired rather than 
  16.      * unmounting unconditionally. Unmount only happens if: 
  17.      *  (1) the mark is already set (the mark is cleared by mntput()) 
  18.      *  (2) the usage count == 1 [parent vfsmount] + 1 [sys_umount] 
  19.      */  
  20.      /*如果設置了MNT_EXPIRE標志,即要標記掛載點“到期”*/  
  21.     if (flags & MNT_EXPIRE) {  
  22.         /*若要卸載的文件系統是根文件系統或者同時設置了 
  23.         MNT_FORCE或MNT_DETACH,則返回-EINVAL*/  
  24.         if (mnt == current->fs->root.mnt ||  
  25.             flags & (MNT_FORCE | MNT_DETACH))  
  26.             return -EINVAL;  
  27.         /*檢查vfsmount的引用計數,若不為2,則返回-EBUSY, 
  28.         要卸載的文件系統在卸載的時候不能有引用者, 
  29.         這個2代表vfsmount的父vfsmount和sys_umount()對本對象的引用*/  
  30.         if (atomic_read(&mnt->mnt_count) != 2)  
  31.             return -EBUSY;  
  32.         /*設置vfsmount對象的mnt_expiry_mark字段為1。*/  
  33.         if (!xchg(&mnt->mnt_expiry_mark, 1))  
  34.             return -EAGAIN;  
  35.     }  
  36.   
  37.     /* 
  38.      * If we may have to abort operations to get out of this 
  39.      * mount, and they will themselves hold resources we must 
  40.      * allow the fs to do things. In the Unix tradition of 
  41.      * 'Gee thats tricky lets do it in userspace' the umount_begin 
  42.      * might fail to complete on the first run through as other tasks 
  43.      * must return, and the like. Thats for the mount program to worry 
  44.      * about for the moment. 
  45.      */  
  46.      /*如果用戶要求強制卸載操作,則調用umount_begin 
  47.      超級塊操作中斷任何正在進行的安裝操作*/  
  48.     /*當然如果特定的文件系統定義了下面函數則調用它*/  
  49.     if (flags & MNT_FORCE && sb->s_op->umount_begin) {  
  50.         sb->s_op->umount_begin(sb);  
  51.     }  
  52.   
  53.     /* 
  54.      * No sense to grab the lock for this test, but test itself looks 
  55.      * somewhat bogus. Suggestions for better replacement? 
  56.      * Ho-hum... In principle, we might treat that as umount + switch 
  57.      * to rootfs. GC would eventually take care of the old vfsmount. 
  58.      * Actually it makes sense, especially if rootfs would contain a 
  59.      * /reboot - static binary that would close all descriptors and 
  60.      * call reboot(9). Then init(8) could umount root and exec /reboot. 
  61.      */  
  62.      /*如果要卸載的文件系統是根文件系統,且用戶 
  63.      並不要求真正地把它卸載下來(即設置了MNT_DETACH標志, 
  64.      這個標志僅僅標記掛載點為不能再訪問,知道掛載不busy 
  65.      時才卸載),則調用do_remount_sb()重新安裝根文件系統為只 
  66.      讀並終止,並返回do_remount_sb()的返回值。*/  
  67.     if (mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) {  
  68.         /* 
  69.          * Special case for "unmounting" root ... 
  70.          * we just try to remount it readonly. 
  71.          */  
  72.         down_write(&sb->s_umount);  
  73.         if (!(sb->s_flags & MS_RDONLY))  
  74.             retval = do_remount_sb(sb, MS_RDONLY, NULL, 0);  
  75.         up_write(&sb->s_umount);  
  76.         return retval;  
  77.     }  
  78.       
  79.     down_write(&namespace_sem);  
  80.     /*為進行寫操作而獲取當前進程的namespace_sem讀/寫信號量和vfsmount_lock自旋鎖*/  
  81.     spin_unlock(&vfsmount_lock);  
  82.     spin_lock(&vfsmount_lock);  
  83.     event++;  
  84.   
  85.     if (!(flags & MNT_DETACH))  
  86.         shrink_submounts(mnt, &umount_list);  
  87.   
  88.     retval = -EBUSY;  
  89.     /*如果已安裝文件系統不包含任何子安裝文件系統的安裝點,或者用戶要求強制 
  90.     卸載文件系統,則調用umount_tree()卸載文件系統(及其所有子文件系統)。*/  
  91.     if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) {  
  92.         if (!list_empty(&mnt->mnt_list))  
  93.             /*完成實際的底層的卸載文件系統的任務。首先他將mnt的所有孩子移動至kill鏈表中, 
  94.             也就是傳遞進去的umount_list,然後將kill鏈表中的所有的vfsmount對象的一些字段設為無效狀態。 
  95.             */  
  96.             umount_tree(mnt, 1, &umount_list);  
  97.         retval = 0;  
  98.     }  
  99.       
  100.     if (retval)  
  101.         security_sb_umount_busy(mnt);  
  102.     /*釋放vfsmount_lock自旋鎖和當前進程的namespace_sem讀/寫信號量*/  
  103.     up_write(&namespace_sem);  
  104.     /*減小相應文件系統根目錄的目錄項對象和已經安裝文件系統 
  105.     描述符的引用計數器值,這些計數器值由path_lookup()增加*/  
  106.     release_mounts(&umount_list);  
  107.     return retval;  
  108. }  
Copyright © Linux教程網 All Rights Reserved