文件系统实现
1. 核心概念和架构
Nanos-lite需要实现一个文件系统,用于管理程序和数据。这个设计基于几个关键概念:
- 文件抽象:文件本质是字节序列加上额外属性。
- 文件描述符:通过数字标识符引用打开的文件。
- 虚拟文件系统:统一接口访问不同类型的"文件"。
- "一切皆文件"哲学:将设备和其他资源统一抽象为文件。
2. 简易文件系统(SFS)实现
基本特点
- 文件大小固定。
- 写操作不能超过原有大小。
- 文件数量固定。
- 无目录结构(文件名中包括路径)。
物理存储布局
0
+-------------+---------+----------+-----------+--
| file0 | file1 | ...... | filen |
+-------------+---------+----------+-----------+--
\ / \ / \ /
+ size0 + +size1+ + sizen +
文件记录表结构
typedef struct {
char *name; // 文件名
size_t size; // 文件大小
size_t disk_offset; // 文件在ramdisk中的偏移
ReadFn read; // 读函数指针
WriteFn write; // 写函数指针
} Finfo;
3. 核心API实现
文件操作接口
int fs_open(const char *pathname, int flags, int mode);
size_t fs_read(int fd, void *buf, size_t len);
size_t fs_write(int fd, const void *buf, size_t len);
size_t fs_lseek(int fd, size_t offset, int whence);
int fs_close(int fd);
实现要点
- 在
fs_open
中查找文件并返回文件描述符(文件表索引)。 - 为每个打开的文件维护偏移量
open_offset
。 - 在读写操作中检查边界条件。
- 通过函数指针调用相应的读写操作。
4. 虚拟文件系统设计
VFS的核心思想
通过函数指针抽象不同类型的文件操作:
- 普通文件:使用ramdisk读写。
- 特殊文件:使用专门的处理函数。
文件类型区分
- 块设备文件:有"位置"概念,支持lseek (如ramdisk文件)。
- 字符设备文件:无"位置"概念,不支持lseek (如键盘,串口)。
5. 标准输入输出和设备文件
预定义文件描述符
#define FD_STDIN 0 // 标准输入
#define FD_STDOUT 1 // 标准输出
#define FD_STDERR 2 // 标准错误
设备抽象为文件
-
串口 →
/dev/tty
-
实现
serial_write()
供 stdout 和 stderr 使用。 -
键盘事件 →
/dev/events
-
实现
events_read()
获取按键事件。 - 事件格式:
kd KEY\n
(按下) 或ku KEY\n
(释放)。 -
显示设备 →
/dev/fb
-
实现
fb_write()
将像素写入帧缓冲。 - 支持 lseek 定位到特定像素位置。
-
显示信息 →
/proc/dispinfo
-
实现
dispinfo_read()
提供屏幕大小等信息。
6. 用户层多媒体库 (NDL)
NDL库为用户程序提供统一接口,通过文件操作访问底层设备:
// 时间相关
uint32_t NDL_GetTicks(); // 通过gettimeofday实现
// 输入事件相关
int NDL_PollEvent(char *buf, int len); // 读取/dev/events
// 绘图相关
void NDL_OpenCanvas(int *w, int *h); // 创建画布,读取/proc/dispinfo获取屏幕信息
void NDL_DrawRect(uint32_t *pixels, int x, int y, int w, int h); // 写入/dev/fb
7. 实现步骤
- 初始化文件系统和文件记录表。
- 实现普通文件的读写操作(ramdisk)。
- 实现文件描述符管理。
- 实现标准输入输出设备。
- 实现其他设备文件接口。
- 实现 NDL 库,通过文件接口访问设备.