RT-Thread DFS 组件的主要功能特点

网友投稿 385 2022-11-23

RT-Thread DFS 组件的主要功能特点

1.1 文件系统引入

在早期的嵌入式系统中,需要存储的数据比较少,数据类型也比较单一,往往使用直接在存储设备中的指定地址写入数据的方法来存储数据。然而随着嵌入式设备功能的发展,需要存储的数据越来越多,也越来越复杂,这时仍使用旧方法来存储并管理数据就变得非常繁琐困难。因此我们需要新的数据管理方式来简化存储数据的组织形式,这就是文件系统的由来。

1.2 虚拟文件系统引入

2 DFS 简介

DFS( Device File System)是一种抽象的文件机制,RT-Thread中对文件系统的相关操作实际上都是通过操作DFS实现,也就是说DFS是对各种文件系统的抽象。DFS使的其他部分无须关心不同文件系统之间的差异,使得RT-Thread可以支持多种类型的文件系统。

3 DFS 框架

RT-Thread DFS 组件的主要功能特点有:

DFS 的层次架构如下图所示,主要分为 POSIX 接口层、虚拟文件系统层和设备抽象层。

POSIX 接口层:

虚拟文件系统层:

用户可以将具体的文件系统注册到 DFS 中,如 FatFS、RomFS、DevFS 等。

设备抽象层:设备抽象层将物理设备如 SD Card、SPI Flash、Nand Flash,抽象成符合文件系统能够访问的设备,例如 FAT 文件系统要求存储设备必须是块设备类型。

不同文件系统类型是独立于存储设备驱动而实现的,因此把底层存储设备的驱动接口和文件系统对接起来之后,才可以正确地使用文件系统功能。

4 DFS 数据结构

文件系统操作表:

文件系统表:

1struct dfs_filesystem filesystem_table[DFS_FILESYSTEMS_MAX];

文件描述符:

5 虚拟文件系统使用步骤

初始化 DFS 组件。

注册具体类型的文件系统。

挂载文件系统

当文件系统不再使用,可以将它卸载。

5.1 初始化 DFS 组件

dfs_init() 函数会初始化 DFS 所需的相关资源,创建一些关键的数据结构, 有了这些数据结构,DFS 便能在系统中找到特定的文件系统,并获得对特定存储设备内文件的操作方法。

dfs_init()加入了自动初始化机制,在系统上电后会自动运行dfs_init()。

1INIT_PREV_EXPORT(dfs_init);

实例化DFS 组件相关的数据结构

1struct dfs_filesystem filesystem_table[DFS_FILESYSTEMS_MAX]

1static struct dfs_fdtable _fdtab

创建当前目录表

1char working_directory[DFS_PATH_MAX] = {“/”}

初始化 DFS:

清除文件系统操作表

清除文件系统表

清除文件描述符表

初始化互斥量

设置当前工作目录为“/”

5.2 注册具体类型的文件系统

在 DFS 组件初始化之后,还需要初始化使用的具体类型的文件系统,也就是将具体类型的文件系统注册到 DFS 中。注册文件系统的接口如下所示:

1int dfs_register(const struct dfs_filesystem_ops *ops);

检查这个文件系统是否已经存在于文件系统操作表的目录中

在文件系统操作表中找出一个空的文件类型条目

将这个文件系统的数据结构地址赋值给空的文件系统操作表目录

5.3 挂载文件系统

在挂载文件系统之前,如果是用作存储设备,还需要先存储设备注册为块设备,然后格式化成对应的文件系统后,才能挂载。

在 RT-Thread 中,挂载是指将一个存储设备挂接到一个已存在的路径上。我们要访问存储设备中的文件,必须将文件所在的分区挂载到一个已存在的路径上,然后通过这个路径来访问存储设备。挂载文件系统的接口如下所示:

1int dfs_mount(const char *device_name,

2 const char *path,

3 const char *filesystemtype,

4 unsigned long rwflag,

5 const void *data);

