Linux虚拟文件系统之文件系统卸载(sys_umount())
来源:互联网 发布:欧洲圣母 知乎 编辑:程序博客网 时间:2024/06/06 12:00
Linux中卸载文件系统由umount系统调用实现,入口函数为sys_umount()。较于文件系统的安装较为简单,下面是具体的实现。
从内核链表中脱离
释放引用计数
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. }
卸载实际工作
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. }
从内核链表中脱离
1. /*完成实际的底层的卸载文件系统的任务。首先他将mnt的所有子移动至kill链表中, 2. 也就是传递进去的umount_list,然后将kill链表中的所有的vfsmount对象的一些字段设为无效状态。 3. */ 4. void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) 5. { 6. struct vfsmount *p; 7. 8. for (p = mnt; p; p = next_mnt(p, mnt)) 9. list_move(&p->mnt_hash, kill); 10. 11. if (propagate) 12. propagate_umount(kill); 13. 14. list_for_each_entry(p, kill, mnt_hash) { 15. list_del_init(&p->mnt_expire); 16. list_del_init(&p->mnt_list); 17. __touch_mnt_namespace(p->mnt_ns); 18. p->mnt_ns = NULL; 19. list_del_init(&p->mnt_child); 20. if (p->mnt_parent != p) { 21. p->mnt_parent->mnt_ghosts++; 22. p->mnt_mountpoint->d_mounted--; 23. } 24. change_mnt_propagation(p, MS_PRIVATE); 25. } 26. }
释放引用计数
1. void release_mounts(struct list_head *head) 2. { 3. struct vfsmount *mnt; 4. while (!list_empty(head)) { 5. mnt = list_first_entry(head, struct vfsmount, mnt_hash); 6. list_del_init(&mnt->mnt_hash); 7. if (mnt->mnt_parent != mnt) { 8. struct dentry *dentry; 9. struct vfsmount *m; 10. spin_lock(&vfsmount_lock); 11. dentry = mnt->mnt_mountpoint; 12. m = mnt->mnt_parent; 13. mnt->mnt_mountpoint = mnt->mnt_root; 14. mnt->mnt_parent = mnt; 15. m->mnt_ghosts--; 16. spin_unlock(&vfsmount_lock); 17. /*下面两个函数为减小引用计数,减到0时释放*/ 18. dput(dentry); 19. mntput(m); 20. } 21. /*vfsmount对象所占的内存空间最终在mntput()函数中释放*/ 22. mntput(mnt); 23. } 24. }
- Linux虚拟文件系统之文件系统卸载(sys_umount())
- Linux虚拟文件系统之文件系统卸载(sys_umount())
- Linux虚拟文件系统之文件系统卸载(sys_umount())
- Linux内核源码分析-卸载文件系统-sys_umount
- Linux内核-文件系统之虚拟文件系统
- linux文件系统(二) - 虚拟文件系统
- Linux虚拟文件系统之文件系统安装(sys_mount())
- Linux虚拟文件系统之文件系统安装(sys_mount())
- Linux虚拟文件系统之文件系统安装(sys_mount())
- Linux内核具体体系结构之虚拟文件系统
- Linux内核具体体系结构之虚拟文件系统
- Linux文件编程之虚拟文件系统(VFS)
- linux 内核编程之proc虚拟文件系统
- linux 内核编程之proc虚拟文件系统
- Linux文件编程之虚拟文件系统(VFS)
- linux设备驱动之VFS虚拟文件系统
- Linux文件系统卸载问题
- linux卸载Nfs文件系统
- mvc 3.0 自定义 AuthorizeAttribute 权限管理
- 缺陷管理(一)
- 齐次坐标的理解
- Hadoop Job Scheduling
- Android记住用户
- Linux虚拟文件系统之文件系统卸载(sys_umount())
- 软件测试学习网站小全
- 局域网内linux系统读取windows的共享目录
- 高斯克吕格与地理坐标相互转换算法(JS版本)
- Linux虚拟文件系统之文件系统安装(sys_mount())
- VS2010快捷键
- Linux虚拟文件系统(安装根文件系统)
- 在IE6里面的文字内容多出最后一个字出现在下一行 解决方法
- C++“窗口”程序设计启蒙(之二)