Skip to content

Commit 1deac24

Browse files
committed
working on rtems file system
1 parent 4a441b5 commit 1deac24

File tree

1 file changed

+179
-13
lines changed

1 file changed

+179
-13
lines changed

为了工作/Linux/内核层/Rtems Source Code.md

Lines changed: 179 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ categories:
55
- 内核层
66
abbrlink: 4936fe45
77
date: 2025-05-19 12:50:00
8-
updated: 2025-05-21 23:00:00
8+
updated: 2025-05-22 16:30:00
99
---
1010

1111
<meta name="referrer" content="no-referrer"/>
@@ -18,9 +18,11 @@ RTEMS(Real‑Time Executive for Multiprocessor Systems)是一款始于 1988
1818

1919
<!-- more -->
2020

21-
# 文件系统流程
21+
# 文件系统
2222

23-
## open 函数
23+
## 系统调用
24+
25+
### open 函数
2426

2527
open() 函数的源码如下:
2628

@@ -56,7 +58,7 @@ int open(const char *path, int oflag, ...)
5658
}
5759
```
5860
59-
### struct rtems_libio_t
61+
#### struct rtems_libio_t
6062
6163
rtems_libio_t 结构体定义如下。该结构体用于表示一个文件描述符的内部状态,Rtems 中每打开一个文件都会关联一个该结构体的实例,通常简称为 iop(I/O pointer)。
6264
@@ -86,7 +88,7 @@ struct rtems_libio_tt
8688
};
8789
```
8890

89-
#### struct rtems_filesystem_location_info_t
91+
##### struct rtems_filesystem_location_info_t
9092

9193
rtems_filesystem_location_info_t 结构体定义如下。它表示一个路径位置,用于描述文件系统中某个具体节点(如文件或目录)的位置及其访问方式。
9294

@@ -189,7 +191,7 @@ struct rtems_filesystem_mount_table_entry_tt
189191
};
190192
```
191193

192-
### rtems_libio_allocate()
194+
#### rtems_libio_allocate()
193195

194196
open 函数中分配文件描述符结构使用的函数是 rtems_libio_allocate(),定义如下:
195197

@@ -229,7 +231,7 @@ rtems_libio_t *rtems_libio_allocate(void)
229231
}
230232
```
231233
232-
#### rtems_libio_iop_free_head
234+
##### rtems_libio_iop_free_head
233235
234236
rtems_libio_iop_free_head 是一个全局变量,用于维护 Rtems 文件描述符(rtems_libio_t)的空闲链表头指针。
235237
@@ -271,7 +273,7 @@ rtems_libio_iops 是 Rtems 预先分配的 I/O 控制块数组,配置了 CONFI
271273
rtems_libio_t rtems_libio_iops[ CONFIGURE_MAXIMUM_FILE_DESCRIPTORS ];
272274
```
273275
274-
### do_open()
276+
#### do_open()
275277
276278
open() 函数中分配好文件描述符结构以后,最终会到达 do_open() 函数的位置进行处理。
277279
@@ -449,7 +451,7 @@ static int do_open(
449451
}
450452
```
451453

452-
#### 路径解析过程
454+
##### 路径解析过程
453455

454456
do_open() 涉及到的路径解析代码片段如下:
455457

@@ -543,7 +545,7 @@ rtems_filesystem_eval_path_extract_currentloc(&ctx, &iop->pathinfo);
543545
rtems_filesystem_eval_path_cleanup(&ctx);
544546
```
545547
546-
#### 底层文件系统的 open 函数
548+
##### 底层文件系统的 open 函数
547549
548550
拿到所有信息以后,do_open() 函数中调用底层文件系统的 open() 函数真正打开文件:
549551
@@ -552,7 +554,7 @@ rtems_filesystem_eval_path_cleanup(&ctx);
552554
rv = (*iop->pathinfo.handlers->open_h)(iop, path, oflag, mode);
553555
```
554556

555-
## close 函数
557+
### close 函数
556558

557559
close() 函数的源码如下。在前面更改完状态标志位后,还是会进入到底层文件系统的 close_h 函数。
558560

@@ -632,7 +634,7 @@ int close(int fd)
632634
}
633635
```
634636
635-
## read 函数
637+
### read 函数
636638
637639
read() 函数的源码如下。可以看出除了做了一些检查以外,直接调用了底层文件系统的 read_h() 函数。
638640
@@ -670,7 +672,7 @@ ssize_t read(
670672
}
671673
```
672674

