萌约 MoeYork

一个普通的博客站点

0%

WSL 2 分离式 home 挂载

最近清理WSL2发行版的磁盘,发现大部分空间都被/home占用,所以决定用独立的vhdx磁盘作为/home挂载到发行版里

关于 WSL 2 架构

WSL 2 架构可以参考wsl.dev,微软于25年5月19开源了 WSL 2 大部分组件。

WSL 2 内核运行在一个使用[HCS API](Host Compute System Overview | Microsoft Learn)创建的隐藏虚拟机里,各发行版实际上是通过namespace隔离的容器。在内核启动后,WSL 进入其预制的WSLg System Distro中,加载各已安装发行版的磁盘,并将其挂载到各发行版的mount namespace中(这里写死了是ext4,所以应该是没法去改根目录文件系统的)。

PS:所有发行版共用同一个network namespace

可以通过下面的命令进入system distro:

1
wsl --system

还可以以root权限进入:

1
wsl --debug-shell

关于 VHD/VHDX

还得是 VHDX

VHD/VHDX有三个很有用的特性:

  • 动态VHD: 支持空间调整
  • 稀疏VHD: 支持自动回收空间
  • 父子VHD: 类似overlayfs

常用的管理命令:

1
2
3
4
5
# 设置动态VHD大小
Resize-VHD

# 压缩动态VHDX空间
Optimize-VHD

关于挂载

  • WSL2 所有发行版共享同一个内核,通过wsl --mount --vhd --bare <vhd path>挂载的磁盘同时对所有发行版可见
  • Linux 从 2.4 开始就支持把一个文件系统挂在多个挂载点上,或者在一个挂载点上挂多个文件系统
  • mount --bind可以挂载一个目录到另一个目录(与挂载点不同,可以是非空目录,且同样可以被挂载多次)

关于稀疏 VHD (SparseVHD)

稀疏VHD实际上是NTFS的稀疏文件,它需要通过特殊的ioctl设置,通过特殊API写入全0数据时可以回收磁盘空间。但是被WSL加了警告

操作过程

分离/home到 VHDX

这里笔者选择了 btrfs,创建了一个空白vhdx,作为/dev/sdxx临时挂载在/mnt/home

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 创建子卷结构
sudo mount /dev/sdxx /mnt/home
sudo btrfs subvolume create /mnt/home/@home
sudo btrfs subvolume create /mnt/home/@.snapshots
sudo umount /mnt/home

# 复制已有的/home
sudo mount -t btrfs -o subvol=/@home /dev/sdxx /mnt/home
sudo rsync -aXS /home/ /mnt/home
sudo umount /mnt/home

# 挂载到/home
sudo mv /home /home_old
sudo mount --mkdir -t btrfs -o subvol=/@home /dev/sdxx /home

自动挂载配置

在上面配置完后其实就已经可用了,但是WSL再次冷启动时之前挂载的VHDX并不会自动挂载,挂载上了磁盘也需要手动挂载/home,所以还需要进行自动挂载的配置。这里利用了WSL 2内置的systemd进行自动挂载:

在发行版/etc/wsl.conf中进行以下配置:

1
2
[automount]
mountFsTab=false # 因为在加载发行版时还没有挂载vhdx,所以需要推迟到systemd引导过程中

创建/usr/lib/systemd/system/wsl-automount.service

其中VHDX路径为"C:\\Users\\UserName\\AppData\\Local\\wsl-home\\home.vhdx"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[Unit]
Description=WSL2 Auto Mount
After=systemd-binfmt.service systemd-udevd.service
Requires=systemd-binfmt.service
Before=home.mount
DefaultDependencies=no

[Service]
Type=oneshot
ExecStart=/bin/sh -c '/mnt/c/Windows/System32/wsl.exe --mount --vhd --bare "C:\\Users\\UserName\\AppData\\Local\\wsl-home\\home.vhdx" || true'
StandardOutput=null
StandardError=null
RemainAfterExit=yes
TimeoutStopSec=5

[Install]
WantedBy=basic.target

创建/usr/lib/systemd/system/home.mount

使用lsblk -f查看磁盘UUID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=Mount VHD Filesystem
After=wsl-automount.service
Requires=wsl-automount.service
Before=shutdown.target
Conflicts=shutdown.target
DefaultDependencies=no

[Mount]
What=UUID=a936001a-3044-4285-8a4a-8be821931f08
Where=/home
Type=btrfs
Options=compress=zstd,noatime,subvol=/@home

[Install]
WantedBy=basic.target

创建'/usr/lib/systemd/system/\x2esnapshots.mount'

快照目录,记得创建/.snapshots

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[Unit]
Description=Mount VHD Filesystem @.snapshots
After=wsl-automount.service
Requires=wsl-automount.service
Before=shutdown.target
Conflicts=shutdown.target
DefaultDependencies=no

[Mount]
What=UUID=a936001a-3044-4285-8a4a-8be821931f08
Where=/.snapshots
Type=btrfs
Options=compress=zstd,noatime,subvol=/@.snapshots

[Install]
WantedBy=basic.target

可以wsl --shutdown后等待8s,重启wsl检查效果


评论