今回はWSLのファイルシステムについて解説を行う。対象は、Windows 11上のWSLだが、基本的にはWindows 10でも仕組みや振る舞いは同じである。評価には、WSLディストリビューションとして、Ubuntu(5.10.60.1-microsoft-standard-WSL2)を使う。なお、基本的な用語については、記事末の表を参照されたい。なお、文章量の関係から、ここでは、ファイルシステムの解説のみ行い、設定などに関しては、別途解説を行う予定である。

■バックナンバー

・Windows Subsystem for Linuxガイド 第3回 WSL2動作設定編

https://news.mynavi.jp/article/20220207-2266984/

・Windows Subsystem for Linuxガイド 第2回 コマンド編

https://news.mynavi.jp/article/20211228-2240002/

・Windows Subsystem for Linuxガイド 第1回 基本編

https://news.mynavi.jp/article/20211203-2211548/

WSLとWin32のファイルシステム

Windowsの中でLinuxを動かすWSLでは、複数のファイルシステムが動作しており、これらを明確に区別する必要がある。(表01)は、WSLが動作するWindows内に存在するファイルシステムを示す。

一般にオペレーティングシステムが直接管理するローカルファイルシステムに関しては、普通はそれぞれの文脈で明確であるため、特に名称をつけず、ローカルファイルシステムやファイルシステム技術名(NTFSやext4)などと呼ぶ。しかし、WSLは、Windowsの中でLinuxが動くという特殊な構成であり、それぞれのファイルシステムを明確に区別しておく必要がある。

この記事では、LinuxのローカルファイルシステムをWindows側と区別するため「WSL側ファイルシステム」と表記することにする。後述するようにWSLでは「WslFs」と呼ばれるファイルシステム形式が使われているため、これと明確に区別するためこの表記を使う。同様にWindowsのローカルファイルシステムを「Win32側ファイルシステム」と表記する。

WSL固有の機能として、WSL側、Win32側からお互いのファイルシステムへのアクセスを行う機能がある。WSL環境からWin32側ファイルシステムへのアクセス機能を「ドライブファイルシステム」と呼ぶ。この名称は、WSL1のときに使われたファイルシステム技術の名称にちなむ。

同様にWin32側からWSL側ファイルシステムへのアクセス機能が用意されているが、これには特に名称がないため、Windows 10に導入された仮想的なホスト名“wsl$”を用いて「wsl$ファイルシステム」と呼ぶことにする。

これらをまとめた図を(図01)に示す。Win32側ファイルシステムを除く、これらのファイルシステムにはそれぞれ特徴があり、使い方に注意する必要がある。また、「Windows Subsystem for Linuxガイド 第1回 基本編」で述べたようにWSL1とWSL2の違いとしてファイルシステムの違いがある。

図01: WSLが動作している環境では、「WSL側ファイルシステム」、「ドライブファイルシステム」、「wsl$ファイルシステム」と、Windowsのファイルシステムである「Win32側ファイルシステム」の4つのファイルシステムが動作している


WSL側ファイルシステム

WSLのLinuxのローカルファイルシステム(WSL側ファイルシステム)は、WSL1とWSL2で異なった技術が使われている。WSL1では現在WslFsと呼ばれる技術が使われているが、当初は、VolFs(Volume File System)と呼ばれる技術が使われていた。VolFs、WslFsともにNTFS上のフォルダーをLinuxのファイルシステムとしてアクセスするものだ。Linuxではカーネルがファイルアクセスの機能を提供するが、WSL1では、LinuxカーネルをWindowsカーネルでエミュレーションしている。このため、ファイルアクセスのカーネル呼び出し(カーネルコール)は、Windowsカーネルのカーネル呼び出しに変換されて処理される。

WslFsとVolFsの違いは、Linuxのファイルアクセス許可(パーミッション)などのメタ情報をNTFS側で記録する方法の違いである。すでにVolFsは利用されていないので詳細は省く。どちらも、NTFS上のフォルダー(ディレクトリ)をLinuxのファイルシステムとしてアクセスし、そのときにファイルのメタ情報(Linuxのファイルパーミッションや所有者などの情報)を、NTFSの「ストリーム」として記録している。NTFSでは、ファイルは複数のストリームとして構成可能で、ストリームは独立して扱うことができる。通常のファイルの内容は、ファイルのストリームの1つである。ストリームに関しては、以下の解説を参考にされたい。

・ファイルのストリーム (ローカルファイルシステム) - Win32 apps | Microsoft Docs

https://docs.microsoft.com/ja-jp/windows/win32/fileio/file-streams

Win32側からこのVolFs/WslFsフォルダーに直接アクセスすることは可能だが、推奨されていない。1つにはLinux側のファイル書き込みなどは非同期に行われるため、Win32側からのアクセスタイミングに注意が必要な点。もう1つは、WindowsとVolFs、WslFsによるLinuxファイルパーミッションが個別に管理されているため、Win32側からのアクセスにより、WSL側ファイルシステムの状態に齟齬を来す可能性があるからだ。

なお、Microsoftのドキュメントでは、WSL側ファイルシステムを「VolFs」と総称していることがある。また、Linuxの中では、ファイルシステムの名前を小文字で表記するため、VolFsに相当するファイルシステムをmountコマンドなどで扱う場合には、volfsなどと表記する。こうした小文字のファイルシステム名は、具体的なLinuxのファイルシステム名を指し、大文字小文字が混在したVolFsのような表記は、ファイルシステムの技術名として理解していただきたい。このあたりの用語を整理した表を(表02)に示す。

