├── LICENSE ├── Lectures ├── Lecture_1.1_RT-Thread_文件系统应用笔记.md ├── Lecture_1.2_文件系统数据结构解析.md ├── Lecture_1.3_DFS文件描述符管理.md └── assets │ ├── 1528354745063.png │ ├── 1528355204158.png │ ├── 1528355291434.png │ ├── 1528356393167.png │ ├── 1528356861018.png │ ├── 1528362120705.png │ ├── 1528416425397.png │ ├── 1528417402476.png │ ├── 1528419313880.png │ ├── 1528419330733.png │ ├── 1528419369526.png │ ├── 1528419422313.png │ ├── 1528419519371.png │ ├── 1528419537678.png │ ├── 1528419554110.png │ ├── 1528419584942.png │ ├── 1528420167135.png │ ├── 1528421204197.png │ ├── 1528423169454.png │ ├── 1528423305271.png │ ├── 1528423429971.png │ ├── 1528449652153.png │ ├── 1528449677236.png │ ├── 1528450972107.png │ ├── 1528451222822.png │ ├── 1528451278720.png │ ├── 1528457058001.png │ ├── 1528459997690.png │ ├── 1528460010565.png │ ├── 1528680175178.png │ ├── rt_fs_structure.png │ └── stm32f429-apollo.png └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-2017 SummerGift <459994202@qq.com> 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | 'Software'), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /Lectures/Lecture_1.1_RT-Thread_文件系统应用笔记.md: -------------------------------------------------------------------------------- 1 | # RT-Thread 文件系统应用笔记 # 2 | 3 | ​ 本应用笔记介绍了 RT-Thread 文件系统的基本知识和使用方法,帮助开发者更好地使用 RT-Thread 文件系统。并给出了在正点原子 `STM32F429-apollo` 开发板上验证的代码示例。 4 | 5 | ## 本文的目的和结构 ## 6 | 7 | ### 本文的目的和背景 ### 8 | 9 | 第一次接触 RT-Thread 文件系统的开发者可能觉得 RT-Thread 文件系统过于复杂,不知道该从何入手。想要在项目中使用文件系统,却不知道该怎么做。产生这种印象的原因是对 RT-Thread DFS 框架没有足够的了解,如果理解了 DFS 框架,在使用 RT-Thread 文件系统时就可以得心应手了。 10 | 11 | 为了能让开发者清楚地理解 RT-Thread DFS 框架的概念,学会使用 RT-Thread 文件系统。本应用笔记将一步步深入介绍 RT-Thread DFS 框架的相关知识以及实现原理。通过演示 shell 命令和使用示例的方式来操作文件系统,让开发者能够学会 RT-Thread 文件系统的使用方法。 12 | 13 | ### 本文的结构 ### 14 | 15 | 本应用笔记将从以下三个方面来介绍 RT-Thread 文件系统: 16 | 17 | - RT-Thread DFS 框架 18 | - RT-Thread 文件系统的移植 19 | - RT-Thread 文件系统的使用 20 | 21 | ## 问题阐述 ## 22 | 23 | 本应用笔记将围绕下面几个问题来介绍RT-Thread 文件系统。 24 | 25 | - 如何移植各种类型的文件系统? 26 | - 如何对文件系统进行操作? 27 | - 如何在文件系统中对文件和文件夹进行操作? 28 | 29 | 想要解决这些问题,就要了解 RT-Thread DFS 框架。下面我们就通过 DFS 框架一步一步地将文件系统使用起来。 30 | 31 | ## 问题的解决 ## 32 | 33 | ### DFS 框架介绍 ### 34 | 35 | RT-Thread 的文件系统采用了三层结构,这种结构就是 RT-Thread DFS 框架。 36 | 37 | 下图为 **RT-Thread 文件系统结构图** : 38 | 39 | ![rt_fs_structure](assets/rt_fs_structure.png) 40 | 41 | DFS 框架的最顶层是一套面向嵌入式系统,专门优化过的设备虚拟文件系统 POSIX 文件接口,中间层是各种文件系统的实现,最底层是各类存储设备驱动。 42 | 43 | #### DFS 框架的来源 #### 44 | 45 | - RT-Thread 为了能够支持各种文件系统,设计了这样一个 DFS 框架,各个层次独立实现,提高了操作系统的可扩展性。使用 DFS 框架可以使得各种文件系统经过简单的修改即可匹配到这个框架上,降低了文件系统移植难度,让 开发者有更多的文件系统类型可供选择。 46 | 47 | #### DFS 框架各层次说明 #### 48 | ##### 顶层:POSIX 文件接口层 ##### 49 | 50 | - 这一层是给开发者使用的接口函数层,开发者使用这一层提供的 `POSIX` 文件接口进行文件的相关操作,不用关心文件系统是如何实现的,也不用关心数据是存放在哪个存储器中。 51 | 52 | ##### 中间层:文件系统实现层 ##### 53 | 54 | - 中间层是各种具体文件系统的实现,这里所说文件系统指各种不同类型的文件系统,比如 `ELM FatFS、RomFS、devfs、Yaffs2、Uffs2` 等。需要知道的是,不同的文件系统类型是独立于存储设备驱动而实现的。因此,想要正确地使用这些文件系统,需要把底层存储设备的驱动接口和文件系统对接起来。 55 | 56 | ##### 底层:存储设备驱动层 ##### 57 | 58 | - 这一层是存储设备驱动层,具体的功能是初始化存储设备并向上层提供存储设备的驱动接口。存储设备的类型可能是 `SPI Flash`,`SD卡` 等。 59 | 60 | ### 文件系统的移植 ### 61 | 62 | - 本次演示使用正点原子开发板 `STM32F429-Apollo` ,选择的文件系统类型是 `elm FatFS` 。由于 RT-Thread 自带了这个文件系统,所以移植工作较为简单,只需要通过 env 工具对系统进行合适的配置既可。其他 RT-Thread 支持的文件系统,移植过程也是类似的,只需要对系统进行合适的配置即可使用。 63 | 64 | ![stm32f429-apollo](assets/stm32f429-apollo.png) 65 | 66 | #### 准备工程 #### 67 | 68 | - 下载 [RT-Thread 源码](https://github.com/RT-Thread/rt-thread) 。 69 | 70 | - [env 工具](https://www.rt-thread.org/document/site/rtthread-development-guide/rtthread-tool-manual/env/env-user-manual/) 71 | 72 | #### 移植过程介绍 #### 73 | 74 | 文件系统的移植主要包括下面几个方面: 75 | 76 | - 开启/配置 DFS 框架 77 | - 开启/配置 指定的文件系统 78 | - 确保开发板上的存储设备驱动正常工作 79 | 80 | 通过 env 工具可以方便地开启文件系统,将所需的文件系统类型添加到工程中。 81 | 82 | 对存储设备进行功能测试,可以确保存储设备驱动是正常工作的。驱动程序的稳定工作是文件系统正常使用的基础。 83 | 84 | #### 文件系统的配置 #### 85 | 使用 env 工具进入 `rt-thread\bsp\stm32f429-apollo` 目录,在命令行中输入 `menuconfig` 命令进入配置界面。 86 | 87 | - 在 `menuconfig` 配置界面依次选择 `RT-Thread Components → Device virtual file system`,如下图所示: 88 | 89 | ![1528457058001](assets/1528457058001.png) 90 | 91 | - 下面介绍 DFS 的配置项: 92 | - Using device virtual file system : 使用设备虚拟文件系统,即 RT-Thread 文件系统。 93 | - Using working directory : 打开这个选项,在 `finsh/msh` 中就可以使用基于当前工作目录的相对路径。 94 | - The maximal number of mounted file system : 最大挂载文件系统的数量。 95 | - The maximal number of file system type : 最大支持文件系统类型的数量。 96 | - The maximal number of opened files : 打开文件的最大数量。 97 | - Enable elm-chan fatfs : 使用 elm-chan FatFs。 98 | - elm-chan's FatFs, Generic FAT Filesystem Module : elm-chan 文件系统的配置项。 99 | - Using devfs for device objects : 开启 devfs 文件系统。 100 | - Enable BSD socket operated by file system API : 使 BSD socket 可以使用文件系统的 API 来管理,比如读写操作和 select/poll 的 POSIX API 调用。 101 | - Enable ReadOnly file system on flash : 在 Flash 上使用只读文件系统。 102 | - Enable RAM file system : 使用 RAM 文件系统。 103 | - Enable UFFS file system: Ultra-low-cost Flash File System :使用 UFFS。 104 | - Enable JFFS2 file system : 使用 JFFS2 文件系统。 105 | - Using NFS v3 client file system :使用 NFS 文件系统。 106 | 107 | - 进入到 DFS 的配置界面,开启下图所示的选项,就可以将 `FatFS` 添加到系统中。如图所示: 108 | 109 | ![1528354745063](assets/1528354745063.png) 110 | 111 | - 这里需要注意的是还需要进入到 `elm-chan's FatFs, Generic FAT Filesystem Module` 选项中修改关于长文件名支持的选项,否则在后面使用文件系统的过程中,创建的文件或者文件夹的名称不能超过 8 个字符。修改方式如下图所示: 112 | 113 | ![1528355204158](assets/1528355204158.png) 114 | 115 | ![1528355291434](assets/1528355291434.png) 116 | 117 | - 因为要使用一些 C 库函数,所以需要打开 `libc` 功能: 118 | 119 | ![1528680175178](assets/1528680175178.png) 120 | 121 | - 保存选项后即可退出,此时 `elm FatFS` 已经添加到项目中 。 122 | 123 | #### 存储设备初始化 #### 124 | ##### 开启 SPI 设备驱动 ##### 125 | 126 | - DFS 框架的文件系统实现层需要存储设备驱动层提供驱动接口用于对接,本次使用的存储设备为 `SPI Flash`,底层设备初始化过程可以参考 [《SPI 设备应用笔记》](https://www.rt-thread.org/document/site/rtthread-application-note/driver/spi/an0004-rtthread-driver-spi/) 。 127 | 128 | - 重新打开 menuconfig 配置界面,在 `RT-Thread Components → Device Drivers` 界面中选中 `Using SPI Bus/Device device drivers` 以及 `Using Serial Flash Universal Driver` 选项,如下图所示: 129 | 130 | ![1528356393167](assets/1528356393167.png) 131 | 132 | - 为了方便地使用 shell 命令,我们在 `RT-Thread Components → Command shell` 选项中开启 `Using module shell` 选项,如下图所示: 133 | 134 | ![1528356861018](assets/1528356861018.png) 135 | 136 | - 保存选项并退出,在 env 中输入命令 `scons --target=mdk5 -s` 生成 mdk5 工程,编译并下载程序。 137 | 138 | ##### 检查存储设备驱动 ##### 139 | 140 | - 在 stm32f429-apollo 开发板上 ` SPI Flash` 挂在了 SPI5 总线上,对应的 `SPI Device` 的设备名为 `spi50`。在终端输入 `list_device` 命令可以看到名为 `spi50` 的设备类型为 `SPI Device`,就说明 SPI 设备添加成功。如果没有出现相应的设备,则需要检查驱动程序,查找错误。 141 | 142 | ![1528449652153](assets/1528449652153.png) 143 | 144 | - 为了确保该驱动工作正常,可以使用 `sf` 命令对该设备做 `benchmark` 测试。该功能由 `sfud` 组件提供,可以通过检查存储设备的读、写和擦除功能来判断存储设备的驱动程序是否正常。 如果像下图一样提示成功,所示则认为该驱动工作正常。如果无法通过测试,则需要检查驱动程序,使用逻辑分析仪对存储设备的接口波形进行分析。测试过程如下图: 145 | 146 | ![1528449677236](assets/1528449677236.png) 147 | 148 | ##### 创建存储设备 ##### 149 | - 由于只有块设备类型的设备才能和文件系统对接,所以需要根据 `SPI Device` 找到 `SPI Flash` 设备,并创建与其对应的 `Block Device`。 150 | 151 | - 这里需要使用到万能 SPI Flash 驱动库:[SFUD](https://github.com/armink/SFUD) ,RT-Thread 已经集成了该组件,在上面的配置过程中我们已经开启这个功能。此时只需要使用 SFUD 提供的 `rt_sfud_flash_probe` 函数即可。该函数将执行如下操作: 152 | 153 | - 根据名为 `spi50` 的 `SPI Device` 设备找到对应的 `Flash` 存储设备。 154 | 155 | - 初始化 `Flash` 设备。 156 | 157 | - 在 Flash 存储设备上创建名为 `W25Q256` 的 `Block Device`。 158 | 159 | - 如果开启了组件自动初始化功能,该函数会被自动执行,否则需要手动调用运行。 160 | 161 | ```c 162 | static int rt_hw_spi_flash_with_sfud_init(void) 163 | { 164 | if (RT_NULL == rt_sfud_flash_probe("W25Q256", "spi50")) 165 | { 166 | return RT_ERROR; 167 | }; 168 | 169 | return RT_EOK; 170 | } 171 | INIT_COMPONENT_EXPORT(rt_hw_spi_flash_with_sfud_init) 172 | ``` 173 | 174 | - 在终端输入 `list_device` 命令如果看到名为 `W25Q256` 的设备类型为 `Block Device`,这说明块设备已经创建成功,如果失败则需要对 `spi50` 设备进行检查。 175 | 176 | 如下图所示: 177 | 178 | ![1528362120705](assets/1528362120705.png) 179 | 180 | - 获得可以用于挂载的块类型设备,那么移植的工作就算完成了。 181 | 182 | ### 文件系统的使用 ### 183 | 184 | #### 文件系统的初始化 #### 185 | 186 | RT-Thread 文件系统初始化过程一般按以下流程来进行: 187 | 188 | 1. 初始化 DFS 框架 189 | 2. 初始化具体文件系统 190 | 3. 初始化存储设备 191 | 192 | 下面我们按照这样的顺序来逐步讲解文件系统的初始化过程: 193 | 194 | ##### DFS 框架的初始化 ##### 195 | 196 | DFS 框架的初始化主要是对内部数据结构以及资源的初始化。这一过程包括初始化文件系统必须的数据表,以及互斥锁。该功能由如下函数完成。如果开启了组件自动初始化功能,该函数会被自动执行,否则需要手动调用运行。 197 | 198 | ![1528451222822](assets/1528451222822.png) 199 | 200 | ##### 中间层文件系统的初始化 ##### 201 | 202 | 这一步的初始化主要是将 `elm FatFS` 的操作函数注册到 DFS 框架中。该功能由如下函数完成。如果开启了组件自动初始化功能,该函数会被自动执行,否则需要手动调用运行。 203 | 204 | ![1528451278720](assets/1528451278720.png) 205 | 206 | ##### 存储设备的初始化 ##### 207 | 208 | 存储设备的初始化可以参考 [《创建存储设备》](#_14)章节。 209 | 210 | #### 创建文件系统 #### 211 | 212 | - 第一次使用 `SPI Flash` 作为文件系统地存储设备时,如果我们直接重启开发板来挂载文件系统,就会看到 `spi flash mount to /spi failed!` 的提示。这是因为此时在 SPI Flash 中还没有创建相应类型的文件系统,这就用到了创建文件系统 shell 命令:`mkfs`。 213 | 214 | - `mkfs` 命令的功能是在指定的存储设备上创建指定类型的文件系统。使用格式为:`mkfs [-t type] device` 。第一次挂载文件系统前需要使用 `mkfs` 命令在存储设备上创建相应的文件系统,否则就会挂载失败。如果要在 `W25Q256` 设备上创建 `elm` 类型的文件系统,就可以使用 `mkfs -t elm W25Q256` 命令,使用方法如下图: 215 | 216 | ![1528416425397](assets/1528416425397.png) 217 | 218 | - 文件系统创建完成后需要重启设备。 219 | 220 | #### 文件系统的挂载 #### 221 | 222 | 文件系统的挂载指的是将文件系统和具体的存储设备关联起来,并挂载到某个挂载点,这个挂载点即为这个文件系统的根目录。在下面的示例中,我们将 `elm FatFS` 文件系统和名为 `W25Q256` 的存储设备关联起来,并且挂载到 `/spi` 文件夹中。(这里可以挂载到 `/spi` 文件夹的原因是 `stm32f429-apollo BSP` 的文件系统根目录已经挂载了 `RomFS`,并且已经创建了 `/spi` 文件夹。如果没有特殊情况,文件系统可以直接挂载到根目录 `/` 上。) 223 | 224 | - 挂载文件系统的操作由 `dfs_mount()` 函数完成,`dfs_mount()` 函数的参数分别为:块设备名、文件系统挂载点路径、挂载文件系统类型、读写标志位以及文件系统的私有数据,使用方法如下图所示: 225 | 226 | ![1528450972107](assets/1528450972107.png) 227 | 228 | - 经过了上面的创建文件系统操作,我们重启开发板(会自动重新执行挂载函数),就可以成功地挂载文件系统了。可以看到提示 `spi flash mount to /spi !` 。这时再次使用 `list_device` 命令可以看到 `W25Q256` 设备已经被挂载成功。如下图所示: 229 | 230 | ![1528417402476](assets/1528417402476.png) 231 | 232 | - 到这一步为止,文件系统已经初始化完成,接下来可以对文件和目录进行操作了。 233 | 234 | #### 文件与目录操作 shell 命令 #### 235 | 236 | 在这一小节介绍关于文件和目录操作常用的 shell 命令: 237 | 238 | - **ls** 239 | 功能:显示文件和目录的信息,示例如下图: 240 | ![1528419313880](assets/1528419313880.png) 241 | 242 | - **cd** 243 | 功能:切换到指定工作目录,示例如下图: 244 | ![1528419330733](assets/1528419330733.png) 245 | 246 | - **cp** 247 | 功能:copy 文件,示例如下图: 248 | ![1528419369526](assets/1528419369526.png) 249 | 250 | - **rm** 251 | 功能:删除文件或目录,示例如下图: 252 | ![1528419422313](assets/1528419422313.png) 253 | 254 | - **mv** 255 | 功能:将文件移动位置或者改名,示例如下图: 256 | ![1528419519371](assets/1528419519371.png) 257 | 258 | - **echo** 259 | 功能:将指定内容写入文件: 260 | ![1528460010565](assets/1528460010565.png) 261 | 262 | - **cat** 263 | 功能:展示文件的内容,示例如下图: 264 | ![1528419537678](assets/1528419537678.png) 265 | 266 | - **pwd** 267 | 功能:打印出当前目录地址,示例如下图: 268 | ![1528419554110](assets/1528419554110.png) 269 | 270 | - **mkdir** 271 | 功能:创建文件夹,示例如下图: 272 | ![1528419584942](assets/1528419584942.png) 273 | 274 | ### 文件操作示例 ### 275 | 276 | 本节以创建文件夹操作为例,介绍如何使用 RT-Thread 文件系统 Sample 来对文件系统进行操作。 277 | 278 | - 在 `menuconfig` 配置界面依次选择 `RT-Thread online packages → miscellaneous packages → filesystem sample options`,选中 `[filesystem] mkdir` 选项,如下图所示: 279 | 280 | ![1528420167135](assets/1528420167135.png) 281 | 282 | - 保存并退出后,使用 `pkgs --update` 命令更新软件包,然后使用 `scons --target=mdk5 -s` 命令重新生成工程。可以看到该 Sample 已经添加到工程中: 283 | 284 | ![1528421204197](assets/1528421204197.png) 285 | 286 | - 这里需要注意的是由于我们文件系统的根目录挂载了 `RomFS`,不可修改,所以我们不能直接在根目录创建文件夹。因此,我们需要对程序进行简单的修改,如下图所示: 287 | 288 | ![1528423169454](assets/1528423169454.png) 289 | 290 | - 重新编译后下载运行,在 msh 中可以使用 `mkdir_sample_init` 命令来创建 web 文件夹,效果如下图所示: 291 | 292 | ![1528423305271](assets/1528423305271.png) 293 | 294 | - 此时切换到 `/spi` 文件夹中可以看到 web 文件夹已经被创建。 295 | 296 | ![1528423429971](assets/1528423429971.png) 297 | 298 | - 文件系统提供的 Sample 还有 `openfile`、`readwrite`、`stat`、`rename`、`opendir`、`readdir` 、 299 | `tell_seek_dir`,大家可以用上面的方法来使用这些功能。 300 | 301 | ## 常见问题 ## 302 | 303 | 1.发现文件名或者文件夹名称显示不正常怎么办? 304 | 305 | - 检查是否开启了长文件名支持,可以参考本应用笔记[《文件系统的配置》](#_11)章节。 306 | 307 | 2.文件系统初始化失败怎么办? 308 | 309 | - 检查文件系统配置项目中的允许挂载的文件系统类型和数量是否充足。 310 | 311 | 3.创建文件系统 `mkfs` 命令失败怎么办? 312 | 313 | - 检查存储设备是否存在,如果存在检查设备驱动是否可以通过功能测试,如果不能通过,则检查驱动错误。 314 | - 检查 libc 功能是否开启,参见 [《文件系统的配置》](#_11)章节。 315 | 316 | 4.文件系统挂载失败怎么办? 317 | 318 | - 检查指定的挂载路径是否存在。文件系统可以直接挂载到根目录(“/”),但是如果想要挂载到其他路径上,如 (“/sdcard”)。需要确保(“/sdcard”)路径是存在的,否则需要先在根目录创建 `sdcard` 文件夹才能挂载成功。 319 | - 检查是否在存储设备上创建了文件系统,如果存储设备上没有文件系统,需要使用 `mkfs` 命令在存储器上创建文件系统。 320 | 321 | 5.SFUD 探测不到 Flash 所使用的具体型号怎么办? 322 | 323 | - 检查硬件引脚设置错误 324 | - SPI 设备是否已经注册 325 | - SPI 设备是否已经挂载到总线 326 | - 检查在 `RT-Thread Components → Device Drivers -> Using SPI Bus/Device device drivers -> Using Serial Flash Universal Driver` 菜单下的 `Using auto probe flash JEDEC SFDP parameter` 和 `Using defined supported flash chip information table` 配置项是否选中,如果没有选中那么需要开启这两个选项。配置图可参考 [《开启 SPI 设备驱动》](#spi) 章节。 327 | - 如果开启了上面的选项仍然无法识别存储设备,那么可以在 [SFUD](https://github.com/armink/SFUD) 项目中提出 issues。 328 | 329 | 6.elm FatFS 的最大扇区大小该如何设置? 330 | 331 | - 根据所使用的存储设备的不同,也会有些不一样,一般根据 Flash 设备的要求可以设置为 4K,也就是填写 4096。 332 | - 一般常见的 TF 卡和 SD 卡的扇区大小设置为 512。 333 | 334 | 7.存储设备的 `benchmark` 测试耗时过长是怎么回事? 335 | 336 | - 可对比 `system tick` 为 1000 时的 [benchmark 测试数据](https://github.com/armink/SFUD/blob/master/docs/zh/benchmark.txt) 和本次测试所需的时长,如果耗时差距过大,则可以认为测试工作运行不正常。 337 | 338 | - 检查系统 tick 的设置,因为一些延时操作会根据 tick 时间来决定,所以需要根据系统情况来设置合适的 `system tick` 值。如果系统的 `system tick` 值不低于 1000,则需要使用逻辑分析仪检查波形确定通信速率正常。 339 | 340 | 8.SPI Flash 实现 elmfat 文件系统,如何保留部分扇区不被文件系统使用? 341 | 342 | - 可以使用 RT-Thread 提供的 [partition](https://github.com/RT-Thread-packages/partition) 工具软件包为整个存储设备创建多个块设备,为创建的多个块设备分配不同的功能即可。 343 | 344 | 9.测试文件系统过程中程序卡住了怎么办? 345 | 346 | - 尝试使用调试器或者打印一些必要的调试信息,确定程序卡住的位置再提出问题。 347 | 348 | 10.如何一步步检查文件系统出现的问题? 349 | 350 | - 可以采用从底层到上层的方法来逐步排查问题。 351 | - 首先检查存储设备是否注册成功,功能是否正常。 352 | - 检查存储设备中是否创建了文件系统。 353 | - 检查指定文件系统类型是否注册到 DFS 框架,经常要检查允许的文件系统类型和数量是否足够。 354 | - 检查 DFS 是否初始化成功,这一步的初始化操作是纯软件的,因此出错的可能性不高。需要注意的是如果开启了组件自动初始化,就无需再次手动初始化。 355 | 356 | ## 参考 ## 357 | 358 | ### 本文所有相关的API ### 359 | 360 | #### API列表 #### 361 | | 文件系统初始化相关API | 位置 | 362 | | ---------------------- | ------------- | 363 | | dfs_init() | dfs.c | 364 | | elm_init() | dfs_elm.c | 365 | | dfs_mount() | dfs_fs.c | 366 | 367 | | shell命令相关API | 位置 | 368 | | ---------------------- | ------------- | 369 | | cmd_cat() | msh_cmd.c | 370 | | cmd_rm() | msh_cmd.c | 371 | | cmd_cd() | msh_cmd.c | 372 | | cmd_cp() | msh_cmd.c | 373 | | cmd_mv() | msh_cmd.c | 374 | | cmd_rm() | msh_cmd.c | 375 | | cmd_pwd() | msh_cmd.c | 376 | | cmd_mkdir() | msh_cmd.c | 377 | | cmd_mkfs() | msh_cmd.c | 378 | 379 | #### 核心API详解 #### 380 | ##### dfs_init() ##### 381 | **函数功能**: 382 | - 初始化 RT-Thread 文件系统 DFS 框架。 383 | 384 | **函数原型**: 385 | ```{.c} 386 | int dfs_init(void) 387 | ``` 388 | 389 | **函数返回**: 成功返回 RT_EOK。 390 | 391 | ##### elm_init() ##### 392 | **函数功能**: 393 | - 注册 FatFS 到 DFS 框架。 394 | 395 | **函数原型**: 396 | ```{.c} 397 | int elm_init(void) 398 | ``` 399 | 400 | **函数返回**: 成功返回 RT_EOK。 401 | 402 | ##### dfs_mount() ##### 403 | **函数功能**: 404 | - 在指定路径挂载特定类型的文件系统。 405 | 406 | **函数原型**: 407 | ```{.c} 408 | int dfs_mount(const char *device_name, 409 | const char *path, 410 | const char *filesystemtype, 411 | unsigned long rwflag, 412 | const void *data) 413 | ``` 414 | 415 | 参数 | 描述 416 | - | - 417 | device_name | 包含文件系统的块设备名 418 | path | 文件系统挂载点路径 419 | filesystemtype | 需要挂载的文件系统类型 420 | rwflag | 读写标志位 421 | data | 该文件系统的私有数据 422 | 423 | **函数返回**: 成功返回 RT_EOK,失败则返回 -1。 424 | -------------------------------------------------------------------------------- /Lectures/Lecture_1.2_文件系统数据结构解析.md: -------------------------------------------------------------------------------- 1 | # 文件系统数据结构解析 2 | ## 1. DFS 框架的组成内容 3 | 4 | DFS 框架内部主要包含三个表以及一个文件系统互斥锁用于解决资源冲突的问题: 5 | 6 | - `filesystem_operation_table`:这个表的每一个表项表示一个文件系统的对应的一套操作函数及相关属性。 7 | - `filesystem_table`:这个表记录已经挂载的文件系统,即每一个表项表示挂载的一个文件系统。 8 | - `fd_table`:这个表记录当前已经打开的文件描述符。 9 | - `fslock`:文件系统互斥锁,用于文件系统访问的资源冲突问题。 10 | 11 | 实现代码如下: 12 | ```c 13 | /* Global variables */ 14 | const struct dfs_filesystem_ops *filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX]; 15 | struct dfs_filesystem filesystem_table[DFS_FILESYSTEMS_MAX]; 16 | 17 | /* device filesystem lock */ 18 | static struct rt_mutex fslock; 19 | 20 | #ifdef DFS_USING_WORKDIR 21 | char working_directory[DFS_PATH_MAX] = {"/"}; 22 | #endif 23 | 24 | struct dfs_fd fd_table[DFS_FD_MAX]; 25 | ``` 26 | 27 | ### 1.1 文件系统操作表 28 | `filesystem_operation_table` 是记录各个文件系统操作接口的表,其各个表项的结构如下定义: 29 | 30 | ```c 31 | /* File system operations */ 32 | struct dfs_filesystem_ops 33 | { 34 | char *name; // 文件系统的名称 35 | uint32_t flags; /* flags for file system operations */ 36 | 37 | /* operations for file */ 38 | const struct dfs_file_ops *fops; 39 | 40 | /* mount and unmount file system */ 41 | int (*mount) (struct dfs_filesystem *fs, unsigned long rwflag, const void *data); 42 | int (*unmount) (struct dfs_filesystem *fs); 43 | 44 | /* make a file system */ 45 | int (*mkfs) (rt_device_t devid); 46 | int (*statfs) (struct dfs_filesystem *fs, struct statfs *buf); 47 | 48 | int (*unlink) (struct dfs_filesystem *fs, const char *pathname); 49 | int (*stat) (struct dfs_filesystem *fs, const char *filename, struct stat *buf); 50 | int (*rename) (struct dfs_filesystem *fs, const char *oldpath, const char *newpath); 51 | }; 52 | 53 | struct dfs_file_ops 54 | { 55 | int (*open) (struct dfs_fd *fd); 56 | int (*close) (struct dfs_fd *fd); 57 | int (*ioctl) (struct dfs_fd *fd, int cmd, void *args); 58 | int (*read) (struct dfs_fd *fd, void *buf, size_t count); 59 | int (*write) (struct dfs_fd *fd, const void *buf, size_t count); 60 | int (*flush) (struct dfs_fd *fd); 61 | int (*lseek) (struct dfs_fd *fd, off_t offset); 62 | int (*getdents) (struct dfs_fd *fd, struct dirent *dirp, uint32_t count); 63 | 64 | int (*poll) (struct dfs_fd *fd, struct rt_pollreq *req); 65 | }; 66 | 67 | ``` 68 | 69 | 由上面的文件操作定义可知,`filesystem_opration_table` 内每一个表项保存的是一个文件系统的一套操作函数,所有类型的操作系统,其操作函数的形式都是一致的。 70 | 71 | ### 1.2 文件系统挂载表 72 | `filesystem_table` 记录的是当前挂载的文件系统,其每一个表项表示的就是一个文件系统。 73 | 文件系统的定义如下: 74 | 75 | ```c 76 | /* Mounted file system */ 77 | struct dfs_filesystem 78 | { 79 | rt_device_t dev_id; /* Attached device */ 80 | 81 | char *path; /* File system mount point */ 82 | const struct dfs_filesystem_ops *ops; /* Operations for file system type */ 83 | 84 | void *data; /* Specific file system data */ 85 | }; 86 | ``` 87 | 88 | ### 1.3 文件描述符表 89 | `fd_table` 记录当前打开的文件集合,每一个表项表示一个打开的文件句柄,其结构如下定义: 90 | 91 | ```c 92 | /* file descriptor */ 93 | #define DFS_FD_MAGIC 0xfdfd 94 | struct dfs_fd 95 | { 96 | uint16_t magic; /* file descriptor magic number */ 97 | uint16_t type; /* Type (regular or socket) */ 98 | 99 | char *path; /* Name (below mount point) */ 100 | int ref_count; /* Descriptor reference count */ 101 | 102 | const struct dfs_file_ops *fops; 103 | 104 | uint32_t flags; /* Descriptor flags */ 105 | size_t size; /* Size in bytes */ 106 | off_t pos; /* Current file position */ 107 | 108 | void *data; /* Specific file system data */ 109 | }; 110 | 111 | struct dfs_file_ops 112 | { 113 | int (*open) (struct dfs_fd *fd); 114 | int (*close) (struct dfs_fd *fd); 115 | int (*ioctl) (struct dfs_fd *fd, int cmd, void *args); 116 | int (*read) (struct dfs_fd *fd, void *buf, size_t count); 117 | int (*write) (struct dfs_fd *fd, const void *buf, size_t count); 118 | int (*flush) (struct dfs_fd *fd); 119 | int (*lseek) (struct dfs_fd *fd, off_t offset); 120 | int (*getdents) (struct dfs_fd *fd, struct dirent *dirp, uint32_t count); 121 | 122 | int (*poll) (struct dfs_fd *fd, struct rt_pollreq *req); 123 | }; 124 | ``` 125 | 126 | ### 1.4 文件系统互斥锁 127 | 128 | `fslock` 就是一个静态的互斥锁,实现方式如下: 129 | ```c 130 | /* device filesystem lock */ 131 | static struct rt_mutex fslock; 132 | 133 | /** 134 | * Mutual exclusion (mutex) structure 135 | */ 136 | struct rt_mutex 137 | { 138 | struct rt_ipc_object parent; /**< inherit from ipc_object */ 139 | 140 | rt_uint16_t value; /**< value of mutex */ 141 | 142 | rt_uint8_t original_priority; /**< priority of last thread hold the mutex */ 143 | rt_uint8_t hold; /**< numbers of thread hold the mutex */ 144 | 145 | struct rt_thread *owner; /**< current owner of mutex */ 146 | }; 147 | typedef struct rt_mutex *rt_mutex_t; 148 | ``` 149 | 150 | ### 1.5 小结 151 | 152 | - 由上面几个小节的内容可知,DFS 框架主要由三张表组成,而 dfs.c, dfs_fs.c, dfs_file.c 这三个源文件主要是围绕着三张表来进行操作的。 153 | - 主要的操作是文件系统的添加、删除和查找等。 154 | - 对具体文件的操作并不在 DFS 框架内实现,而是由中间层的具体文件系统类型来实现。 155 | - 中间层的文件系统向文件系统操作表中注册该文件系统的操作函数。 156 | - 向文件系统挂载表中添加需要挂载的文件系统信息。 157 | - 有了文件系统挂载表、文件系统操作表、文件描述符表这三张表,系统就可以找到对特定文件的操作函数了。 158 | 159 | 160 | 161 | 文件系统挂载函数: 162 | 163 | ```c 164 | /** 165 | * this function will mount a file system on a specified path. 166 | * 167 | * @param device_name the name of device which includes a file system. 168 | * @param path the path to mount a file system 169 | * @param filesystemtype the file system type 170 | * @param rwflag the read/write etc. flag. 171 | * @param data the private data(parameter) for this file system. 172 | * 173 | * @return 0 on successful or -1 on failed. 174 | */ 175 | int dfs_mount(const char *device_name, 176 | const char *path, 177 | const char *filesystemtype, 178 | unsigned long rwflag, 179 | const void *data) 180 | { 181 | const struct dfs_filesystem_ops **ops; 182 | struct dfs_filesystem *iter; 183 | struct dfs_filesystem *fs = NULL; 184 | char *fullpath = NULL; 185 | rt_device_t dev_id; 186 | 187 | /* open specific device */ //打开一个特定的设备用来挂载 188 | if (device_name == NULL) 189 | { 190 | /* which is a non-device filesystem mount */ 191 | dev_id = NULL; 192 | } 193 | else if ((dev_id = rt_device_find(device_name)) == NULL) //如果找不到指定的设备就返回错误信息 194 | { 195 | /* no this device */ 196 | rt_set_errno(-ENODEV); 197 | return -1; 198 | } 199 | 200 | /* find out the specific filesystem */ 201 | dfs_lock(); // 查找是否注册了指定的文件系统类型 202 | 203 | for (ops = &filesystem_operation_table[0]; 204 | ops < &filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX]; ops++) 205 | if ((*ops != NULL) && (strcmp((*ops)->name, filesystemtype) == 0)) 206 | break; 207 | 208 | dfs_unlock(); 209 | 210 | if (ops == &filesystem_operation_table[DFS_FILESYSTEM_TYPES_MAX]) // 如果相等则为找到最后也没找到 211 | { 212 | /* can't find filesystem */ 213 | rt_set_errno(-ENODEV); // 如果没有注册特定的文件系统类型,则返回错误 214 | return -1; 215 | } 216 | 217 | /* check if there is mount implementation */ // 如果该文件系统没有提供操作函数,或者挂载函数为空则返回错误 218 | if ((*ops == NULL) || ((*ops)->mount == NULL)) 219 | { 220 | rt_set_errno(-ENOSYS); 221 | return -1; 222 | } 223 | 224 | /* make full path for special file */ 225 | fullpath = dfs_normalize_path(NULL, path); // 获得需要挂载的绝对路径 226 | if (fullpath == NULL) /* not an abstract path */ 227 | { 228 | rt_set_errno(-ENOTDIR); 229 | return -1; 230 | } 231 | 232 | /* Check if the path exists or not, raw APIs call, fixme */ 233 | if ((strcmp(fullpath, "/") != 0) && (strcmp(fullpath, "/dev") != 0)) // 如果地址不是根目录也不是 /dev 目录, 234 | { // 那么尝试打开指定的路径,如果没有这个路径则报错 235 | struct dfs_fd fd; 236 | 237 | if (dfs_file_open(&fd, fullpath, O_RDONLY | O_DIRECTORY) < 0) 238 | { 239 | rt_free(fullpath); 240 | rt_set_errno(-ENOTDIR); 241 | 242 | return -1; 243 | } 244 | dfs_file_close(&fd); 245 | } 246 | 247 | /* check whether the file system mounted or not in the filesystem table 248 | * if it is unmounted yet, find out an empty entry */ // 查看这个文件系统是否已经被挂载了, 249 | dfs_lock(); // 如果还没有被挂载,那么找到一个挂载点 250 | 251 | for (iter = &filesystem_table[0]; 252 | iter < &filesystem_table[DFS_FILESYSTEMS_MAX]; iter++) 253 | { 254 | /* check if it is an empty filesystem table entry? if it is, save fs */ 255 | if (iter->ops == NULL) // 查看是否有空的挂载点,如果有那么就将这个挂载点的指针赋值给 fs 256 | (fs == NULL) ? (fs = iter) : 0; 257 | /* check if the PATH is mounted */ 258 | else if (strcmp(iter->path, path) == 0) // 没有空的可挂载点,查看想要挂载的路径是否已经被挂载了其他类型的文件系统 259 | { 260 | rt_set_errno(-EINVAL); 261 | goto err1; 262 | } 263 | } 264 | // 走到这里如果有位置挂载,那么两个条件都不会成立。只会给 FS 赋值最小的那个挂载点 265 | if ((fs == NULL) && (iter == &filesystem_table[DFS_FILESYSTEMS_MAX])) 266 | { 267 | rt_set_errno(-ENOSPC); // 如果没有空的挂载点,返回没有空位了,这里常出现错误,需要添加一些提示信息。 268 | goto err1; 269 | } 270 | 271 | /* register file system */ // 开始注册需要挂载的文件系统信息。 272 | fs->path = fullpath; // 文件系统的挂载地址 273 | fs->ops = *ops; // 文件系统所需要的操作函数 274 | fs->dev_id = dev_id; // 挂载设备的设备 ID 275 | /* release filesystem_table lock */ 276 | dfs_unlock(); 277 | 278 | /* open device, but do not check the status of device */ 279 | if (dev_id != NULL) // 尝试打开需要挂载的设备,如果打不开则清空上面初始化的内容返回错误 280 | { 281 | if (rt_device_open(fs->dev_id, 282 | RT_DEVICE_OFLAG_RDWR) != RT_EOK) 283 | { 284 | /* The underlaying device has error, clear the entry. */ 285 | dfs_lock(); 286 | memset(fs, 0, sizeof(struct dfs_filesystem)); 287 | 288 | goto err1; 289 | } 290 | } 291 | 292 | /* call mount of this filesystem */ 293 | if ((*ops)->mount(fs, rwflag, data) < 0) // s挂载函数,传入挂载路径,操作集合指针,设备 ID,进行底层操作 294 | { 295 | /* close device */ 296 | if (dev_id != NULL) 297 | rt_device_close(fs->dev_id); 298 | 299 | /* mount failed */ 300 | dfs_lock(); 301 | /* clear filesystem table entry */ 302 | memset(fs, 0, sizeof(struct dfs_filesystem)); 303 | 304 | goto err1; 305 | } 306 | 307 | return 0; // 如果没有错误则返回 0 308 | 309 | err1: 310 | dfs_unlock(); 311 | rt_free(fullpath); 312 | 313 | return -1; 314 | } 315 | ``` 316 | 317 | -------------------------------------------------------------------------------- /Lectures/Lecture_1.3_DFS文件描述符管理.md: -------------------------------------------------------------------------------- 1 | # DFS 的文件描述符(FD)管理 2 | ## 1. 文件描述符简介 3 | 4 | 在 RT-Thread 文件系统中的文件描述符称为 `dfs_fd` ,它作为一种数据结构存放在文件描述符表中。可以通过修改 `dfs_fd` 的类型将其编程某中种特定类型的文件描述符,如普通文件描述符或者网络文件描述符。 5 | 6 | `dfs_fd` 是由一个结构体数组来存储的,其定义在 `dfs.c` 文件中: 7 | ```c 8 | struct dfs_fd fd_table[DFS_FD_MAX]; 9 | ``` 10 | 这里的 DFS_FD_MAX 参数最终由 rtconfig.h 中的宏来定义。意思就是系统中允许存在的文件描述符数量。任何类型的文件打开或者使用,都要消耗这个 DFS_FD 描述符资源。所以应该根据情况写的稍大一些。 11 | ```c 12 | #define DFS_FD_MAX 64 13 | ``` 14 | 15 | 这里讨论 fd_get() 函数和 fd_put() 函数的作用。 16 | 17 | 这个函数将根据文件返回一个文件描述符结构体: 18 | 19 | ```c 20 | struct dfs_fd *fd_get(int fd) 21 | { 22 | struct dfs_fd *d; 23 | 24 | fd = fd - DFS_FD_OFFSET; //减去标准输入输出的偏移量 25 | if (fd < 0 || fd >= DFS_FD_MAX) //如果比0小则不可用,如果比fd最大值还大,也不允许,所以返回NULL 26 | return NULL; 27 | 28 | dfs_lock(); //获得互斥锁 29 | d = &fd_table[fd]; //从 fd_table 中获得 fd 文件描述符的指针 30 | 31 | /* check dfs_fd valid or not */ 32 | if (d->magic != DFS_FD_MAGIC) //检查文件描述符魔数,如果错误则不是文件描述符,返回NULL 33 | { 34 | dfs_unlock(); 35 | return NULL; 36 | } 37 | 38 | /* increase the reference count */ 39 | d->ref_count ++; //将改文件的调用次数+1 40 | dfs_unlock(); //释放互斥锁 41 | 42 | return d; //返回文件描述符的指针 43 | } 44 | 45 | void fd_put(struct dfs_fd *fd) 46 | { 47 | RT_ASSERT(fd != NULL); //检测传入的描述符结构体指针是否为空 48 | 49 | dfs_lock(); 50 | fd->ref_count --; //减少其调用次数 51 | 52 | /* clear this fd entry */ 53 | if (fd->ref_count == 0) //如果这个文件的调用次数为0,那么在table中清空这个描述符的信息,这里相当于使释放这个描述符了 54 | { 55 | memset(fd, 0, sizeof(struct dfs_fd)); 56 | } 57 | dfs_unlock(); 58 | } 59 | 60 | ``` 61 | 62 | - 这里的 `fd_get` 和 `fd_put` 使用了一种计数的惯用手法,在面向对象的系统中,对象之间的协作关系非常复杂,所谓的协作其实就是调用对象的函数或者向对象发送消息,但不管调用函数还是发送消息,总是要通过某种方式知道目标对象才行。而最常见的做法就是保存目标对象的引用(指针)。 63 | 64 | - 对象被别人引用了,但是自己可能并不知道。此时如果对象被销毁,对该对象的引用就变成了野指针,系统随时可能因此而崩溃。 65 | 66 | - 此时我们可以采用对象引用计数,对象有一个引用计数器,不管谁要引用这个对象,就要把对象的引用计数器+1,如果不再引用了,就把对象的引用计数器-1.当对象的引用计数器被减为0时,说明没有其他对象引用它,该对象就可以安全地销毁了。这样,对象地生命周期就得到了有效地管理。 67 | 68 | 69 | ## 2. 网络文件描述符 70 | ### 2.1 网络文件描述符的定义 71 | 72 | socket 的存储数据结构也是一个结构体数组,在 sockets.c 中定义。 73 | ```c 74 | /** The global array of available sockets */ 75 | static struct lwip_sock sockets[NUM_SOCKETS]; 76 | ``` 77 | 这里的 NUM_SOCKETS 参数最终由 rtconfig.h 中的宏来定义。 78 | ```c 79 | #define RT_MEMP_NUM_NETCONN 32 80 | ``` 81 | 意思是系统中最大允许的 socket 连接的数量,这个数值是不允许比上文提到的文件描述符 `DFS_FD_MAX` 大的,因为 socket 套接字描述符也是 DFS_FD 描述符的一种,使用 Posix 接口来申请 socket 时,首先要申请 DFS_FD 的空间,如果 `RT_MEMP_NUM_NETCONN` 的值大于 DFS_FD 的最大值,那么当申请更多的 socket 的时候,必然会出现失败的情况。 82 | 83 | ```c 84 | int dfs_net_getsocket(int fd) 85 | { 86 | int sock; 87 | struct dfs_fd *_dfs_fd; 88 | 89 | _dfs_fd = fd_get(fd); //从fd table 返回 fd 结构体 90 | if (_dfs_fd == NULL) return -1; 91 | 92 | if (_dfs_fd->type != FT_SOCKET) sock = -1; 93 | else sock = (int)_dfs_fd->data; 94 | 95 | fd_put(_dfs_fd); /* put this dfs fd */ 96 | return sock; 97 | } 98 | 99 | int closesocket(int s) 100 | { 101 | int sock = dfs_net_getsocket(s); //这里相当于是从文件描述fd获得socket套接字 102 | struct dfs_fd *d; 103 | 104 | d = fd_get(s); 105 | 106 | /* socket has been closed, delete it from file system fd */ 107 | fd_put(d); //先从 table 里面将这个文件描述符删除 这一步是减少其调用次数 108 | fd_put(d); //这一步是清空 table 里面的结构体,因为前面dfs_net_getsocket 里面给调用次数+1,fd_get又+1,所以这里要put两次 109 | 110 | return lwip_close(sock); //再关闭这个socket链接 111 | } 112 | ``` 113 | 根据以上代码可以看出关闭SOCKET的时候,先是将文件描述符从table中删除,然后再调用lwip提供的接口关闭 socket 连接。 114 | list_fd 函数会遍历 fd_table[],然后将已经使用的 DFS_FD 信息打印出来,包括 DFS_FD 号码,类型和引用次数。这里打印出的 DFS_FD 号码指的是这个 DFS_FD 在 table 里面的索引号。 115 | 116 | ### 2.2 网络文件描述符 117 | 118 | ### 2.2.1 申请文件描述符 119 | 120 | 那么现在问题来了,再建立一个socket连接的时候,获取文件描述符fd又是什么流程呢。 121 | 122 | 在 POSIX 的 socket 函数中,调用了 fd_new() 函数。 123 | 在 fd_new 函数中: 124 | ```c 125 | int fd_new(void) 126 | { 127 | struct dfs_fd *d; 128 | int idx; 129 | 130 | /* lock filesystem */ 131 | dfs_lock(); //锁住文件系统 132 | 133 | /* find an empty fd entry */ //在fd_talbe中找到一个空的文件描述符接入点,条件是某个描述符的接入点的调用次数为0 134 | for (idx = 0; idx < DFS_FD_MAX && fd_table[idx].ref_count > 0; idx++); 135 | 136 | /* can't find an empty fd entry */ 137 | if (idx == DFS_FD_MAX) //直到最后也没有找到,那么到最后返回一个负数 138 | { 139 | idx = -(1 + DFS_FD_OFFSET); 140 | goto __result; 141 | } 142 | 143 | d = &(fd_table[idx]); //如果找到了一个空的位置那么将这个位置的指针赋给 d 144 | d->ref_count = 1; //更新调用次数为1 145 | d->magic = DFS_FD_MAGIC; //写入魔数 146 | 147 | __result: 148 | dfs_unlock(); //解锁文件系统 149 | return idx + DFS_FD_OFFSET; //返回一个index + fd 偏移值的文件 fd 150 | } 151 | ``` 152 | 153 | ### 2.2.2 申请网络文件描述符 154 | 155 | ```c 156 | int socket(int domain, int type, int protocol) 157 | { 158 | /* create a BSD socket */ 159 | int fd; 160 | int sock; 161 | struct dfs_fd *d; 162 | struct lwip_sock *lwsock; 163 | 164 | /* allocate a fd */ 165 | fd = fd_new(); //这里就获取了一个文件描述符 fd 166 | if (fd < 0) 167 | { 168 | rt_set_errno(-ENOMEM); //如果获取失败,那么返回 -1 169 | 170 | return -1; 171 | } 172 | d = fd_get(fd); //根据 fd 得到文件描述符结构体的指针 173 | 174 | /* create socket in lwip and then put it to the dfs_fd */ 175 | sock = lwip_socket(domain, type, protocol); //通过 lwip 接口获得一个socket描述符 176 | if (sock >= 0) //如果获得成功,那么将相关信息存放到文件描述符 fd 中 177 | { 178 | /* this is a socket fd */ 179 | d->type = FT_SOCKET; 180 | d->path = NULL; 181 | 182 | d->fops = dfs_net_get_fops(); 183 | 184 | d->flags = O_RDWR; /* set flags as read and write */ 185 | d->size = 0; 186 | d->pos = 0; 187 | 188 | /* set socket to the data of dfs_fd */ 189 | d->data = (void *) sock; 190 | 191 | lwsock = lwip_tryget_socket(sock); 192 | rt_list_init(&(lwsock->wait_head)); 193 | lwsock->conn->callback = event_callback; 194 | } 195 | 196 | /* release the ref-count of fd */ 197 | fd_put(d); 198 | 199 | return fd; //将文件描述符 fd 返回 200 | } 201 | ``` -------------------------------------------------------------------------------- /Lectures/assets/1528354745063.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528354745063.png -------------------------------------------------------------------------------- /Lectures/assets/1528355204158.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528355204158.png -------------------------------------------------------------------------------- /Lectures/assets/1528355291434.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528355291434.png -------------------------------------------------------------------------------- /Lectures/assets/1528356393167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528356393167.png -------------------------------------------------------------------------------- /Lectures/assets/1528356861018.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528356861018.png -------------------------------------------------------------------------------- /Lectures/assets/1528362120705.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528362120705.png -------------------------------------------------------------------------------- /Lectures/assets/1528416425397.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528416425397.png -------------------------------------------------------------------------------- /Lectures/assets/1528417402476.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528417402476.png -------------------------------------------------------------------------------- /Lectures/assets/1528419313880.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528419313880.png -------------------------------------------------------------------------------- /Lectures/assets/1528419330733.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528419330733.png -------------------------------------------------------------------------------- /Lectures/assets/1528419369526.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528419369526.png -------------------------------------------------------------------------------- /Lectures/assets/1528419422313.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528419422313.png -------------------------------------------------------------------------------- /Lectures/assets/1528419519371.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528419519371.png -------------------------------------------------------------------------------- /Lectures/assets/1528419537678.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528419537678.png -------------------------------------------------------------------------------- /Lectures/assets/1528419554110.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528419554110.png -------------------------------------------------------------------------------- /Lectures/assets/1528419584942.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528419584942.png -------------------------------------------------------------------------------- /Lectures/assets/1528420167135.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528420167135.png -------------------------------------------------------------------------------- /Lectures/assets/1528421204197.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528421204197.png -------------------------------------------------------------------------------- /Lectures/assets/1528423169454.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528423169454.png -------------------------------------------------------------------------------- /Lectures/assets/1528423305271.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528423305271.png -------------------------------------------------------------------------------- /Lectures/assets/1528423429971.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528423429971.png -------------------------------------------------------------------------------- /Lectures/assets/1528449652153.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528449652153.png -------------------------------------------------------------------------------- /Lectures/assets/1528449677236.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528449677236.png -------------------------------------------------------------------------------- /Lectures/assets/1528450972107.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528450972107.png -------------------------------------------------------------------------------- /Lectures/assets/1528451222822.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528451222822.png -------------------------------------------------------------------------------- /Lectures/assets/1528451278720.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528451278720.png -------------------------------------------------------------------------------- /Lectures/assets/1528457058001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528457058001.png -------------------------------------------------------------------------------- /Lectures/assets/1528459997690.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528459997690.png -------------------------------------------------------------------------------- /Lectures/assets/1528460010565.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528460010565.png -------------------------------------------------------------------------------- /Lectures/assets/1528680175178.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/1528680175178.png -------------------------------------------------------------------------------- /Lectures/assets/rt_fs_structure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/rt_fs_structure.png -------------------------------------------------------------------------------- /Lectures/assets/stm32f429-apollo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SummerGift/rtthread_deep_analysis/cd5eaf8fb9a4bdbecbe2a2d7e883df6a3601766f/Lectures/assets/stm32f429-apollo.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 深度解析 RT-Thread 操作系统 2 | 3 | ## 简介 4 | 5 | - 这个仓库的内容包括 RT-Thread 操作系统功能实现的深度解析。 6 | 7 | - 从实现的功能,数据结构,设计方法的角度来讲解 RT-Thread 操作系统。 8 | 9 | ___ 10 | 11 | ## 内容 12 | 13 | ### RT-Thread 内核对象模型 14 | 15 | ### RT-Thread 文件系统 16 | - [x] [Lecture 1 - RT-Thread 文件系统应用笔记](./Lectures/Lecture_1.1_RT-Thread_文件系统应用笔记.md) 17 | - [x] [Lecture 2 - 文件系统数据结构解析](./Lectures/Lecture_1.2_文件系统数据结构解析.md) 18 | - [x] [Lecture 3 - DFS 文件描述符(FD)管理](./Lectures/Lecture_1.3_DFS文件描述符管理.md) 19 | 20 | 21 | --------------------------------------------------------------------------------