e 文件系统





0/5 (0投票)
它可用于归档文件,因为所有读写操作都发生在底层系统的一个实际文件中。此外,它还可用于在客户端-服务器环境中流式传输数据。此外,它还可作为爱好者操作系统或嵌入式操作系统的文件系统。
引言
e 文件系统以欧拉常数 e = 2.718 命名,它是一个基本文件系统,旨在支持类 UNIX 接口。该系统目前设计为在用户空间运行,其中所有数据都存储在一个文件中,尽管它代表多个文件和目录。该系统目前支持大多数 UNIX 系统调用,如 open、close、read、write 和 lseek。它可用于归档文件,因为所有读写操作都发生在底层系统的一个实际文件中。此外,它还可用于在客户端-服务器环境中流式传输数据。此外,它还可作为爱好者操作系统或嵌入式操作系统的文件系统。
背景
e 文件系统的基本设计侧重于一个 512 字节的块。虽然这可以配置为更大的常量,但所有读写操作都基于此块大小,在代码中由 C 宏 DEV_BLOCK_SIZE
表示。该系统约 20% 的块用于 inode,其余 80% 用于数据。可用文件系统的初始空间目前保留用于加载内核,代表 0 到 4095 块,或两兆字节。第一个块是块 4096,它是描述文件系统的根块。它的 C 结构名称是 master_inode
,其定义如下:
typedef struct master_inode {
short magic; /* Magic to identify the file system. */
short init_fs; /* 1 if fs is initialized, 0 otherwise. */
block_t block_start; /* location of master inode. */
block_t inode_map_start; /* map of free inodes start. */
block_t inode_map_end; /* map of free inodes end. */
block_t bmap_map_start; /* map of free blocks start. */
block_t bmap_map_end; /* map of free blocks end. */
block_t inode_start; /* start of inodes. */
block_t inode_end; /* end of inodes. */
block_t data_start; /* start of data. */
block_t data_end; /* end of data. */
block_t imap_ptr; /* what inode map block on disk. */
block_t imap_bit; /* what inode map bit. */
block_t bmap_ptr; /* what bit map block on disk. */
block_t bmap_bit; /* what bit map bit. */
block_t inodes; /* number of inodes. */
block_t blocks; /* number of blocks. */
char *imap; /* Created on the fly and loaded. */
char *bmap; /* Created on the fly and loaded. */
block_t dev; /* Device we are on. */
char pad[MNODE_PAD]; /* padding to fit page size. */
} master_inode_t;
master_inode
也称为根 inode,它描述了磁盘上文件系统的布局。它指示 inodes
的起始位置、数据节点起始位置以及用于标记哪些块可用或已使用的位图的起始位置。下一个也是最重要的结构是 inode
结构,它是一个 C 结构,定义如下:
typedef struct inode {
char user_read;
char user_write;
char user_execute;
char group_read;
char group_write;
char group_execute;
char world_read;
char world_write;
char world_execute;
char is_directory; /* If this is a directory,
* all blocks point to other inodes,
including next. */
char is_device; /* If this is a device, call device
driver subsystem. */
char is_file; /* If this is a file, all blocks point
to data, including next. */
char is_symlink; /* If this is a symlink. */
char is_hardlink; /* If this is a hardlink. */
block_t create_time; /* Time of last status change. */
block_t modified_time; /* Time of last modification. */
block_t accessed_time; /* Time of last access. */
block_t self;
block_t parent;
/* The following are used for implementing files:
* size (sizeof file)
* pos (position in the file)
* current (current block number of block we are in)
* dev (device we are on)
*/
inode_ptr_t size; /* Size of the file in 64 bits. */
inode_ptr_t pos; /* Where in the file we are currently.*/
// NOTE - These fields must be initialized on open of the file.
block_t current; /* Current data block. */
block_t current_parent; /* Block map to which current is stored in. */
int iblock; /* Where in the current_parent we are. */
int dev; /* Device we are on. */
inode_perm_t o_mode; /* File open mode. */
// The above fields are needed for implementing files.
inode_group_t group; /* Group where we belong. */
inode_own_t owner; /* Who owns this file. */
block_t refcount; /* Reference count. */
char path[MAX_PATH];
char pad[INODE_PAD];
block_t next; /* Map to blocks in case of a regular file.*/
} inode_t;
inode
结构与 master_inode
一样,每个大小为 512 字节。inode
描述文件或目录的入口点。如果它是文件,则下一个指针指向数据块;如果它是目录,则下一个指针指向其他 inode。在这两种情况下,下一个指针都指向一个名为 block_map 的 C 结构,该结构包含 127 个块指针和一个下一个指针。块指针可以是数据或 inode。所有块的大小都是固定的 512 字节。block_map
结构定义如下:
typedef struct block_map {
block_t next;
block_t blocks[BMAP_BLOCKS];
} block_map_t;
符号链接实现为一个 512 字节的块,由 inode 中的下一个指针指向,并包含另一个文件或目录的路径。硬链接的实现方式类似,但与之关联的是一个引用计数。link 的结构定义如下:
typedef struct link {
char path[MAX_PATH];
char pad[MAX_PATH];
} link_t;
实现中最重要函数是 inode_create
、inode_get
和 inode_free
。这些函数以及其他文件系统函数利用块缓冲缓存。inode_create 函数创建文件、目录、符号链接和硬链接。inode_get
函数从文件系统中检索代表文件、目录、符号链接或硬链接的 inode。inode_free
函数释放文件、目录、符号链接或硬链接的资源。对于目录,如果目录不为空,inode_free
函数将失败。
系统中的路径使用 UNIX 风格的路径表示,路径分隔符是“/”正斜杠字符。文件系统的根表示为单个正斜杠。当前目录用特殊字符“.”表示。父目录用特殊字符“..”表示。
实现采用了分层方法,先实现了最基本组件。所有组件都使用 C 编写的测试驱动程序进行测试,并且是各自 .c 实现文件的一部分。最低级和最基本的模块是用于实现位图的 bitmap.c,用于 UNIX 路径操作的 paths.c,以及用于从磁盘读取或写入指定块的 dev.c。下一个级别是包含在 block.c 中的块缓冲缓存。系统的核心是 inode.c,它实现了所有 inode 功能。引用文件的文件系统系统调用位于 file.c 中。这些包括熟悉的 open、read、write、close 和 lseek 调用。目录系统调用位于 dir.c。链接系统调用位于 link.c。一个名为 krealpath.c 的实用模块提供了一个函数来将相对路径解析为绝对路径,因为所有函数实际上都处理绝对路径。为了让系统在用户空间运行,需要一些类内核结构,这些结构包含在 compat.h 和 compat.c 中。
Using the Code
如果没有为系统调用添加前缀,代码将无法在用户空间编译和运行。没有前缀,本地实现的系统调用很可能会解析底层内核的调用。因此,所有调用都加上“k”前缀,并且可以通过 fs_syscalls.h 在 C 程序中使用外部接口。例如,如果您想打开一个文件,则需要使用 kopen 调用而不是 open 系统调用。在实际使用文件系统之前,需要对其进行初始化。代码如下:
// ...
#include "bool.h"
#include "paths.h"
#include "block.h"
#include "dev.h"
#include "inode.h"
#ifdef _TEST_INC
#include <stdio.h>
#include <string.h>
#define printk printf
#include "compat.h"
#endif
#include "file.h"
#include "dir.h"
#include "link.h"
// Obtains the device based on block_open -> dev_open
// Initialization here is similar to what would happen
// in the real kernel. We must make the file system first.
if(inode_dev_open("./inode.dat",&dev) == INODE_INIT) {
if(inode_mkfs("./inode.dat", 2 * TWOMEG) != INODE_OK) {
printk("fs_init:: error initializing filesystem\n");
return 1;
}
if(inode_dev_open("./inode.dat", &dev) != INODE_OK) {
printk("fs_init:: error opening device\n");
return 1;
}
}
master = master_get(dev);
master_set_dev("./inode.dat", dev);
代码首先在调用 inode_dev_open
时检查文件系统是否可以打开,如果不能,则使用 inode_mkfs
调用创建文件系统。创建文件系统后,需要第二次调用 inode_dev_open
来打开文件系统。之后,需要初始化主 inode,并调用 master_get 和
master_set_dev 来完成此操作。在执行完这些调用后,就可以使用文件系统了。例如:
if((fd = kopen(“/foo”, O_CREAT | O_RDWR)) == -1) {
printk(“error opening file\n”);
}
// Ok to read, write fd file descriptor.
关注点
该系统是正在开发中的爱好者操作系统的一部分。鼓励有兴趣开发用于嵌入式和实验用途的开源内核的用户与作者联系。目前,该文件系统已使用作为相应 C 源文件一部分的测试驱动程序进行了测试,并测试了特定模块。随附的 Makefile 构建了各种测试程序来测试代码。由于没有用户使用过该代码,因此应将该代码视为 beta 版本。鼓励用户使用该代码并对其进行改进。