673-
## write 函数
675+
### write 函数
674676

675677
write() 函数的源码如下。大致逻辑同样同 read 函数。
676678

@@ -707,3 +709,167 @@ ssize_t write(
707709
}
708710
```
709711

712+
## 文件系统启动流程
713+
714+
### rtems_filesystem_initialize()
715+
716+
该函数用于初始化 Rtems 的根文件系统,通常是 IMFS。[官方文档](https://docs.rtems.org/docs/6.1/filesystem/system_init.html) 提到,其他文件系统可以被挂载,但它们只能挂载到基础文件系统中的某个目录挂载点。对于我们想注册的自定义文件系统,有两种手段,一种是在根文件系统挂载好以后,找到某个目录手动挂载新文件系统,另一种是直接修改 rtems_filesystem_root_configuration 根文件系统的配置,使用我们自己的文件系统,这样 Rtems 在启动的时候就会默认跑我们自己的文件系统。
717+
718+
```c
719+
void rtems_filesystem_initialize(void)
720+
{
721+
int rv = 0;
722+
723+
// 获取根文件系统的挂载配置信息(通常是 IMFS)。
724+
const rtems_filesystem_mount_configuration *root_config =
725+
&rtems_filesystem_root_configuration;
726+
727+
// 挂载根文件系统(通常是内存文件系统 IMFS)。
728+
rv = mount(
729+
root_config->source, // 挂载源(IMFS 为 NULL)。
730+
root_config->target, // 挂载点(根目录 "/")。
731+
root_config->filesystemtype, // 文件系统类型(如 "imfs")。
732+
root_config->options, // 挂载选项(一般为 0)。
733+
root_config->data // 传递给文件系统的私有数据(通常为 NULL)。
734+
);
735+
736+
// 如果挂载失败,触发致命错误并停止系统。
737+
if (rv != 0)
738+
rtems_fatal_error_occurred(0xABCD0002);
739+
740+
/*
741+
* 传统 UNIX 系统将设备节点放在 "/dev" 目录,
742+
* 所以我们手动在根文件系统中创建 "/dev" 目录。
743+
* 权限为 0755:所有者可读写执行,组用户和其他用户可读执行。
744+
*/
745+
rv = mkdir("/dev", S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
746+
747+
// 如果 "/dev" 目录创建失败,也触发致命错误。
748+
if (rv != 0)
749+
rtems_fatal_error_occurred(0xABCD0003);
750+
751+
/*
752+
* 到此为止,根文件系统(IMFS)和 /dev 目录已经建立。
753+
*
754+
* 下面这段注释说明:
755+
* - 如果你想挂载其他文件系统(如 FAT、NFS 等),你必须先创建挂载点目录。
756+
* - 如果该文件系统依赖设备(如块设备 /dev/sd0),则必须等设备驱动初始化完成。
757+
* - 所以此函数只做了最基本的文件系统初始化,并没有自动挂载其他文件系统。
758+
* - 后续可以手动使用 mount() 挂载其他子文件系统。
759+
*/
760+
}
761+
```
762+
763+
#### struct rtems_filesystem_mount_configuration
764+
765+
挂载根文件系统的挂载配置信息的结构体是 struct rtems_filesystem_mount_configuration。该结构体是 Rtems 中用于挂载文件系统时传递参数的配置结构。它的作用是将挂载一个文件系统所需的各种信息(如设备源、挂载点、文件系统类型等)集中在一起,作为参数传给 mount() 函数。
766+
767+
```c
768+
typedef struct
769+
{
770+
// 描述挂载源,通常是设备路径,如 "/dev/sd0";对 IMFS 等内存文件系统可为 NULL。
771+
const char *source;
772+
773+
// 挂载目标目录,必须是系统中已存在的路径,如 "/" 或 "/mnt/usb"。
774+
const char *target;
775+
776+
// 文件系统类型的名称字符串,如 "imfs"、"dosfs"、"devfs" 等。
777+
const char *filesystemtype;
778+
779+
// 挂载选项,定义为 rtems_filesystem_options_t 类型,控制如只读、读写等行为。
780+
rtems_filesystem_options_t options;
781+
782+
// 指向文件系统特定的附加数据,一般为 NULL,某些文件系统可能使用此字段传递配置。
783+
const void *data;
784+
} rtems_filesystem_mount_configuration;
785+
```
786+
787+
在 rtems_filesystem_initialize() 中,根文件系统的配置是预定义好的全局变量 rtems_filesystem_root_configuration。
788+
789+
```c
790+
const rtems_filesystem_mount_configuration rtems_filesystem_root_configuration = {
791+
NULL,
792+
NULL,
793+
"/",
794+
RTEMS_FILESYSTEM_READ_WRITE,
795+
&IMFS_root_mount_data,
796+
};
797+
```
798+
799+
### rtems_filesystem_register()
800+
801+
rtems_filesystem_register() 用于在 Rtems 操作系统中注册一个新的文件系统类型。它接收文件系统的类型名称和对应的挂载函数指针,动态分配内存创建一个文件系统节点,将类型名称和挂载函数保存到该节点中,并检查该类型是否已被注册。如果未注册,则将该节点添加到全局文件系统链表完成注册;如果已注册,则释放内存并返回错误。通过这个注册机制,系统能够识别和管理多种文件系统类型,并在需要时调用对应的挂载函数进行挂载操作。
802+
803+
```c
804+
// 文件系统类型字符串,例如 "imfs"、"dosfs" 等。
805+
int rtems_filesystem_register(
806+
const char *type,
807+
// 挂载处理函数指针,用于挂载该类型的文件系统。
808+
rtems_filesystem_fsmount_me_t mount_h)
809+
{
810+
// 获取全局文件系统链表控制结构的指针。
811+
rtems_chain_control *chain = &filesystem_chain;
812+
813+
// 计算文件系统类型字符串长度(包含字符串结束符)。
814+
size_t type_size = strlen(type) + 1;
815+
816+
// 计算要分配的内存大小:filesystem_node结构体大小 + 文件系统类型字符串大小。
817+
size_t fsn_size = sizeof(filesystem_node) + type_size;
818+
819+
// 动态分配内存用于存储新文件系统节点和类型字符串。
820+
filesystem_node *fsn = malloc(fsn_size);
821+
822+
// 指向分配内存中,存储类型字符串的位置(紧接在filesystem_node结构体之后)。
823+
char *type_storage = (char *)fsn + sizeof(*fsn);
824+
825+
// 如果内存分配失败。
826+
if (fsn == NULL)
827+
// 设置错误码为“内存不足”,返回-1。
828+
rtems_set_errno_and_return_minus_one(ENOMEM);
829+
830+
// 将传入的文件系统类型字符串拷贝到刚分配的内存中。
831+
memcpy(type_storage, type, type_size);
832+
833+
// 设置节点中的type指针指向存储的类型字符串。
834+
fsn->entry.type = type_storage;
835+
836+
// 设置节点中的挂载处理函数指针。
837+
fsn->entry.mount_h = mount_h;
838+
839+
// 加锁,防止多线程环境下链表操作冲突。
840+
rtems_libio_lock();
841+
842+
// 检查链表中是否已注册过该类型的文件系统。
843+
if (rtems_filesystem_get_mount_handler(type) == NULL)
844+
{
845+
// 初始化新节点的链表节点结构。
846+
rtems_chain_initialize_node(&fsn->node);
847+
848+
// 将新节点追加到文件系统链表中(无锁版本,锁由外部保证)。
849+
rtems_chain_append_unprotected(chain, &fsn->node);
850+
}
851+
else
852+
{
853+
// 如果已注册,解锁。
854+
rtems_libio_unlock();
855+
856+
// 释放刚分配的内存。
857+
free(fsn);
858+
859+
// 设置错误码为“无效参数”(文件系统类型重复),返回-1。
860+
rtems_set_errno_and_return_minus_one(EINVAL);
861+
}
862+
863+
// 解锁。
864+
rtems_libio_unlock();
865+
866+
// 成功返回0。
867+
return 0;
868+
}
869+
```
870+
871+
# 参考文档
872+
873+
1. [RTEMS Filesystem Design Guide (6.1). — RTEMS Filesystem Design Guide 6.1 (22nd January 2025) documentation](https://docs.rtems.org/docs/6.1/filesystem/index.html)
874+
2. [rtems文件系统部分 - 《ext4文件系统移植》 - 极客文档](https://geekdaxue.co/read/linggs@qnf7q6/pnhxbw)
875+

0 commit comments

Comments
 (0)