本サイトは広告・アフィリエイトプログラムにより収益を得ています
WSL 3.0.1がリリースされたので、/mnt/cをvirtiofsに切り替えてPlan9との速度差を測ってみた

WSL 3.0.1がリリースされたので、/mnt/cをvirtiofsに切り替えてPlan9との速度差を測ってみた

スポンサーリンク

2026年9月29日、WSL 3.0.1がリリースされました。目玉はLinuxコンテナをWindowsで直接動かせる「WSL containers(WSLc)」が一般提供開始されたことでしょうか。

Windows Subsystem for Linux. Contribute to microsoft/WSL development by creating…
github.com
WSL is central to our commitment to making Windows the best place to build, run …
blogs.windows.com

僕が気になっていたのは、実はコンテナよりもWindows側のドライブとの共有方式のほうなんです。

WSLでは、.wslconfigにvirtiofs=trueと書くと、Windows側のドライブ(/mnt/c)の共有方式を従来のPlan9からvirtiofsに切り替えられます。

ただ、2.7系ではドライブの自動マウントがまとめてスキップされる不具合(#40773)などがIssueにあったので、僕はしばらくPlan9のまま使っていました。

その#40773の修正は、プレリリースを除くと2.7 系には取り込まれていませんでした。

ですが3.0.1にはこの修正が取り込まれたので、そろそろvirtiofsに切り替えてもいいのでは?と思い、手元の環境で試してみました。

本記事では、既存環境をWSL 3.0.1にアップデートする手順と、/mnt/cをvirtiofsに切り替える方法、Plan9とvirtiofsでディスクI/Oにどの程度の差があるのかをまとめます。あわせて、3.0.1の新機能も簡単に紹介します。

WSL 3.0.1の新機能

「WSL 3」になったけど中身はWSL2と同じ

まず誤解されそうな点から。「WSL 3.0」はWSLのパッケージのバージョン番号で、軽量VMの上でLinuxカーネルを動かす仕組みはWSL2と変わりません。

wsl --set-versionで選ぶ「WSL1/WSL2」とは別の話なので、既存のディストリをそのまま使えます。

uname -rで表示されるカーネルも「6.18.40.1-microsoft-standard-WSL2」で、WSL2のままでした。

WSL containers(WSLc)が一般提供に

3.0.1の目玉はこちらです。wsl --updateで3.0.1に上げると、新しくwslc.exeコマンドが使えるようになります。

wslc.exeはコンテナのビルド・実行・デプロイを行うCLIで、container.exeという別名でも呼び出せます。

ネイティブのWindowsアプリからLinuxコンテナを操作するためのAPI(WSL containers API)も用意されました。

GAのタイミングで追加されたコマンドは以下のとおりです。

  • wslc container restart(実行中のコンテナの再起動)
  • wslc container cp(ファイルのコピー)
  • wslc system info(環境の状態表示)
  • wslc network connect/wslc network disconnect(ネットワーク接続の管理)
  • wslc events(アクティビティのリアルタイム監視)

このほか、コンテナのヘルスチェックにも対応しており、記事公開段階ではVS Code Dev ContainersやMicrosoft Aspireもwslcに対応しています。

情シス目線で気になるのは、Microsoft IntuneにWSL containersの有効/無効を切り替える設定と、イメージの取得元を承認済みのレジストリに絞る設定が追加された点です。

Microsoft Defender for Endpointとも連携していて、セキュリティ担当がコンテナの動きを調査できるとのこと。

特に、Docker Desktopの有償ライセンスが気になっていた組織にとっては、選択肢の1つになるんじゃないかなぁと思います。

なおIntuneでの制御については、構成プロファイルの設定カタログから、「Windows Subsystem For Linux」を追加すると下記2項目が選択できます。

  • Allow WSL container
    • WSL経由でLinuxコンテナーを実行できるかどうかを制御します。
    • WSL自体を有効/無効とする設定値ではないため注意が必要です。
      • ADMXのインポートからWSL ADMX fileをインポートして設定します。
  • Allowlist for WSL container registers
    • このポリシーを有効化すると、WSLコンテナーまたはWSLコンテナーのAPIを使うすべてのアプリケーションでイメージを取得できるレジストリを指定したもののみに制限できます。

一方で、要望の多いcompose対応はまだで、次の優先事項としてロードマップに挙がっている段階です。既存のcompose.yamlをそのまま使いたい方は、もう少し待つ必要がありそうです。

WSLcのアーキテクチャについては、Windows Command Lineブログで詳しく解説されています。

WSL containers is now generally available! Check out this blog post to learn mor…
devblogs.microsoft.com

WSLcは僕もまだ触れていないので、実際に試したら別の記事で紹介する予定です。

virtiofsとPlan9は何が違うのか

WSL2のディストリからWindows側のドライブ(/mnt/cなど)にアクセスするとき、従来はPlan9(9P)というファイル共有プロトコルが使われてきました。

/mnt/cの上でgitやnpmを動かすと極端に遅い、というのはWSL2を使っている人なら一度は経験があるのではないでしょうか。

virtiofsはVMとホストの間でファイルシステムを共有するための仕組みで、Plan9よりも高速に動作するとされています。

前述のWSLcの解説記事でも、コンテナのボリュームマウントにvirtiofsを採用した理由として「plan9と比べて約2倍速い」と書かれています。

ただしこれはWSLcのボリュームの話で、ディストリの/mnt/cについての数字ではありません。なので、実際に/mnt/cで測ってみることにしました。

なお、virtiofsのオプトイン設定(.wslconfigのvirtiofs)は、WSLがオープンソース化された時点で既にに存在していたので、WSL 3.0.1導入前でも設定しようと思えば設定できました。

既存環境をWSL 3.0.1にアップデートする

アップデート手順

ここからは手元のノートPC(Windows 11 on ARM)での作業してみます。

管理者権限のPowerShellで、現在のバージョンを確認してからwsl --updateを実行しました。

PS C:\Users\syobon\work> wsl -v
WSL バージョン: 2.7.10.0
カーネル バージョン: 6.18.33.2-2
WSLg バージョン: 1.0.73.2
MSRDC バージョン: 1.2.6676
Direct3D バージョン: 1.611.1-81528511
DXCore バージョン: 10.0.26100.1-240331-1435.ge-release
Windows バージョン: 10.0.28000.2525
PS C:\Users\nagao-sotaro\work> wsl --update
更新プログラムを確認しています。
Linux 用 Windows サブシステムをバージョン 3.0.1 に更新しています。
PS C:\Users\syobon\work> wsl -v
WSL バージョン: 3.0.1.0
カーネル バージョン: 6.18.40.1-1
WSLg バージョン: 1.0.79
MSRDC バージョン: 1.2.7214
Direct3D バージョン: 1.611.1-81528511
DXCore バージョン: 10.0.26100.1-240331-1435.ge-release
Windows バージョン: 10.0.28000.2525

更新前後で変わったのは以下の項目です。

項目更新前更新後
WSL2.7.10.03.0.1.0
カーネル6.18.33.2-26.18.40.1-1
WSLg1.0.73.21.0.79
MSRDC1.2.66761.2.7214
Direct3D/DXCore/Windows変化なし変化なし

アップデート後はwsl --shutdownでVMを止めてから、ディストリを起動し直しておきます。

wsl --shutdown後にディストリを起動してuname -rを実行し、カーネルが6.18.40.1になっていることを確認しました。

アップデートしただけでは/mnt/cはPlan9のまま

3.0.1に上げたあとで、/mnt/cのマウント状態を確認してみます。

syobon@ichika:~$ mount | grep /mnt/c
C:\ on /mnt/c type 9p (rw,noatime,aname=drvfs;path=C:\;uid=1000;gid=1000;symlinkroot=/mnt/,cache=0x5,access=client,msize=65536,trans=fd,rfd=6,wfd=6)

typeが9pなので、Plan9のままです。デスクトップPC(x86_64なWindows 11)でも同じ結果でした。

3.0.1のリリースノートにも、/mnt/cの共有方式を変更したという記述はありません。

WSLのソース(src/windows/common/WslCoreConfig.h)を見ても、EnableVirtioFsの既定値はfalseでした。

新規インストールした場合も確認しておきたかったので、Proxmox VE上に立てたWindows 11 26H2(OSビルド 26300.9457)のVMにWSLを入れてみました。

WSL未導入の状態でwsl -vを実行すると更新を促すメッセージが表示され、キーを押すとWSL 3.0.1のインストールと仮想マシンプラットフォーム(VirtualMachinePlatform)の有効化が自動で行われます。

再起動後にDebianを入れて確認したところ、こちらも/mnt/cはPlan9でした。

syobon@DESKTOP-BMKMVK4:/mnt/c/Users/user$ uname -r
6.18.40.1-microsoft-standard-WSL2
syobon@DESKTOP-BMKMVK4:/mnt/c/Users/user$ mount | grep /mnt/c
C:\ on /mnt/c type 9p (rw,noatime,aname=drvfs;path=C:\;uid=0;gid=0;symlinkroot=/mnt/,cache=0x5,access=client,msize=65536,trans=fd,rfd=6,wfd=6)

アップデートでも新規インストールでも、/mnt/cの既定はPlan9です。

virtiofsを使うには新規で構築した環境や既存環境にかかわらず、自分で.wslconfigに設定を書く必要があります。

余談 初回起動だけuid=0でマウントされる

上の出力をよく見ると、新規インストール直後の/mnt/cはuid=0;gid=0、つまりrootの所有としてマウントされています。デスクトップPCやノートPCではuid=1000だったので、あれ?と思ったんですよね。

その後、wsl --terminate Debianでディストリを再起動すると、uid=1000に変わりました。

PS C:\Users\user> wsl --terminate Debian
この操作を正しく終了しました。
PS C:\Users\user> wsl -d Debian
syobon@DESKTOP-BMKMVK4:/mnt/c/Users/user$ mount | grep /mnt/c
C:\ on /mnt/c type 9p (rw,noatime,aname=drvfs;path=C:\;uid=1000;gid=1000;symlinkroot=/mnt/,cache=0x5,access=client,msize=65536,trans=fd,rfd=6,wfd=6)

気になったので、WSL 3.0.1のソースで処理の順番を追ってみました。

  1. ディストリを登録した時点では、既定のユーザー(DefaultUid)はroot(0)になっている
  2. 初回起動時、WSLのサービスはその時点のDefaultUid(0)をinitに渡し、initはそのuidで/mnt/cをマウントする
  3. そのあとで初回セットアップ(ユーザー作成)が走り、/etc/wsl-distribution.confのdefaultUid(Debianでは1000)でDefaultUidが更新される。ただし、すでにマウント済みの/mnt/cはそのまま
  4. ディストリを再起動すると、更新後のDefaultUid(1000)でマウントされる

初回セットアップ直後のセッションだけの現象なので、実害はほとんどないと思います。

ただ、キッティング手順の中でディストリを入れて、そのまま/mnt/c配下のファイルを作るような流れだと所有者がrootに見えるので、一度wsl --terminateを挟んでおくと安心かもしれません。

(この動きは正直今まで意識していなかったので、個人的に今回の検証作業中で一番大きな成果でした。)

/mnt/cをvirtiofsに切り替える

.wslconfigに設定を書く

切り替えは簡単で、Windows側のユーザーフォルダにある.wslconfig(C:\Users<ユーザー名>.wslconfig)に以下を書くだけです。ファイルが無ければ新規に作成してください。

[wsl2]
virtiofs=true

保存したらwsl --shutdownでVMを止め、ディストリを起動し直します。

PS C:\Users\syobon\work> wsl --shutdown
PS C:\Users\syobon\work> debian
syobon@ichika:~$ mount | grep /mnt/c
drvfsa on /mnt/c type virtiofs (rw,noatime)

typeがvirtiofsになっていれば切り替え完了です。Plan9のときに表示されていたuidやgidなどのオプションは、virtiofsでは表示されなくなります。

元に戻したいときは、.wslconfigからvirtiofs=trueの行を消すかfalseにして、もう一度wsl --shutdownしてください。

ファイルの所有者を確認する

virtiofsでは、/mnt/c配下のファイルがroot所有に見えるというIssue(#40719)がOpenのままだったので、所有者も確認しておきました。

syobon@ichika:~$ ls -lnd /mnt/c/tmp
drwxrwxrwx 1 1000 1000 4096 Oct  3 01:18 /mnt/c/tmp
syobon@ichika:~$ touch /mnt/c/tmp/owner_test && ls -ln /mnt/c/tmp/owner_test
-rwxrwxrwx 1 1000 1000 0 Oct  3 01:33 /mnt/c/tmp/owner_test

UID/GIDともに1000で、手元の環境ではroot所有に見える症状は再現できませんでした。

Plan9とvirtiofsのディスクI/Oを比べてみた

検証方法

検証はノートPC(Windows11 on ARM)で、すべてWSL 3.0.1(カーネル 6.18.40.1)の状態で行いました。

主なスペックは以下の通りです。

  • モデル:Zenbook SORA UX3407RA(2025年モデル)
  • OS:Windows 11 Pro 26H1(OSビルド28000.2956)
  • CPU:Snapdragon X Elite X1E78100
  • メモリ:LPDDR5-8488 32GB
  • ストレージ:WD Blue SN5100 1TB

テストデータには、ファイル数の多いリポジトリとしてmicrosoft/vscodeのタグ1.140.0を使いました。

ext4側に置いたbareミラーから--no-hardlinks付きでcloneし、そのリポジトリに対して以下の操作の所要時間を測っています。

  • 対象ディレクトリへのclone
  • git status(2回連続で実行)
  • findによる全ファイルの列挙
  • duによる容量の集計
  • 小さなファイル5,000個の作成、ls -l、削除
  • リポジトリ全体の削除

計測は自作のベンチマークスクリプトで行い、/mnt/c/tmp(Plan9)、/mnt/c/tmp(virtiofs)、対照としてディストリ内のext4(~/benchtmp)の3パターンで各3回実行して中央値をとりました。

#!/usr/bin/env bash
set -euo pipefail
TAG=1.140.0
MIRROR="$HOME/mirror/vscode.git"
BASE="${1:-/mnt/c/tmp}"
RUNS="${2:-3}"
mkdir -p "$BASE"
cd "$BASE"
FSTYPE=$(findmnt -n -o FSTYPE -T "$BASE")
LOG="$HOME/bench_$(hostname)_${FSTYPE}_$(date +%Y%m%d_%H%M%S).csv"
{
  echo "# host=$(hostname) kernel=$(uname -r) base=$BASE fstype=$FSTYPE tag=$TAG"
  echo "# $(findmnt -n -T "$BASE")"
  echo "run,test,seconds"
} | tee "$LOG"
TIMEFORMAT='%R'
measure() {
  local label=$1; shift
  local sec
  sec=$( { time "$@" >/dev/null 2>&1; } 2>&1 )
  echo "$run,$label,$sec" | tee -a "$LOG"
}
for run in $(seq 1 "$RUNS"); do
  rm -rf vscode smallfiles
  measure clone        git clone -q --no-hardlinks --branch "$TAG" "$MIRROR" vscode
  measure status_1     git -C vscode status
  measure status_2     git -C vscode status
  measure find         bash -c 'find vscode -type f | wc -l'
  measure du           du -sh vscode
  measure small_create bash -c 'mkdir smallfiles && for i in $(seq 5000); do echo x > smallfiles/f$i; done'
  measure small_stat   bash -c 'ls -l smallfiles > /dev/null'
  measure rm_small     rm -rf smallfiles
  measure rm_repo      rm -rf vscode
done
echo "log: $LOG"

なお、デスクトップPC(x86_64)とノートPC(Windows 11 on ARM)はハードウェアもWindowsのビルドも違うので、比較はノートPCの結果だけで比較しています。

結果

単位は秒で、小さいほど速い結果です。

テストPlan9virtiofsPlan9/virtiofsext4(対照)
clone305.1112.82.71倍3.84
git status(1回目)17.98.42.12倍0.23
git status(2回目)17.78.22.16倍0.08
find7.922.962.67倍0.05
du16.64.173.98倍0.05
小ファイル5,000個作成7.643.032.53倍0.10
ls -l(5,000個)4.972.292.17倍0.02
小ファイル削除2.561.651.55倍0.04
リポジトリ削除20.210.71.89倍0.49

すべての項目でvirtiofsのほうが速く、おおむね2〜3倍、duに至っては約4倍という結果になりました。

cloneは5分強かかっていたのが2分弱になっていて、体感でもはっきり分かる差です。WSLcの記事にあった「約2倍」という数字とも大きくはずれていない印象ですね。

一方で、ext4と比べるとvirtiofsでもまだ数十倍遅いのが正直なところです。

ext4のほうは1秒未満で終わる項目が多く、cloneが3.49〜9.04秒、git statusの1回目が0.09〜0.78秒と、実行ごとのばらつきも大きめでした(いずれも1回目が遅い)。ext4との倍率はあくまで目安程度に見てください。

アップデートだけでPlan9は速くなる?

参考として、アップデート前のカーネル(6.18.33.2)でもPlan9のベンチを取っていました。3.0.1(6.18.40.1)との差は中央値の比で各項目−3%〜+7%程度です。

各3回しか測っていないので断言はできませんが、アップデートしただけではPlan9の速度はほぼ変わらないと思われます。

デスクトップPCでもアップデート前後でddによる書き込み速度を測ってみました(bs=10G count=1 oflag=directで、実際の書き込みは約2GiB、各1回のみ)。

書き込み先2.7.83.0.1
~/(ext4)784 MB/s987 MB/s
/mnt/c/tmp(Plan9)284 MB/s292 MB/s

こちらも/mnt/cはほぼ横ばいです。ext4は数字の上では伸びていますが、1回ずつしか測っていないので誤差の範囲かもしれません。

切り替える前に知っておきたい注意点

  • .wslconfigの設定はすべてのディストリに反映されます。ディストリごとにPlan9とvirtiofsを使い分けることはできないはずです。
  • 設定を反映するにはwsl --shutdownが必要です。起動中のディストリやVS CodeのRemote接続もすべて切れるので、作業の区切りで行ってください。
  • virtiofsを有効にしたときに、/etc/wsl.confのumask/fmaskが10進数として解釈され、fmaskがディレクトリにも適用されてしまう不具合(#41711)が報告されています。
    2.9.13.0で報告されたもので、2026年10月3日時点でまだOpenです。wsl.confの[automount]でパーミッションを調整している方は、切り替え後に/mnt/c配下のパーミッションを確認してください
  • virtiofsにしてもext4よりは大幅に遅いので、ソースコードやnode_modulesを/mnt/cに置く運用はおススメしません

まとめ

WSL 3.0.1にアップデートしても、/mnt/cは自動ではvirtiofsになりません。.wslconfigに1行書いてwsl --shutdownするだけで切り替えられ、手元の環境ではPlan9より2〜4倍ほど速くなりました。

ちょっとした作業でWindows側のファイルを触ることが多い方は、切り替える価値は十分あると思います。

とはいえ、ext4との差はまだまだ大きく、「リポジトリはディストリ内のext4に置く」というこれまでの鉄則は変わりません。virtiofsはあくまで「/mnt/cを触るときの遅さがだいぶマシになる」くらいに捉えておくのがいいんじゃないかなぁと思います。

既定がPlan9のままになっているのも、#41711のような不具合がまだ残っていることを考えると、慎重な判断なのかもしれません。

個人的には、早く既定でvirtiofsになってほしいなぁ…というのが本音です。なお、社内の開発端末に展開するかどうかは、組織に合った方法で判断してください。

モバイルバージョンを終了