在文件系统操作表中找出特定的文件系统

为特殊文件系统建立完整路径

检查路径是否存在

检查文件系统是否挂载在文件系统表中

检查文件系统表是否有空余,如果有,把空余地址指向给此文件系统

注册文件系统

调用此文件系统的挂载接口

5.4 卸载文件系统

当某个文件系统不需要再使用了,那么可以将它卸载掉。卸载文件系统的接口如下所示:

1int dfs_unmount(const char *specialfile);

检查路径是否存在

在文件系统表中找到此文件系统

清除文件系统表的这个条目内容

调用此文件系统的卸载接口

6 文件系统实例演示

6.1 devfs文件系统

6.1.1 简介

devfs是设备文件系统,设备文件系统是用来把一切设备都抽象为像文件那样操作(如可读,可写)。devfs默认挂载在“/dev”路径下。但是会发现在根目录下使用shell 的ls命令不能看到“/dev”目录, 但是cd “/dev” 能进入dev 目录 ,并且进入dev目录后也能显示dev下的设备。因为根目录“/“下并没有创建任何文件夹,所以在根目录下ls命令自然看不到“/dev”目录。由于挂载文件系统需要挂载在一个已存在的路径上,devfs属于特殊文件系统,DFS为devfs设备文件系统注册时设置了专门的“/dev”路径以供设备文件系统挂载。

2 if ((strcmp(fullpath, ”/“) != 0) && (strcmp(fullpath, ”/dev“) != 0))

3 {

4 struct dfs_fd fd;

5

6 if (dfs_file_open(&fd, fullpath, O_RDONLY | O_DIRECTORY) 《 0)

7 {

8 rt_free(fullpath);

9 rt_set_errno(-ENOTDIR);

10

11 return -1;

12 }

13 dfs_file_close(&fd);

14 }

6.1.2 注册devfs文件系统

如果开启了DFS,devfs设备文件系统会在dfs_init()里自动初始化和挂载。

1#ifdef RT_USING_DFS_DEVFS

2 {

3 extern int devfs_init(void);

4

5 /* if enable devfs, initialize and mount it as soon as possible */

6 devfs_init();

7

8 dfs_mount(NULL, ”/dev“, ”devfs“, 0, 0);

9 }

10#endif

设置devfs文件系统的数据结构:_device_fs

1static const struct dfs_filesystem_ops _device_fs =

2{

3 ”devfs“,

4 DFS_FS_FLAG_DEFAULT,

5 &_device_fops,

6

7 dfs_device_fs_mount,

8 RT_NULL,

9 RT_NULL,

10 RT_NULL,

11

12 RT_NULL,

13 dfs_device_fs_stat,

14 RT_NULL,

15};

将devfs文件系统的数据结构挂载到文件系统操作表里

1int devfs_init(void)

2{

3 /* register rom file system */

4 dfs_register(&_device_fs);

5

6 return 0;

7}

检查devfs文件系统是否已经存在于文件系统操作表的目录中

在文件系统操作表中找出一个空的文件类型条目

将devfs文件系统的数据结构_device_fs地址赋值给空的文件系统操作表目录

文件系统操作表filesystem_operation_table的第一个目录:

6.1.2 挂载devfs文件系统

1dfs_mount(NULL, ”/dev“, ”devfs“, 0, 0)

在文件系统操作表中找出devfs文件系统

跳过检查”/dev“路径是否存在

检查devfs文件系统是否已经挂载在文件系统表中

检查文件系统表是否有空余,如果有,把空余地址赋值给devfs文件系统

注册文件系统

调用devfs文件系统的挂载接口

文件系统表filesystem_table的第一个目录:

在根目录下使用shell 的cd命令切换到/dev目录,然后使用ls命令:

6.2 RomFS文件系统

6.2.1 简介

