0 00:00:00,000 --> 00:00:07,080 1 00:00:07,120 --> 00:00:08,080 好 那我们接下来 2 00:00:08,120 --> 00:00:09,320 再稍微具体一点 3 00:00:09,360 --> 00:00:12,040 看一下uCore文件系统一个架构 4 00:00:12,080 --> 00:00:13,440 那么这一块呢 5 00:00:13,480 --> 00:00:15,560 比刚才要更深入一些 6 00:00:15,600 --> 00:00:18,520 从两个角度 一个是从控制流的角度 7 00:00:18,560 --> 00:00:21,680 一个从数据结构的角度来看uCore 8 00:00:21,720 --> 00:00:24,600 文件系统一个架构 9 00:00:24,640 --> 00:00:27,160 首先我们看一下这个控制流 10 00:00:27,200 --> 00:00:29,400 就是说 用户访问文件的时候呢 11 00:00:29,440 --> 00:00:32,080 它从应用程序开始发出请求 12 00:00:32,120 --> 00:00:34,880 到最后从硬盘中读 13 00:00:34,920 --> 00:00:36,400 或者写相应的数据 14 00:00:36,440 --> 00:00:38,640 这个过程从上而下 15 00:00:38,680 --> 00:00:43,720 看看这个访问是怎么一步步来完成的 16 00:00:43,760 --> 00:00:46,840 那第一个 是通用文件系统的访问接口 17 00:00:46,880 --> 00:00:48,440 那么这个是包含两部分 18 00:00:48,480 --> 00:00:51,080 一部分是给我们应用程序 19 00:00:51,120 --> 00:00:52,640 提供了一些API 20 00:00:52,680 --> 00:00:54,760 这些API呢是放在一个 21 00:00:54,800 --> 00:00:56,240 简单一个C库里面 22 00:00:56,280 --> 00:00:59,280 那这C库呢会访问相应的系统调用 23 00:00:59,320 --> 00:01:02,280 从而可以获得uCore操作系统 24 00:01:02,320 --> 00:01:06,760 关于文件这一块的一个服务 25 00:01:06,800 --> 00:01:09,400 那对应的这个函数可以看出来 26 00:01:09,440 --> 00:01:11,400 我们调用 比如说在这里面 27 00:01:11,440 --> 00:01:15,560 提供了write 就是写文件这么一个操作 28 00:01:15,600 --> 00:01:17,560 那么write呢 会最终调这个 29 00:01:17,600 --> 00:01:19,080 关于write的sys_call 30 00:01:19,120 --> 00:01:21,680 使得我们内核通过sys_write 31 00:01:21,720 --> 00:01:24,680 来完成接下来的这个服务请求 32 00:01:24,720 --> 00:01:26,120 这是第一个层面 33 00:01:26,160 --> 00:01:27,480 就是站在用户的角度看待 34 00:01:27,520 --> 00:01:31,960 这个层面的一个调用过程 35 00:01:32,000 --> 00:01:35,800 那第二个呢一旦说在操作系统里面 36 00:01:35,840 --> 00:01:38,160 我们的sys_call这个level 37 00:01:38,200 --> 00:01:39,880 得到了一个请求 说 38 00:01:39,920 --> 00:01:42,280 要完成一个文件的写操作 39 00:01:42,320 --> 00:01:43,720 那接下来的控制就会 40 00:01:43,760 --> 00:01:45,760 交给我们什么呢 VFS 41 00:01:45,800 --> 00:01:47,360 文件系统的抽象层 42 00:01:47,400 --> 00:01:49,120 就是虚拟文件系统这一块 43 00:01:49,160 --> 00:01:51,840 虚拟文件系统呢它包含了很多部分 44 00:01:51,880 --> 00:01:56,120 包括了文件的接口 目录的接口 45 00:01:56,160 --> 00:01:59,240 inode的接口以及文件系统的接口 46 00:01:59,280 --> 00:02:00,600 整体一个抽象 47 00:02:00,640 --> 00:02:02,720 那么这个呢 屏蔽了底层 48 00:02:02,760 --> 00:02:07,400 具体文件系统和设备的一些差异性 49 00:02:07,440 --> 00:02:11,480 可以看出来刚才这个sys_write 50 00:02:11,520 --> 00:02:12,840 会进一步向下调用 51 00:02:12,880 --> 00:02:16,280 会访问什么呢 sysfile_write 52 00:02:16,320 --> 00:02:18,360 file_write以及vop_write 53 00:02:18,400 --> 00:02:21,160 需要注意的是 从file_write到vop_write 54 00:02:21,200 --> 00:02:22,880 其实形成一个转换 55 00:02:22,920 --> 00:02:26,240 这个转换是从文件 面向用户这个文件 56 00:02:26,280 --> 00:02:31,240 转成了面向具体硬盘里面的操作的一个inode 57 00:02:31,280 --> 00:02:35,640 这是一个转换 58 00:02:35,680 --> 00:02:39,720 当VFS把用户发出的针对文件的写操作 59 00:02:39,760 --> 00:02:42,400 转变对一个inode写操作之后呢 60 00:02:42,440 --> 00:02:43,640 这个inode本身 61 00:02:43,680 --> 00:02:46,280 还是一个站在虚拟文件系统上面 62 00:02:46,320 --> 00:02:47,840 一个抽象的inode 63 00:02:47,880 --> 00:02:50,520 它会进一步转变成什么呢 64 00:02:50,560 --> 00:02:51,840 一个具体文件系统 65 00:02:51,880 --> 00:02:53,120 在这里面我们是以一个 66 00:02:53,160 --> 00:02:55,360 simple file system来举的例子 67 00:02:55,400 --> 00:02:57,000 一个具体的文件系统呢 68 00:02:57,040 --> 00:02:58,280 它的一个inode情况 69 00:02:58,320 --> 00:03:00,760 通过inode来完成后续的 70 00:03:00,800 --> 00:03:03,200 针对磁盘的一个读写 71 00:03:03,240 --> 00:03:07,680 72 00:03:07,720 --> 00:03:11,480 那可以看到 刚才的vop_write呢 73 00:03:11,520 --> 00:03:14,600 会进一步变成fs的write 74 00:03:14,640 --> 00:03:16,520 就是simple file system 的write 75 00:03:16,560 --> 00:03:22,000 这个write会再通过wbuf (write_buffer) 76 00:03:22,040 --> 00:03:23,240 这么一个操作 77 00:03:23,280 --> 00:03:25,720 来向我们设备发出请求 78 00:03:25,760 --> 00:03:27,240 比方说做一个写操作 79 00:03:27,280 --> 00:03:28,360 那么它的数据内容 80 00:03:28,400 --> 00:03:29,480 是从我们应用程序 81 00:03:29,520 --> 00:03:30,880 刚才那个高层的 82 00:03:30,920 --> 00:03:34,520 write的buffer里传到这里面来 83 00:03:34,560 --> 00:03:36,200 然后把这个buffer内容 84 00:03:36,240 --> 00:03:42,480 会写到我们的device中去 85 00:03:42,520 --> 00:03:43,480 Simple file system 86 00:03:43,520 --> 00:03:44,600 它发出一个写请求之后呢 87 00:03:44,640 --> 00:03:47,600 最后会通过一个外设的访问接口 88 00:03:47,640 --> 00:03:50,480 来完成对外设的一个访问 89 00:03:50,520 --> 00:03:53,920 这个外设呢 和我们刚才说那个 90 00:03:53,960 --> 00:03:56,320 具体的硬盘呢还是不一样的 91 00:03:56,360 --> 00:03:58,440 它是在硬盘之上建立成抽象 92 00:03:58,480 --> 00:04:01,640 而这个抽象我们称之为I/O设备接口 93 00:04:01,680 --> 00:04:03,080 这个接口也是由 94 00:04:03,120 --> 00:04:05,080 我们VFS来进行管理的 95 00:04:05,120 --> 00:04:09,120 96 00:04:09,160 --> 00:04:11,560 可以看到当Simple file system 97 00:04:11,600 --> 00:04:13,600 发出wbuf这个操作之后呢 98 00:04:13,640 --> 00:04:15,520 会把这个操作转变成一个 99 00:04:15,560 --> 00:04:18,040 针对device的一个操作 100 00:04:18,080 --> 00:04:19,800 这个device操作呢有很多类 101 00:04:19,840 --> 00:04:24,080 我们刚才已经看到有面向串口的 102 00:04:24,120 --> 00:04:26,880 有面向屏幕的 也有面向硬盘的 103 00:04:26,920 --> 00:04:29,320 还有甚至空设备 有不同类型的设备 104 00:04:29,360 --> 00:04:30,960 我们最终选择是disk 105 00:04:31,000 --> 00:04:32,520 我们前面已经设定好了 106 00:04:32,560 --> 00:04:34,800 SFS它的数据是位于 107 00:04:34,840 --> 00:04:36,680 我们disk 0这个磁盘上的 108 00:04:36,720 --> 00:04:40,240 所以 当发出这个dop_io的时候 109 00:04:40,280 --> 00:04:42,680 最终会调disk 0的I/O 110 00:04:42,720 --> 00:04:46,040 使得它可以向disk 0发出写请求 111 00:04:46,080 --> 00:04:49,680 112 00:04:49,720 --> 00:04:51,600 这层I/O设备接口呢 113 00:04:51,640 --> 00:04:52,960 是一个抽象的接口 114 00:04:53,000 --> 00:04:54,800 它里面可以包含不同类型的设备 115 00:04:54,840 --> 00:04:57,000 最终disk 0会访问什么呢 116 00:04:57,040 --> 00:04:59,000 会访问一个驱动 117 00:04:59,040 --> 00:05:01,160 这个驱动是硬盘驱动 118 00:05:01,200 --> 00:05:03,600 通过硬盘驱动来完成实际的 119 00:05:03,640 --> 00:05:05,840 往这个硬盘数据的一个读写 120 00:05:05,880 --> 00:05:07,800 121 00:05:07,840 --> 00:05:10,480 可以看出来 刚才这个disk 0的I/O 122 00:05:10,520 --> 00:05:12,720 会转变成一个IDE的write 123 00:05:12,760 --> 00:05:13,920 因为我们前面知道 124 00:05:13,960 --> 00:05:15,440 最开始是一个write操作 125 00:05:15,480 --> 00:05:16,960 那么这个I/O既可以支持读 126 00:05:17,000 --> 00:05:17,920 也可以支持写 127 00:05:17,960 --> 00:05:19,640 我们会变成一个IDE的write之后呢 128 00:05:19,680 --> 00:05:22,200 完成把应有程序提供的数据 129 00:05:22,240 --> 00:05:25,120 最终写到我们硬盘扇区里面去 130 00:05:25,160 --> 00:05:27,600 就是这个ide_write_secs 131 00:05:27,640 --> 00:05:29,800 IDE硬盘它的扇区 132 00:05:29,840 --> 00:05:33,920 这是一个整个的执行过程 133 00:05:33,960 --> 00:05:35,320 那么前面呢我们看到一个 134 00:05:35,360 --> 00:05:37,560 从上到下的控制流的一个访问 135 00:05:37,600 --> 00:05:39,600 针对write的一个操作 136 00:05:39,640 --> 00:05:41,440 接下来我们可以看看 137 00:05:41,480 --> 00:05:44,920 在内核中数据结构整体一个布局 138 00:05:44,960 --> 00:05:48,760 那么也是从高层逐步往下来展开 139 00:05:48,800 --> 00:05:51,640 给大家做一个讲解 140 00:05:51,680 --> 00:05:53,240 我们知道 我们的应用 141 00:05:53,280 --> 00:05:55,120 其实是以进程的方式 142 00:05:55,160 --> 00:05:57,400 在操作系统管理之下运行的 143 00:05:57,440 --> 00:06:01,720 所以在我们进程控制块里扩展了一部分 144 00:06:01,760 --> 00:06:04,200 跟文件相关的一些数据结构 145 00:06:04,240 --> 00:06:06,360 比如说我们的proc_struct 146 00:06:06,400 --> 00:06:08,920 它包含了一个files_struct 147 00:06:08,960 --> 00:06:11,960 而这个files_struct实际上是一个数组 148 00:06:12,000 --> 00:06:13,640 在这数组里面 很重要一点 149 00:06:13,680 --> 00:06:14,640 它打开了哪些文件 150 00:06:14,680 --> 00:06:16,840 它有一个opened file array 151 00:06:16,880 --> 00:06:20,640 根据打开文件 可以进一步找到 152 00:06:20,680 --> 00:06:23,640 这个文件所对应inode 153 00:06:23,680 --> 00:06:24,920 可以看出来 这一块区域 154 00:06:24,960 --> 00:06:27,440 是和我们进程紧密相连的 155 00:06:27,480 --> 00:06:29,080 应该说 是属于我们 156 00:06:29,120 --> 00:06:31,000 进程控制块的一部分 157 00:06:31,040 --> 00:06:32,640 但光有这部分还不够 158 00:06:32,680 --> 00:06:34,520 我们还需要进一步去 159 00:06:34,560 --> 00:06:37,960 和我们系统级inode进行联系 160 00:06:38,000 --> 00:06:40,960 所以可以看着这个struct file呢 161 00:06:41,000 --> 00:06:43,760 会有一个信息会到一个inode里面去 162 00:06:43,800 --> 00:06:47,240 而这个inode信息是属于VFS 163 00:06:47,280 --> 00:06:49,440 可以看出来在 VFS管理之下 164 00:06:49,480 --> 00:06:52,560 它有很多这些 对应的数据结构 165 00:06:52,600 --> 00:06:57,160 我们这里面关注哪个呢 in_info 166 00:06:57,200 --> 00:06:59,120 这个in其实是inode一个简称 167 00:06:59,160 --> 00:07:01,560 这个VFS这一层的inode 168 00:07:01,600 --> 00:07:06,280 它会进一步表述具体的inode怎么回事 169 00:07:06,320 --> 00:07:08,800 你可以看出来 这是一个union结构 170 00:07:08,840 --> 00:07:10,160 比较有意思 这个union结构呢 171 00:07:10,200 --> 00:07:12,720 其实说它包含了不同类型的inode 172 00:07:12,760 --> 00:07:14,760 我们在这里面 具体而言 173 00:07:14,800 --> 00:07:16,840 是一个SFS的一个inode 174 00:07:16,880 --> 00:07:18,840 就是simple file system的一个inode 175 00:07:18,880 --> 00:07:21,800 这个结构也是在内存中的 176 00:07:21,840 --> 00:07:23,600 这个在内存中inode结构呢 177 00:07:23,640 --> 00:07:25,080 包含了更进一步的 178 00:07:25,120 --> 00:07:28,640 跟硬盘相关的SFS的信息 179 00:07:28,680 --> 00:07:31,920 也很重要数据就是sfs_disk_inode 180 00:07:31,960 --> 00:07:33,200 那么这个inode信息 181 00:07:33,240 --> 00:07:36,120 其实就是在硬盘中存储的内容 182 00:07:36,160 --> 00:07:37,720 所以说 这一块内容 183 00:07:37,760 --> 00:07:40,120 其实和我们硬盘中的一块区域中 184 00:07:40,160 --> 00:07:42,600 专门来存储inode的数据块呢 185 00:07:42,640 --> 00:07:44,240 它里面的内容是一致的 186 00:07:44,280 --> 00:07:47,560 那么这个sfs_disk_inode 187 00:07:47,600 --> 00:07:50,920 它的成员变量中有很多丰富的信息 188 00:07:50,960 --> 00:07:53,880 比如说这里面type 表明这个inode 189 00:07:53,920 --> 00:07:56,400 它的类型是文件 目录 190 00:07:56,440 --> 00:07:58,000 还是其它什么东西 191 00:07:58,040 --> 00:08:01,120 第二个呢它这个direct和indirect 192 00:08:01,160 --> 00:08:03,760 表明了它所存储的数据 193 00:08:03,800 --> 00:08:06,440 所在数据块的位置 194 00:08:06,480 --> 00:08:07,440 有了这个信息之后 195 00:08:07,480 --> 00:08:09,800 我们就可以很容易找到这个inode 196 00:08:09,840 --> 00:08:11,280 所对应文件的内容 197 00:08:11,320 --> 00:08:13,320 或者目录内容在什么地方 198 00:08:13,360 --> 00:08:15,760 关于simple file system这个结构里面 199 00:08:15,800 --> 00:08:17,600 有很多的内容 200 00:08:17,640 --> 00:08:18,840 是和我们硬盘中的 201 00:08:18,880 --> 00:08:21,040 数据结构是直接对应的 202 00:08:21,080 --> 00:08:22,400 当然我们在具体访问的时候 203 00:08:22,440 --> 00:08:23,680 需要把部分的内容 204 00:08:23,720 --> 00:08:27,720 也会取到内存中来做进一步的操作 205 00:08:27,760 --> 00:08:30,560 从上到下可以看出来这整个的过程 206 00:08:30,600 --> 00:08:33,840 从进程开始 到uCore kernel里面 207 00:08:33,880 --> 00:08:35,640 system level的数据结构 208 00:08:35,680 --> 00:08:39,800 VFS再进一步引申到我们具体的SFS 209 00:08:39,840 --> 00:08:41,400 那么SFS又分两块 210 00:08:41,440 --> 00:08:43,760 一块是内存中一些管理信息 211 00:08:43,800 --> 00:08:45,680 还有一部分是从硬盘中 212 00:08:45,720 --> 00:08:49,520 读取的一些管理信息和数据信息 213 00:08:49,560 --> 00:08:52,800 形成了整个的 跟文件系统相关的 214 00:08:52,840 --> 00:08:54,760 数据结构一个关系图 215 00:08:54,800 --> 00:08:54,840