WSL挂载虚拟磁盘完整步骤

思路概要

在我实际操作的环境下(win10+WSL2), 给WSL2挂载虚拟磁盘本质只有两步:

  • 一是在Windows侧创建虚拟磁盘文件(下文简称vhdx文件)并执行一把格式化, 此后vhdx文件和Windows系统关系就不大了,就像一个普通文件一样躺在磁盘里.
  • 二是在WSL启动时通过vhdx文件路径将其挂载进WSL系统.

创建虚拟磁盘并配置权限

创建

方式一: 在磁盘管理器中创建VHD

磁盘管理->操作->创建VHD->确定.vhdx文件路径->...
注意: 创建完后, 右键VHD磁盘选择分离VHD, 使其在Windows磁盘管理器中不可见, 否则无法挂载进WSL,会提示vhdx文件被其他进程占用.

方式二: 管理员PowerShell创建

new-vhd -Dynamic -SizeBytes 100gb -BlockSizeBytes 1mb -path E:\data_in_wsl.vhdx
此方式创建的虚拟磁盘默认已是分离状态,在Windows磁盘管理中不可见.

配置权限

.vhdx文件->属性->安全->编辑->给Authenticated Users勾上完全控制.
如果没有此步骤在后面WSL启动时执行wsl --mount时会报没有权限访问.vhdx文件的错误.

格式化虚拟磁盘

  1. 手动把vhdx挂载进WSL
    windows端powershell管理员模式执行: wsl --mount --vhd "E:\data_in_wsl.vhdx" --bare
  2. 在wsl内对新增磁盘进行格式化
    lsblk   # 找到新增磁盘,比如/dev/sdb, 可通过挂载状态+磁盘大小判断哪个是新增的
    sudo mkfs.ext4 /dev/sdb  # 格式化为ext4
    

实现WSL重启后自动挂载(主机是否重启没有区别)

在WSL内创建WSL启动时执行挂载的脚本
  • 新建/home/.wsl_vhdx_automount.sh用于执行挂载动作, 内容如下(添加执行权限):
    • 对挂载点无特殊需求, 让wsl执行默认挂载行为, 默认挂载在/mnt/wsl/<name>
      #!/bin/bash
      
      if ! mount | grep -q '/home/data_vhdx'; then # 防止开多个terminal时多次执行
      	powershell.exe -Command 'wsl --mount  --vhd "E:\data_in_wsl.vhdx" --name "data_vhdx" ' > /dev/null
      	sleep 1    # 等块设备出来
      fi
      
    • 对挂载点有要求,比如我要挂在到/home/data_vhdx目录下,则可参考下面这种写法:
      #!/bin/bash
      
      if ! mount | grep -q '/home/data_vhdx'; then
      	powershell.exe -Command 'wsl --mount --bare --vhd "E:\data_in_wsl.vhdx"' > /dev/null
      	sleep 1    # 等块设备出来
      	sudo mkdir -p /home/data_vhdx
      	sudo mount /dev/sdc /home/data_vhdx
      fi
      
  • 设置WSL启动后自动执行/home/.wsl_vhdx_automount.sh
    • win11: 通过在/etc/wsl.conf中的boot/command设置WSL开机自动执行/home/.wsl_vhdx_automount.sh即可(会自动用root用户执行,其实这种场景下挂载动作和terminal会话应该就没关系了, 开多个terminal不会多次挂载,脚本内容可简化,但我不是win11无法测试)
      [boot]
      command = "/home/.wsl_vhdx_automount.sh"
      
    • win10: 不支持boot/command配置, 需要将脚本放在shell会话启动中执行,比如加在/etc/profile或者~/.bashrc 等文件末尾

      如果是对挂载点有要求的场景此时会出现一个问题,脚本中涉及执行sudo操作, 非root用户是要输入密码的, 每次WSL刚启动第一次进去就需要输入一次密码, 变麻烦了, 解决办法是在给脚本中用到的sudo命令添加免除密码配置:sudo visudo 在末尾添加:

      <username> ALL=(ALL) NOPASSWD: /usr/bin/mkdir -p /home/data_vhdx
      <username> ALL=(ALL) NOPASSWD: /bin/mount /dev/sdc /home/data_vhdx
      

FAQ

  1. 手动挂载vhdx时遇到.vhdx文件被其他进程占用怎么回事?

    windows端主动卸载vhdx:Dismount-VHD -Path "C:\wsl_ext4.vhdx"或者在Windows磁盘管理器中对VHD执行分离操作.

  2. 手动挂载vhdx时遇到Error code: Wsl/Service/AttachDisk/MountVhd/HCS/E_ACCESSDENIED

    权限问题, .vhdx文件->属性->安全->编辑->给Authenticated Users勾上完全控制.

  3. 有很多网页中都提到了使用PowerShell中的相关命令查找磁盘ID,然后利用ID再挂载到WSL的步骤, 为什么这里没有相关内容?

    我在搜索资料时确实看到了相关内容,但综合了大家的方法后我发现在当前的版本(win10+WSL2)下, 挂载虚拟磁盘只需要指定虚拟磁盘的vhdx在Windows中的具体路径即可, 并不需要虚拟磁盘的物理ID, 而且通过路径去指定磁盘只简单直观.已在win10+WSL2测试没问题.

  4. 挂载磁盘时的 --bare参数是什么意思?

    经过一番折腾之后我理解这个--bare参数的意思让WSL看到磁盘(vhdx文件)但不要自动去mount, 之后用户可以在WSL内部自己mount, 这在想要自行觉得mount位置的时候有用, 而如果不加--bare参数则WSL会自动挂载磁盘到系统目录, 如果有--name参数则根据name参数挂载到/mnt/wsl/<name>下,如果没有name参数就会由WSL自己生成一个name去挂载.

posted @ 2025-04-29 20:38  龙龙不瞎浪  阅读(1380)  评论(0)    收藏  举报