RomFS是在嵌入式设备上常用的一种文件系统,具备体积小,可靠性高,读取速度快等优点,常用来作为系统初始文件系统。但也具有其局限性,RomFS是一种只读文件系统。

6.2.2 注册devfs文件系统

把RomFS当作初始文件系统rootfs挂载在根目录,在RomFS里创建几个目录,用于其他文件系统的挂载点。

更改… omfs.c文件,添加mnt文件夹和user文件夹。

2#include 《dfs_romfs.h》

3

4static const struct romfs_dirent _romfs_root[] = {

5 {ROMFS_DIRENT_DIR, ”mnt“, RT_NULL, 0},

6 {ROMFS_DIRENT_DIR, ”user“, RT_NULL, 0}

7};

8

9const struct romfs_dirent romfs_root = {

10 ROMFS_DIRENT_DIR, ”/“, (rt_uint8_t *)_romfs_root, sizeof(_romfs_root)/sizeof(_romfs_root[0])

11};

设置romfs文件系统的数据结构:_romfs

1static const struct dfs_filesystem_ops _romfs =

2{

3 ”rom“,

4 DFS_FS_FLAG_DEFAULT,

5 &_rom_fops,

6

7 dfs_romfs_mount,

8 dfs_romfs_unmount,

9 NULL,

10 NULL,

11

12 NULL,

13 dfs_romfs_stat,

14 NULL,

15};

将romfs文件系统的数据结构挂载到文件系统操作表里

1int dfs_romfs_init(void)

2{

3 /* register rom file system */

4 dfs_register(&_romfs);

5 return 0;

6}

7INIT_COMPONENT_EXPORT(dfs_romfs_init);//自动初始化

检查romfs文件系统是否已经存在于文件系统操作表的目录中

在文件系统操作表中找出一个空的文件类型条目

将romfs文件系统的数据结构_romfs地址赋值给空的文件系统操作表目录

文件系统操作表filesystem_operation_table的第二个目录:

6.2.3 挂载romfs文件系统

1int mnt_init(void)

2{

3 if(dfs_mount (RT_NULL,”/“,”rom“,0,&(romfs_root)) == 0)

4 {

5 rt_kprintf(”ROM file system initializated;

“);

6 }

7 else

8 {

“);

10 }

11 return 0;

12}

13INIT_ENV_EXPORT(mnt_init);

在文件系统操作表中找出romfs文件系统

检查”/“路径是否存在

检查romfs文件系统是否已经挂载在文件系统表中

检查文件系统表是否有空余,如果有,把空余地址指向romfs文件系统

注册文件系统

调用romfs文件系统的挂载接口

文件系统表filesystem_table的第二个目录:

6.2.4 测试RomFS文件系统

在根目录下使用shell 的ls命令:

6.3.1 简介

RamFS是内存文件系统,它不能格式化,可以同时创建多个,在创建时可以指定其最大能使用的内存大小。其优点是读写速度很快,但存在掉电丢失的风险。如果一个进程的性能瓶颈是硬盘的读写,那么可以考虑在RamFS上进行大文件的读写操作。

RT-Thread的RamFS设计之初未考虑支持文件夹,所以不能使用mkdir。

6.3.2 注册RamFS文件系统

设置ramfs文件系统的数据结构:_ramfs

1static const struct dfs_filesystem_ops _ramfs =

2{

3 ”ram“,

4 DFS_FS_FLAG_DEFAULT,

5 &_ram_fops,

6

7 dfs_ramfs_mount,

8 dfs_ramfs_unmount,

9 NULL, /* mkfs */

10 dfs_ramfs_statfs,

11

12 dfs_ramfs_unlink,

13 dfs_ramfs_stat,

14 dfs_ramfs_rename,

15};

将ramfs文件系统的数据结构挂载到文件系统操作表里

1int dfs_ramfs_init(void)

2{

3 /* register ram file system */

4 dfs_register(&_ramfs);

5

6 return 0;

7}

