Skip to content

文件系统实现

1. 核心概念和架构

Nanos-lite需要实现一个文件系统,用于管理程序和数据。这个设计基于几个关键概念:

  1. 文件抽象:文件本质是字节序列加上额外属性。
  2. 文件描述符:通过数字标识符引用打开的文件。
  3. 虚拟文件系统:统一接口访问不同类型的"文件"。
  4. "一切皆文件"哲学:将设备和其他资源统一抽象为文件。

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);

实现要点

  1. fs_open 中查找文件并返回文件描述符(文件表索引)。
  2. 为每个打开的文件维护偏移量 open_offset
  3. 在读写操作中检查边界条件。
  4. 通过函数指针调用相应的读写操作。

4. 虚拟文件系统设计

VFS的核心思想

通过函数指针抽象不同类型的文件操作:

  • 普通文件:使用ramdisk读写。
  • 特殊文件:使用专门的处理函数。

文件类型区分

  • 块设备文件:有"位置"概念,支持lseek (如ramdisk文件)。
  • 字符设备文件:无"位置"概念,不支持lseek (如键盘,串口)。

5. 标准输入输出和设备文件

预定义文件描述符

#define FD_STDIN  0  // 标准输入
#define FD_STDOUT 1  // 标准输出
#define FD_STDERR 2  // 标准错误

设备抽象为文件

  1. 串口/dev/tty

  2. 实现 serial_write() 供 stdout 和 stderr 使用。

  3. 键盘事件/dev/events

  4. 实现 events_read() 获取按键事件。

  5. 事件格式:kd KEY\n (按下) 或 ku KEY\n (释放)。
  6. 显示设备/dev/fb

  7. 实现 fb_write() 将像素写入帧缓冲。

  8. 支持 lseek 定位到特定像素位置。
  9. 显示信息/proc/dispinfo

  10. 实现 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. 实现步骤

  1. 初始化文件系统和文件记录表。
  2. 实现普通文件的读写操作(ramdisk)。
  3. 实现文件描述符管理。
  4. 实现标准输入输出设备。
  5. 实现其他设备文件接口。
  6. 实现 NDL 库,通过文件接口访问设备.