假设所有文件系统都是特定的,像 ls、touch、cat 等工具如何与它们交互?我想 'ls' 不知道有关 btrfs 的细节,但它无论如何都会读取目录条目。当某个进程写入文件时,它不知道特定文件系统的块分配器的细节,但无论如何,文件已成功写入。
是否有某种内核 API 可以对进程隐藏底层文件系统实现?出于学术目的设计一个自定义的简单文件系统并编写一个操作它的程序(mkfs,fsck等)并不太复杂,但是如何告诉内核文件系统的实现,以便其他进程可以使用它?
编辑:
我了解用户空间中的系统调用,但我真正感兴趣的是之后在内核空间中发生的事情。
答案1
在任何 POSIX 系统上,应用程序和内核之间的接口都是一些函数调用:open
、read
、write
、close
等。应用程序例如cat
调用这些函数;它不关心这些功能是如何在后台实现的。
在 Unix 系统上,这些函数实际上是系统调用:应用程序调用核心。在内核内部,典型的体系结构是虚拟FS层,它处理独立于文件系统格式的任务(例如定位正确的文件系统、权限、锁定等)。一旦确定了文件所在的文件系统,VFS 层就会将操作传递给正确的文件系统特定驱动程序。
您可以使用类似的工具观察应用程序和内核之间的接口斯特雷斯在 Linux 或其他 Unix 平台上的同等平台上(trace
、truss
、 ...)。示例(省略启动和最终清理对应的跟踪部分cat
):
$ strace cat foo
…
open("foo", O_RDONLY) = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=6, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
mmap(NULL, 139264, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f8b9ea14000
read(3, "hello\n", 131072) = 6
write(1, "hello\n", 6hello
) = 6
read(3, "", 131072) = 0
munmap(0x7f8b9ea14000, 139264) = 0
close(3) = 0
…
您可以在文件上看到cat
调用open
,read
和。close
它还调用fstat
and fadvise64
,我认为只是为了性能优化。
VFS 和文件系统驱动程序之间的接口不能那么容易被监视。
程序喜欢mkfs
但fsck
不通过内核的文件系统接口,因为它们不处理文件,而是处理存储区域。他们访问块设备直接包含文件系统。
如果要添加对新文件系统的支持,则需要为其编写驱动程序。有两种方法可以解决这个问题。
- 你可以编写一个在内核中运行的驱动程序;这将为您带来最佳性能,并且是实现某些功能(例如细粒度访问控制)的唯一方法。但它也更难调试(如果你的驱动程序有错误,你可能需要重新启动;如果幸运的话,你可能能够查看错误跟踪,甚至可能延迟重新启动,直到保存数据 -最好在虚拟机中执行此操作)。查找您的 Unix 变体内核的文档,了解您需要实现什么接口。
- 或者,您可以使用保险丝,它是一个文件系统驱动程序,它将所有请求转发回内核之外,因此每个文件系统驱动程序都实现为一个进程。如果文件系统有问题,只需终止文件系统驱动程序进程,操作系统的其余部分就可以继续存在。要了解如何编写 FUSE 文件系统,请参阅例子并阅读教程,例如苏米特·辛格。
答案2
Unix/Linux 系统提供 POSIX 系统调用 open(2)/close(2)/read(2)/write(2) 和 stat(2) 以及一些更高级别的函数,如 opendir(3)/angledir(3) /readdir(3),这足以编写所述工具(使用 C 包装器更容易)。内核的部分艰巨工作正是使它们在提供的各种文件系统上工作,并使整个工作在它们可能驻留在的任何设备上。