8INIT_COMPONENT_EXPORT(dfs_ramfs_init);

检查ramfs文件系统是否已经存在于文件系统操作表的目录中

在文件系统操作表中找出一个空的文件类型条目

将ramfs文件系统的数据结构_ramfs地址赋值给空的文件系统操作表目录

文件系统操作表filesystem_operation_table的第三个目录:

6.3.3 挂载RamFS文件系统

1int mnt_ram_elminit(void)

2{

3 if(dfs_mount (RT_NULL,”/mnt“,”ram“,0,dfs_ramfs_create(rampool, 1024)) == 0)

4 {

5 rt_kprintf(”ram file system initializated;

“);

6 }

7 else

8 {

9 rt_kprintf(”ram file system initializate failed;

“);

10 }

11 return 0;

12}

13INIT_ENV_EXPORT(mnt_ram_elminit);

在文件系统操作表中找出ramfs文件系统

检查”/mnt“路径是否存在

检查ramfs文件系统是否已经挂载在文件系统表中

检查文件系统表是否有空余,如果有,把空余地址指向ramfs文件系统

注册文件系统

调用ramfs文件系统的挂载接口

文件系统表filesystem_table的第三个目录:

6.3.4 测试RamFS文件系统

在根目录下使用shell 的cd命令切换到/mnt目录,然后使用ls命令:

6.4 elm-FAT文件系统

6.4.1 简介

FatFs 是一个通用的文件系统(FAT/exFAT)模块,用于在小型嵌入式系统中实现FAT文件系统。

6.4.2 使用流程

初始化 DFS 组件。

初始化具体类型的文件系统。

格式化块设备。

挂载块设备到 DFS 目录中。

当文件系统不再使用,可以将它卸载

6.4.3 注册elm-FAT文件系统

设置fatfs文件系统的数据结构:dfs_elm

1static const struct dfs_filesystem_ops dfs_elm =

2{

3 ”elm“,

4 DFS_FS_FLAG_DEFAULT,

5 &dfs_elm_fops,

6

7 dfs_elm_mount,

8 dfs_elm_unmount,

9 dfs_elm_mkfs,

10 dfs_elm_statfs,

11

12 dfs_elm_unlink,

13 dfs_elm_stat,

14 dfs_elm_rename,

15};

将fatfs文件系统的数据结构挂载到文件系统操作表里

1int elm_init(void)

2{

3 /* register fatfs file system */

4 dfs_register(&dfs_elm);

5

6 return 0;

7}

8INIT_COMPONENT_EXPORT(elm_init);

检查fatfs文件系统是否已经存在于文件系统操作表的目录中

在文件系统操作表中找出一个空的文件类型条目

将fatfs文件系统的数据结构dfs_elm 地址赋值给空的文件系统操作表目录

elm-FAT文件系统注册过程如下图所示:

6.4.4 挂载elm-FAT文件系统

1void sd_mount(void *parameter)

2{

3 while (1)

4 {

5 rt_thread_mdelay(500);

6 if(rt_device_find(”sd0“) != RT_NULL)

7 {

8 if (dfs_mount(”sd0“, ”/fatfs“, ”elm“, 0, 0) == RT_EOK)

9 {

10 LOG_I(”sd card mount to ‘/fatfs’“);

11 break;

12 }

13 else

14 {

15 LOG_W(”sd card mount to ‘/fatfs’ failed!“);

16 }

17 }

18 }

19}

20

22{

23 rt_thread_t tid;

24

25 tid = rt_thread_create(”sd_mount“, sd_mount, RT_NULL,

26 1024, RT_THREAD_PRIORITY_MAX - 2, 20);

27 if (tid != RT_NULL)

28 {

29 rt_thread_startup(tid);

30 }

31 else

32 {

33 LOG_E(”create sd_mount thread err!“);

34 }

35 return RT_EOK;

36}

