WSL 中如何用 mount -t drvfs 手动挂载 Windows 驱动器并理解提权与非提权挂载点?
【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL
在 WSL 中,Windows 驱动器默认以挂载点形式出现在/mnt目录下(指向驱动器根目录)。当默认挂载点不满足需求——例如想把C:挂到自定义目录、或挂载一个 UNC 路径——可以用mount -t drvfs手动完成挂载。同时,WSL 在发行版内部用两套挂载命名空间区分提权(管理员级)和非提权(用户级)上下文,这决定了你的手动挂载会连接哪一个 plan9 文件服务。以下内容基于 WSL 仓库的技术文档(drvfs.md)与文档指向的实现源码整理。
挂载前需要了解的默认状态
- WSL 提供的 Windows 驱动器挂载点默认位于
/mnt,指向 Windows 驱动器根目录。 - 在 WSL2 发行版中,当一个 session leader 被创建时,wslservice.exe 会启动一个 plan9 文件服务,WSL2 虚拟机内的发行版通过它来挂载 Windows 驱动器。这一机制仅适用于 WSL2 发行版。
- 只要 Windows 侧的 plan9 服务在运行,Linux 侧随时可以用
mount挂载 Windows 驱动器,无需重启发行版。 - 发行版初始化时,init 的常规任务之一也是挂载
drvfs驱动器;每个发行版运行在独立的 mount/pid/UTS 命名空间中,但/mnt/wsl挂载点在全部发行版之间共享。
手动挂载一条 Windows 驱动器
文档给出的标准示例是把 C 盘挂载到自定义挂载点:
mount -t drvfs C: /tmp/my-mount-point执行前注意两点:
- 目标挂载点目录需要已存在。
mount.drvfs内部会先校验目标目录是否可用,目录不存在时直接失败。 C:只是示例源,可替换为实际要挂载的 Windows 驱动器或路径。
命令成功时正常退出;失败时会在 stderr 输出形如mount: <错误描述>的信息,退出码非零。
mount -t drvfs实际执行了什么
这条命令并不是普通内核模块挂载,而是由 WSL 自带的一个入口处理的:
/usr/sbin/mount.drvfs是指向/init的符号链接。/init启动后根据argv[0]判断要运行哪个入口点:当argv[0]是mount.drvfs时,/init执行mount.drvfs入口(见 MountDrvfsEntry())。- 根据发行版配置,
mount.drvfs会把驱动器挂载为drvfs(WSL1),或plan9、virtio-plan9、virtiofs(WSL2),具体取决于.wslconfig。也就是说,用户侧命令始终是mount -t drvfs,底层实际的文件系统类型可能不同。 - 参数个数不足 3 个(缺少源和目标)时按错误用法处理,退出码为 1;挂载失败时退出码为 32(见 exit code 常量定义)。
- 在 WSL2 的 plan9 路径下,以
/或\开头的 UNC 风格源路径会被转换后通过 plan9 协议挂载(见 MountPlan9)。 - 当配置为 virtiofs 时,若向宿主添加 virtiofs 共享失败,实现会自动回退到 Plan9 路径完成挂载(见 MountVirtioFs)。
提权与非提权挂载点的区别
这是理解手动挂载行为的关键部分,机制描述来自 drvfs.md:
- WSL 在发行版内部区分从提权(管理员级)上下文创建和从非提权(用户级)上下文创建的 Linux 进程。实现方式是发行版内存在两个独立的 mount namespace:一个提供对 Windows 驱动器的提权访问,另一个提供非提权访问。
- 当某个 Linux 进程被创建时,
wslservice.exe判断其提权状态,并通知init在相应的 mount namespace 中创建该进程。 - 发行版创建时,
wslservice.exe通过LX_INIT_CONFIGURATION_INFORMATION消息告知创建该发行版的进程是否提权,init据此先挂载提权版或非提权版的 plan9 服务器。 - 之后,当未挂载的那个命名空间中创建第一条命令时,
wslservice.exe会向init发送LxInitMessageRemountDrvfs消息,让init补挂另一个命名空间。即另一侧的挂载点是按需延迟挂载的,而不是启动时就同时存在。 - 在 virtiofs 场景下,两个服务器分别对应 tag
drvfs(非提权)和drvfsa(提权),定义见 lxinitshared.h。 mount.drvfs入口在没有被显式指定时使用哪个服务器由 IsDrvfsElevated() 决定:它先检查环境变量WSL_DRVFS_ELEVATED,取值为1时强制使用提权服务器,0时强制使用非提权服务器;未设置该变量时,通过 interop 服务器查询当前上下文应使用的端口;若无法建立该连接,则回退到非管理员 DrvFs 端口。该环境变量在发行版启动早期 interop 服务器尚未就绪时也会由 init 使用(定义见 util.h)。
对你的实际影响是:同一个mount -t drvfs C: <目标>命令,在不同提权状态下执行时,连接的是不同的 plan9/virtiofs 服务器实例,获得的驱动器访问权限级别也相应不同。
如何判断挂载成功或失败
- 退出码 0 表示挂载成功;1 表示用法错误(参数不足);32 表示挂载失败。
- 失败时观察 stderr:
mount.drvfs会输出mount: <strerror>形式的错误行。 - 若怀疑是 Windows 侧问题(例如
/mnt共享访问异常),可查看Microsoft.Windows.Plan9.Server日志,这是 Windows plan9 服务的日志,用于访问/mnt/共享相关场景,说明见 debugging.md。
限制与适用边界
- “创建 session leader 时启动 plan9 文件服务”这一小节仅适用于 WSL2 发行版;WSL1 发行版的
mount.drvfs直接以drvfs文件系统类型挂载。 - 手动挂载的前提是 Windows plan9 服务在运行,且发行版内
init正常工作;发行版的挂载相关行为见 init.md。 - 涉及 WSL2 虚拟机与发行版之间挂载交互的服务端逻辑位于 WslCoreInstance.cpp,Linux 侧实现位于 src/linux/init/drvfs.cpp,可供进一步阅读。
【免费下载链接】WSLWindows Subsystem for Linux项目地址: https://gitcode.com/GitHub_Trending/ws/WSL
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考