歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> Linux虛擬文件系統之文件系統卸載(sys_umount())

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

日期:2017/2/28 15:56:43   编辑:Linux教程
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. retval = -EPERM;
  19. /*如果用戶不具有卸載文件系統的特權*/
  20. if (!capable(CAP_SYS_ADMIN))
  21. goto dput_and_out;
  22. /*實際umount工作*/
  23. retval = do_umount(path.mnt, flags);
  24. dput_and_out:
  25. /* we mustn't call path_put() as that would clear mnt_expiry_mark */
  26. dput(path.dentry);
  27. mntput_no_expire(path.mnt);
  28. out:
  29. return retval;
  30. }

卸載實際工作

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