在文件系统操作表中找出elm文件系统

检查”/fatfs“路径是否存在

检查elm文件系统是否已经挂载在文件系统表中

检查文件系统表是否有空余,如果有,把空余地址指向elm文件系统

注册文件系统

调用elm文件系统的挂载接口

6.4.5 测试elm-FAT文件系统

在根目录下使用shell 的cd命令切换到/fatfs目录,然后使用ls命令:

6.5 littlefs文件系统

6.5.1 简介

自带擦写均衡

支持掉电保护

占用的 RAM/ROM 少

littlefs 自带的擦写均衡和掉电保护使开发者可以放心的将文件系统挂载到 nor flash 上。层级关系

littlefs 在 RT-Thread 上运行的层级关系图如下所示:

6.5.2 使用流程

初始化 DFS 组件。

使能 littlefs 软件包。

使能 MTD 设备。

使能 fal,用来创建 MTD 设备。

创建 MTD 设备

挂载MTD设备到 DFS 目录中。

6.5.3 注册littlefs文件系统

设置littlefs文件系统的数据结构:_dfs_lfs_ops

1static const struct dfs_filesystem_ops _dfs_lfs_ops = {

2 ”lfs“,

3 DFS_FS_FLAG_DEFAULT,

4 &_dfs_lfs_fops,

5

6 _dfs_lfs_mount,

7 _dfs_lfs_unmount,

8

9 _dfs_lfs_mkfs,

10 _dfs_lfs_statfs,

11 _dfs_lfs_unlink,

12 _dfs_lfs_stat,

13 _dfs_lfs_rename,

14};

将littlefs文件系统的数据结构挂载到文件系统操作表里

1int dfs_lfs_init(void)

2{

3 /* init file system lock */

5 /* register ram file system */

6 return dfs_register(&_dfs_lfs_ops);

7}

8INIT_COMPONENT_EXPORT(dfs_lfs_init);

检查littlefs文件系统是否已经存在于文件系统操作表的目录中

在文件系统操作表中找出一个空的文件类型条目

将littlefs文件系统的数据结构_dfs_lfs_ops 地址赋值给空的文件系统操作表目录

6.5.4 挂载littlefs文件系统

1 。..

2 struct rt_device *mtd_dev = RT_NULL;

3

4 。..

5 /* 初始化 fal */

6 fal_init();

7 /* 生成 mtd 设备 */

8 mtd_dev = fal_mtd_nor_device_create(FS_PARTITION_NAME);

9 if (!mtd_dev)

10 {

12 }

13 else

14 {

15 /* 挂载 littlefs */

16 if (dfs_mount(FS_PARTITION_NAME, ”/littlefs“, ”lfs“, 0, 0) == 0)

17 {

18 LOG_I(”Filesystem initialized!“);

19 }

20 else

21 {

22 /* 格式化文件系统 */

23 dfs_mkfs(”lfs“, FS_PARTITION_NAME);

24 /* 挂载 littlefs */

25 if (dfs_mount(”filesystem“, ”/littlefs“, ”lfs“, 0, 0) == 0)

26 {

27 LOG_I(”Filesystem initialized!“);

28 }

29 else

30 {

31 LOG_E(”Failed to initialize filesystem!“);

32 }

33 }

34 }

35 。..

在文件系统操作表中找出lfs文件系统

检查”/littlefs“路径是否存在

检查littlefs文件系统是否已经挂载在文件系统表中

检查文件系统表是否有空余,如果有,把空余地址指向littlefs文件系统

注册文件系统

调用littlefs文件系统的挂载接口

6.5.5 测试littlefs文件系统

在根目录下使用shell 的cd命令切换到/littlefs目录,然后使用ls命令:

注意:spi_flash.h中缺少一个头文件,需要自行添加

6.6 文件系统综合例程

DevFS、RomFS、RamFS、FatFS文件系统配置:

