数据截至 (上游 commit aae05d825bb5)
客机文件系统:virtio-fs 后端、写时复制与主机穿透
30 秒导读: 微VM 里跑的程序读写文件时,内核发出的每一个 FUSE 请求,都由主机上一个普通用户态进程接住并回答。这个进程实现了三种"文件系统后端":纯内存的
memfs、直穿主机目录的passthroughfs、以及把两层叠起来做写时复制的dualfs。本章讲这三层怎么分工、写层(可写上层)怎么在只读底层之上凭空长出来,以及主机进程如何在不动主机真实 inode 的前提下,把 uid/gid/权限/配额都"演"给客机看。
本章是运行期视角:VM 已经起来了,客机正在挂载、读写文件。只读镜像本身的字节布局(EROFS/OCI 层)是构建期的事,见 03-image-rootfs;客机通过协议帧发起的远程文件操作(host 端主动读写沙箱里的文件)走的是另一条通道,见 02-protocol-relay。
1. 这是什么(零基础也能懂)
一句话定义: 客机的文件系统不是一块真磁盘,而是主机进程用代码"现编"的答案——客机内核每次 open/read/readdir,都通过 virtio-fs 这条虚拟总线问到主机进程头上,主机进程查自己的数据结构、必要时读主机真实文件,再把结果回给客机。
为什么要这样做? 因为 microsandbox 的目标是"启动快、隔离强、还能 和主机共享目录"。如果给每个沙箱都格式化一块虚拟磁盘,又慢又浪费。用 virtio-fs 直接把主机的一个目录"投影"进客机,既省事又能双向共享。但直接投影有两个麻烦:
- 底层是只读的(OCI 根文件系统镜像不能被沙箱改坏)——那客机怎么写文件?
- 主机进程不是 root——它没法
chown、没法造设备节点、没法给符号链接设 xattr,可客机里的程序偏偏要求这些能力都正常。
microsandbox 在这一层的全部精巧,都是在回答这两个问题。
一句话直觉/类比: 把它想成一个尽职的前台代接员。客机打电话来问"3 号文件谁是主人?",前台不敢冒充主人的名义改户口(主机 root 权限),就掏出一个小本子(xattr 里的 20 字节 override),照本子念一个"虚拟户主"给你听。你要改文件?底层文件是只读的,前台就先把它复印一份放到可写的上层,让你改复印件——这就是写时复制(copy-on-write,COW,只有真要写时才复制,读的时候大家共享同一份)。
它能做什么:
- 把主机某个目录直穿给客机读写(
passthroughfs)。 - 在只读镜像之上叠一个可写层,实现 COW,客机改动只落在上层(
dualfs)。 - 提供一个纯内存的临时文件系统(
memfs)。 - 在主机进程不特权的前提下,把 uid/gid/mode/设备号、以及"这个文件属于谁"都虚拟化给客机看,而不真的动主机 inode。
- 给可写层设一个字节预算(quota),防止客机把主机磁盘写爆。