btrfsのディスクファイルを作ってWSL2にマウントする
OSのvhdxファイルのサイズを少しでも減らすため、OS本体とは別にbtrfsなディスクファイルを作ってそこに入れる。
最新のWSL2には、vhd/vhdxファイルを直接マウントできる --vhd オプションが追加されてより楽になっている。 (2025/5 時点)
/proc/filesystems にあるファイルシステムならマウントできるらしい
Get started mounting a Linux disk in WSL 2 | Microsoft Learn
New-VHDの実行には、事前に「Windows の機能の有効化または無効化」で「Hyper-V」→「Hyper-V 管理ツール」→「Windows PowerShell 用 Hyper-V モジュール」と「Hyper-V」→「Hyper-V プラットフォーム」→「Hyper-V サービス」を有効にする必要がある
PC再起動は不要
code:powershell
# vhdxを作成 (これだけ管理者権限が必要)
New-VHD -Path "C:\foo\bar.vhdx" -SizeBytes 4GB -Dynamic -BlockSizeBytes 1MB
# ディスクごとマウント
wsl --mount "C:\foo\bar.vhdx" --vhd --bare
code:bash
# マウントされた sdX を確認 (sdc, sdd など)
lsblk
# ディスク全体をbtrfsでフォーマット
sudo apt install btrfs-progs
sudo mkfs.btrfs -L ラベル /dev/sdX
vhdxファイル作成時に -BlockSizeBytes 1MB を設定していた場合、この時点でvhdxファイルのサイズは12MBくらい
code:powershell
# マウント解除
wsl --unmount "C:\foo\bar.vhdx"
# btrfs,圧縮ありで /mnt/wsl/マウント名 にマウント
wsl --mount "C:\foo\bar.vhdx" --vhd --name マウント名 --type btrfs --options "noatime,compress-force=zstd"
code:bash
# 所有者がrootになっているので自分に変更する
cd /mnt/wsl/マウント名
sudo chown $USER:$USER .
自動マウントしたい場合、 wsl.exe --mount を自動実行するのが一般的っぽい。
雑に .bashrc とか .profile とかに記載する方法
https://zenn.dev/dozo/articles/97c539708842ca
code:sh
if ! -d /mnt/wsl/マウント名 ; then
/mnt/c/Windows/System32/wsl.exe --mount 'C:\foo\bar.vhdx' --vhd --name マウント名 --type btrfs --options "compress-force=zstd" 2>/dev/null >/dev/null
fi
/etc/wsl.conf にブート時のコマンドを指定
https://qiita.com/yynet2022/items/4030bcb448cabd9eb081#追加した-ext4vhdx-の自動マウント設定
自分の場合、/etc/wsl.confを以下のようにして、wsl-boot.shに上記マウントコマンドを記載している。
code:/etc/wsl.conf
boot
systemd=true
command=bash /home/user/wsl-boot.sh
wsl-boot.sh の内容: btrfsのディスクファイルを作ってWSL2にマウントする#691fbf170000000000d275bd
複数回 (自分の場合は4回以上) マウントする時、以下のエラーが出てマウントできないことがあった。
code:txt
/home/user/wsl-boot.sh: line 27: /mnt/c/Windows/System32/wsl.exe: cannot execute binary file: Exec format error`
自分の場合、最初のmountの前に sleep 1 を入れることで解消。原因は不明
圧縮が有効になってるか雑に確認。
code:sh
cd /mnt/wsl/マウント名
dd if=/dev/zero of=500MB_file bs=1M count=500
vhdxファイルのサイズが500MB未満なことを確認。
他
vhdxファイルのサイズを減らしたい時
code:sh
# wsl側で2回くらい実行
sudo fstrim /mnt/wsl/マウント名
# PowerShell側でもwsl側でも (wsl側で叩くなら wsl.exe)
# アンマウントを実行 (wsl --shutdown でも可)
wsl --unmount "vhdxファイルパス"
# 管理者権限をもつPowerShellで
# 2回くらい実行
Optimize-VHD -Path "vhdxファイルパス" -Mode full
「2回くらい」には特に根拠はないが、1回だと減らないことがあった(謎)
参考
WSLにデータ移行用の仮想ディスク(VHDX)をマウントする #WSL2 - Qiita(shioccii)
WSL で仮想ハードディスクを追加してみた(速度比較もしてみた) #Linux - Qiita(yynet2022)
WSLのOS引っ越しでvdhxファイルを自動マウント (zenn.dev/dozo)
compress-force オプションについて
BtrfsでZstdの圧縮をする際のマウントオプションでcompressにするかcompress-forceどっちにするかの比較 - みくにまるのブログ
btrfsのファイル損壊現象に遭遇し解決したので備忘録として残しておきます。 #Linux - Qiita(oltWnKXcD89LapBt)
discardオプションについて
Trim/discard — BTRFS documentation
btrfs(5) — BTRFS documentation
BlockSize をデフォルトの32MBでなく1MBに明示的に設定するよう勧めているMicrosoftの記事
Best Practices for running Linux on Hyper-V | Microsoft Learn
Btrfs - ArchWiki
Btrfs - Debian Wiki
NOTE: Using "-o discard" with btrfs is unsafe when compared with fstrim.
注記: btrfs で "-o discard" を使用することは、fstrim と比較すると安全ではありません。
デフラグするとサイズが大きくなる例が報告されている
圧縮すら推奨されてない。。。
現時点(2025-04-17)では、fstab で圧縮レベル 1 に設定された zstd (zstd:1) がおそらく最もよくテストされています。
デフォルト (zstd) だと圧縮レベル3
メモ
code:/home/user/wsl-boot.sh
#!/usr/bin/bash
# 事前に /tmp 以外のログ出力用フォルダを作っておいて出力
# (/tmp はboot command実行中ちゃんと出力されてないか出力された後消えてるかで後から確認できないことがあるっぽいので)
rm -f /tmp2/wsl-boot.log
echo "wsl-boot.sh log $(LANG=c date)" > /tmp2/wsl-boot.log
# sleepなしだと、4回目以降のmountが「/home/user/wsl-boot.sh: line 27: /mnt/c/Windows/System32/wsl.exe: cannot execute binary file: Exec format error」で失敗する
sleep 1
function run {
if ! -d /mnt/wsl/dir1 ; then
/mnt/c/Windows/System32/wsl.exe --mount 'C:\_\vm\vhd\dir1.vhdx' --vhd --name dir1 --type btrfs --options "compress-force=zstd,noatime"
fi
if ! -d /mnt/wsl/dir2 ; then
/mnt/c/Windows/System32/wsl.exe --mount 'C:\_\vm\vhd\dir2.vhdx' --vhd --name dir2 --type btrfs --options "compress-force=zstd,noatime"
fi
# ...
}
# 日本語版Windowsのwsl.exeはUTF-16で出力するようなので変換
run 2>&1 \
| iconv -f utf-16 -t utf-8 \
>/tmp2/wsl-boot.log
mkfs.btrfs コマンドの出力
code:log
btrfs-progs v6.6.3
See https://btrfs.readthedocs.io for more information.
Performing full device TRIM /dev/sde (4.00GiB) ...
NOTE: several default settings have changed in version 5.15, please make sure
this does not affect your deployments:
- DUP for metadata (-m dup)
- enabled no-holes (-O no-holes)
- enabled free-space-tree (-R free-space-tree)
Label: foodrv
UUID: 2491cfe5-f2f7-46ff-9c6c-cf2ec43aa2d0
Node size: 16384
Sector size: 4096
Filesystem size: 4.00GiB
Block group profiles:
Data: single 8.00MiB
Metadata: DUP 256.00MiB
System: DUP 8.00MiB
SSD detected: no
Zoned device: no
Incompat features: extref, skinny-metadata, no-holes, free-space-tree
Runtime features: free-space-tree
Checksum: crc32c
Number of devices: 1
Devices:
ID SIZE PATH
1 4.00GiB /dev/sde