littlefs文件系统配置;

主程序:

1#include 《rtthread.h》

2#include 《rtdevice.h》

3#include 《board.h》

4#include 《fal.h》

5

6#include 《dfs_fs.h》

7#include 《dfs_romfs.h》

8#include 《dfs_ramfs.h》

9#include 《dfs_posix.h》

10

11#define DBG_TAG ”main“

12#define DBG_LVL DBG_LOG

13#include 《rtdbg.h》

14

15/* defined the LED0 pin: PH10 */

16#define LED0_PIN GET_PIN(H, 10)

17

18int main(void)

19{

20 int count = 1;

21 rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);

22

23 while (count++)

24 {

25 rt_pin_write(LED0_PIN, PIN_HIGH);

26 rt_thread_mdelay(1000);

27 rt_pin_write(LED0_PIN, PIN_LOW);

28 rt_thread_mdelay(1000);

29 }

30

31 return RT_EOK;

32}

33rt_uint8_t rampool[128];

34

35void sd_mount(void *parameter)

36{

37 while (1)

38 {

39 rt_thread_mdelay(500);

40 if(rt_device_find(”sd0“) != RT_NULL)

41 {

42 if (dfs_mount(”sd0“, ”/fatfs“, ”elm“, 0, 0) == RT_EOK)

43 {

44 LOG_I(”sd card mount to ’/fatfs‘“);

45 break;

46 }

47 else

48 {

49 LOG_W(”sd card mount to ’/fatfs‘ failed!“);

50 }

51 }

52 }

53}

54

55int fs_init(void)

56{

57 /* partition initialized */

58 fal_init();

59

60 if(dfs_mount (RT_NULL,”/“,”rom“,0,&(romfs_root)) == 0)

61 {

62 LOG_I(”ROM file system initializated;

“);

63 }

64 else

65 {

66 LOG_I(”ROM file system initializate failed;

“);

67 }

68

69 if(dfs_mount (RT_NULL,”/ram“,”ram“,0,dfs_ramfs_create(rampool, sizeof(rampool))) == 0)

70 {

71 LOG_I(”ram file system initializated;

“);

72 }

73 else

74 {

75 LOG_I(”ram file system initializate failed;

“);

76 }

77

78 /* Create a block device on the file system partition of spi flash */

79 struct rt_device *flash_dev = fal_mtd_nor_device_create(”filesystem“);

80

81 if (flash_dev == RT_NULL)

82 {

83 LOG_I(”Can’t create a mtd device on ‘%s’ partition.“, ”filesystem“);

84 }

85 else

86 {

87 LOG_I(”Create a mtd device on the %s partition of flash successful.“, ”filesystem“);

88 }

89 /* mount the file system from ”filesystem“ partition of spi flash. */

90 if (dfs_mount(flash_dev-》parent.name, ”/littlefs“, ”lfs“, 0, 0) == 0)

91 {

92 LOG_I(”littlefs initialized!“);

93 }

94 else

95 {

96 dfs_mkfs(”lfs“, flash_dev-》parent.name);

97 if (dfs_mount(flash_dev-》parent.name, ”/“, ”lfs“, 0, 0) == 0)

98 {

99 LOG_I(”littlefs initialized!“);

100 }

101 }

102

103 rt_thread_t tid;

104

105 tid = rt_thread_create(”sd_mount“, sd_mount, RT_NULL,

106 1024, RT_THREAD_PRIORITY_MAX - 2, 20);

107 if (tid != RT_NULL)

108 {

109 rt_thread_startup(tid);

110 }

111 else

112 {

113 LOG_E(”create sd_mount thread err!“);

114 }

115 return 0;

116}

117INIT_COMPONENT_EXPORT(fs_init);

测试:

责任编辑:pj

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:HDFS Federation
下一篇:oozie学习笔记
相关文章

 发表评论

暂时没有评论,来抢沙发吧~