WSL に Ubuntu 26.04 が来てたので新規インストールして 24.04 からファイルの引継ぎをしていたのですが、ディストロ間のファイルの移動って結構めんどくせえなあと思い、この機に共有ディスク領域を整備してみました。
あと WSL の環境って wsl --unregister ... で中にあるデータごとまとめて簡単に吹っ飛ばせてしまうのが怖いなあと常々思っていたので、今回移行が必要になったような WSL 内の大事なファイルとかは今後ここに置いていこうかと思っています。これで 28.04 が来ても気楽にクリーンインストールできるね!
実施時環境
- Windows 11 Pro 25H2
- WSL 2.7.10.0
- Ubuntu 24.04 LTS
- Ubuntu 26.04 LTS
仮想ディスクを作成して1回だけマウントするところまでは古い Windows でも出来るかもしれませんが、今回行う自動マウントの仕組みの構築は Windows 11 が必須らしいです。
仮想ディスクを作成する
Windows に付いてるディスク管理ユーティリティを使います。
-
ディスクの管理を起動する(Win + Rからdiskmgmt.mscで起動できる) - メニューバーから
[操作(A)] - [VHDの作成]で仮想ハードディスクの作成と接続ダイアログを開く - ダイアログに必要な内容を入力する
-
[OK]を押下して仮想ディスクの作成を実行 - 画面下のペインを下の方にスクロールすると今作成した仮想ディスクが見つかる
- 左側の「不明」とか「初期化されていません」とか書いてあるところを右クリックして
[VHD の切断]を選択 -
仮想ハードディスクの切断確認ダイアログが出てくるので[OK]を押下 - 先ほど右クリックしたディスクが一覧から居なくなってれば完了
以降、この記事において VHDX ファイルは D:\wsl-data.vhdx に作成したものとします。別の場所を指定した場合は適宜読み替えてください。
(おまけ)PowerShell で作成する
上の操作は PowerShell で New-VHD が使えるなら
New-VHD -Path "D:\wsl-data.vhdx" -SizeBytes 2TB -Dynamic
とかで一発で完了するようです。
僕の環境には New-VHD がなく、追加モジュールのインストールが必要そうだったので試しませんでした。
仮想ディスクを接続してフォーマットする
仮想ディスクを接続する
- WSL のコンソールで
lsblkを実行し、ブロックデバイスの一覧を確認する - 管理者権限のコマンドプロンプトか PoweShell で
wsl --mount "D:\wsl-data.vhdx" --vhd --bareを実行し、先ほど作成した仮想ディスクを WSL に接続する - WSL のコンソールで再度
lsblkを実行し、増えた項目を見つけて接続した仮想ディスクのデバイス名を特定する(普通は一番下にあると思う)
ここで判明したデバイス名は次以降の作業で使うので覚えておくこと。以降、この記事では便宜上 sdX だったものとします。
仮想ディスクをフォーマットする
WSL のコンソールで
sudo mkfs.ext4 -L "wsl-data" /dev/sdX
を実行する。sdX の部分は必ず先ほど判明した仮想ディスクの名前を指定すること。間違えた名前を指定すると既存のデータが消去されるため慎重に実施すること。
またコマンドではラベルに -L "wsl-data" を指定しているが、実際は自分が分かりやすい好きな名前を付けてあげるとよい。
(確認)作成した仮想ディスクが複数のディストロで共有できることを確認する
複数の WSL のディストロのコンソールでそれぞれ
sudo mkdir -p /mnt/data
sudo mount -t ext4 /dev/sdX /mnt/data
を実行し、/mnt/data に何かファイルを置いてみてディストロを跨いで共有されていることを確認する。今回は Ubuntu 24.04 と Ubuntu 26.04 でこのマウントポイントを通じてファイルのやり取りができることを確認しました。
WSL の起動時に仮想ディスクが自動マウントされるようにする
共有のファイルシステムは構築できましたが、このままだと WSL がシャットダウンする度に見えなくなってしまいます。最近の WSL だとコンソールが1つも開いてないとかの状態がしばらく続くと VM アイドルと判定されて自動的にシャットダウンしてくれたりしますね。地味に迷惑なことが多い
WSL には自動マウントの機能が無いようですが、GitHub の issue に workaround を投稿されている方が居たので、それを真似して自動マウントの仕組みを作っていきます。
https://github.com/microsoft/WSL/issues/6073#issuecomment-1266405095
仮想ディスクを WSL に接続するタスクを Windows 側で作成する
-
タスク スケジューラを起動する(Win + Rからtaskschd.mscで起動できる) - メニューバーから
[操作(A)] - [タスクの作成(R)...]でタスクの作成ダイアログを開く - ダイアログに必要な内容を入力する
-
[OK]を押下してタスクの作成ダイアログを完了する
管理者権限で wsl --mount "D:\wsl-data.vhdx" --vhd --bare をしてくれるタスクが出来ました。元の投稿によると、わざわざタスク化するモチベーションは UAC ダイアログの回避のためとのことです。
今回はタスク名を wsl-mount としましたが、別の名前を付けた場合は以降の内容を適宜読み替えてください。
WSL の起動時に仮想ディスクをマウントするスクリプトが実行されるようにする
ここが先ほどの方が発明した workaround の肝です。WSL の起動時に特定のスクリプトが実行されるように設定し、そのスクリプトの中で先ほど作った Windows のタスクをキックして仮想ハードディスクを接続させます。コンテナの中で実行されるスクリプトがコンテナの外に居る Windows のタスクをキックするのが面白いですね。
WSL がシャットダウン状態だと仮想ディスクを接続しようとしても失敗するので、WSL 起動 -> 仮想ディスク接続の順序を守るためにこのような回り込みを行っているのだと思います。
以降の編集は仮想ディスクを自動マウントさせたいすべてのディストロでそれぞれ行ってください。
/etc/wsl.conf
まず /etc/wsl.conf の boot セクションに command="bash /boot.sh" を追記します。
[boot]
command="bash /boot.sh"
これで起動時に /boot.sh に置いたスクリプトが実行されるようになります。
元から書かれていた内容や他のセクションは消さないでください。参考までに僕の環境でインストールしたばかりの Ubuntu 26.04 における編集後の wsl.conf は以下のようになりました。
[boot]
systemd=true
command="bash /boot.sh"
[user]
default=akima
※ akima は僕の名前です。
/boot.sh
次に /boot.sh を作成します。
#!/bin/bash
/bin/bash /wsl-boot.sh > /wsl-boot.log 2>&1
sudo chmod +x /boot.sh
元記事に従い、ここでは直接仮想ディスク関係の処理は行わず /wsl-boot.sh というスクリプトに移譲しています。
/wsl-boot.sh
最後に /wsl-boot.sh を作成しますが、その前に仮想ディスクの UUID を調べておきます。
sudo blkid /dev/sdX
で表示される UUID="..." の部分を確認してください。sudo を忘れたりデバイス名を間違えると何も表示されません。
その後、/wsl-boot.sh を作成し、<仮想ディスクのUUID> の部分は調べた値に置き換えてください。
#!/bin/bash
/mnt/c/Windows/system32/schtasks.exe /run /tn "wsl-mount"
VHDX_MP='/mnt/data'
VHDX_UUID='<仮想ディスクのUUID>'
mkdir -p "$VHDX_MP"
if mountpoint -q "$VHDX_MP"; then
exit 0
fi
i=0
while :; do
dev=$(blkid -U "$VHDX_UUID")
if [ -n "$dev" ]; then
break
fi
i=$((i + i))
if [ "$i" -ge 5 ]; then
echo "No device found for '$VHDX_UUID'" 1>&2
exit 1
fi
sleep 1
done
mount -t ext4 "$dev" "$VHDX_MP"
/mnt/c/Windows/system32/schtasks.exe で Windows 側のタスクスケジューラのバイナリを強引に呼び出していますね。なんで Ubuntu の端末で PE フォーマットが実行できるのかは知らないけど、そういうものらしい。
このスクリプトは元記事のものから僕が手を入れています。元記事では Windows タスクで定義する wsl の引数に --bare ではなく --name data を指定して一発でファイルシステムへのマウントまで済ませることを想定しているように見えますが、これを試したところ結構な確率で「/dev/sdX にデバイスはいるが /mnt/wsl/data にはマウントされていない」という中途半端な状態になることがありました。
僕のスクリプトでも sleep 1 をしながら5回までデバイスの発見を試行していますが、これをやらないと結構失敗することがあります。多分 --name data オプションが上手く行かないのも同じ理由なんじゃないかと推測します。