WSL2では、WSL側ファイルシステムは、Windowsの仮想ハードディスクファイル(VHDX)を使って実現されている。WSL2は、軽量ユーティリティ仮想マシンと呼ばれる環境の中でLinuxカーネルとWSLディストリビューションを実行させている。仮想ハードディスクファイルは、Windowsの仮想マシンハイパーバイザーで使われるハードディスクをエミュレーションする技術。仮想マシンからのハードディスクアクセスは、ハイパーバイザー内でVHDXファイル内へのアクセスに変換される。このため、VHDXファイル自体は、NTFSのファイルだが、その中に、仮想マシンが扱うファイルシステム(ハードディスクイメージ)が構築されている。

WSL側ファイルシステムは、WSL1では、LinuxのファイルアクセスをWindowsのファイルアクセスAPIに変換しているため、速度の低下は小さい。また、WSL2では、仮想ハードディスクファイル経由でのアクセスになるため、少し効率が落ちる。ただし、ファイルの読み書き方法(たとえば読み書きのブロックサイズが大きい場合)などによっては、高い速度を出すこともできる。

WSL側ファイルシステムはどこにあるのか?

WSL側ファイルシステムは、ユーザーフォルダー以下の

%userprofile%\Appdata\local\Packages\\LocalState\

にある。ここにVolFs/WslFSフォルダーやVHDXファイルが配置されている。具体的には、(表03)のようなフォルダーになるが、今後のWSLディストリビューションのバージョンアップなどで名称が変わり、パスが変わる可能性がある。このため、表にある「ワイルドカード指定」を使って、

dir %userprofile%\Appdata\Local\packages\

としてディストリビューションのフォルダー名を調べることができる。また、このワイルドカード指定とPowerShellのGet-AppxPackageコマンドを使う方法もある。AppxPackageオブジェクトの“PackageFamilyName”プロパティがフォルダー名に相当する。

こうしてWSLディストリビューションのパッケージフォルダー名が判明したら、その下にある“LocalState”フォルダーにWSL側ファイルシステムに対応するVolFs/WslFsのフォルダーや仮想ハードディスクファイルがある。

WSL側ファイルシステム内へのアクセスには、原則後述のwsl$ファイルシステムを使うが、WSLに問題があり、アクセスができないなどの緊急時には、この方法でファイルシステムにアクセスが可能だ。ただし、WSL2の場合、VHDXファイルはWindowsで直接扱えても、中のext4ファイルシステムをWindowsで直接扱う方法は標準では提供されていない。

ドライブファイルシステム

ドライブファイルシステムは、WSL側からWin32側ファイルシステムをアクセスするためのものだ。Win32側のC:\は、WSL側では/mnt/c/になる。これは、WSL1でもWSL2でも同じだ。

wsl.exeによるLinuxの起動時、wsl.exeを実行したフォルダーに対応するドライブファイルシステム上のパスが、bashなどのLinuxシェルの起動パスとなる。これは、wsl.exeコマンドによるLinuxシェルとWin32側シェル(cmd.exeやPowerShell.exe)で、カレントディレクトリにあるファイルをパス指定なしで扱うことなどを可能にするためだ。このためにドライブファイルシステムが必要になる。

WSL2では、ドライブファイルシステムを実現するために9PFsと呼ばれるファイルシステムが使われる。9PFsは、9Pと呼ばれるネットワークプロトコルを使うネットワークファイル共有システムだ。9Pは、米国ベル研究所で作られた、Plan 9 from Bell Labs(Plan 9と略称で表記されることもある)というオペレーティングシステム用に開発されたもの。Win32側で9PFsのサーバーを動作させ、WSL側に対してファイル共有機能を提供する。ただし、9PFsによるファイルアクセスはそれほど高速ではない。TCP/IPなどのネットワークスタックは利用しないが、手順としては、ネットワークファイルと同じやりかたでWin32側のファイルにアクセスするからだ。

これに対してWSL1のDrvFsでは、Linux側ファイルアクセスをWindowsのファイルアクセス用カーネル呼び出しに変換する。このため、WSL1のDrvFsは、Windowsのローカルファイルアクセスと同程度の性能を持つ。

なお、ホスト側で複数のドライブ(ハードディスクなど)を利用している場合、自動的にマウントが行われる。たとえば、C、Dの2つのドライブがある場合、そのルートフォルダーC:\とD:\は、WSL側からは、/mnt/c/、/mnt/d/としてアクセスできるようになる。こうしたドライブファイルシステムは/etc/wsl.confで制御が可能だ(これに関しては別途解説する予定)。

WSL1では、LinuxのファイルアクセスをWindowsのAPIに変換しているため比較的高速に行える。これに対してWSL2では、WSL側ファイルシステムは比較的高速だが、ドライブファイルシステムでは、9Pを使うためそれほど速度が出ない。このためWSL2では、ファイルアクセスがボトルネックになるような場合、できるだけWSL側ファイルシステムにファイルを置くようにすべきだろう。次回は、Win32側からWSL側ファイルシステムにアクセスするwsl$ファイルシステムを解説し、WSLのファイルアクセス速度を検証してみたい。