はじめに
アドヴェントをきっかけに初めて投稿します。
WSL2環境からSDカードを使うために、思ったよりも手間がかかってしまったのですが、体当たりでいろいろ経験できたため、まとめておこうと思います。
本記事は感想多め&知ってる人には当たり前かもしれないことなので、概要見ておやおやと思った方に読んでいただければ幸いです。
概要
2023/12現在、WSL2ではSDカードへのアクセス手段が公式に提供されておらず、以下の手順を踏みました。
・USB マスストレージクラスのドライバを含むカスタムカーネルイメージのビルド
・Windows版usbipdを利用しusbip経由でUSB-SDカードアダプタをアタッチ
背景
久しぶりにRaspberryPiで遊ぼうと思いたち、新しいSDにイメージを作ることにしました。
最近、VMwareやWSL環境の上のlinuxを幾分触れるようになっていたので、Linux上でtorrentでダウンロードしたりddコマンドでOSイメージを書き込んでみたりしようと思ったのが始まりです。これは、torrentを知って使ってみたかったことと、トラブル時に実機を介さずファイルを読込むためにどうしてもLinuxが必要になった経験があったからです。
この時点では結構甘い見通しでして、起動が楽&いつものブラウザから拾ったファイルが楽につつける環境が気に入っており、WSLのUbuntuでイメージをダウンロードしました。
WSL2でSDカードを使う
WSLがクセつよなLinux環境であることは理解しているつもりでしたが、WSL2は改善リリースも多く、結構イケているのでSDカードにアクセスすることが困難を伴うとは夢にも思わず、今回の沼にハマっていきます。以下、WSLでSDカードにアクセスできるようになるまでの躓きポイントを私の経験した時系列で紹介していきます。
つまづきポイント多め...
1. Windows上のファイルシステムとしてはSDカードにアクセスできない
WindowsからX:として見えているドライブはWSLから扱えるとのですが、標準状態ではcドライブのみがmountされていて、/devにも/mntにもSDカードは発見できませんでした。
FATパーティションについては後述のwsl mountコマンドが利用でできますが、この時点では知りませんでした
2. SDカードアダプタをdiskドライブとして認識できない
Raspbianや他のlinuxでSDカードを使用するときの動作としては、/dev上のblockデバイスとして /dev/sda みたいにdiskとして認識してもらい、パーティションとして認識された/dev/sda1やsda2をファイルシステムにmountしていました。
これをWSLで再現しようと思いましたが、どうやら現在のWSLではSDカードを直接diskとして認識させることができないようです。
参考: wsl mountコマンドはHDDやVHDファイルをブロックデバイスとしてマウントできる機能ですがデバイス名がHDD同様に取得される内蔵SDスロットでも対応不可でした
3. USBデバイスはWSL標準でサポートしていない
上記Microsoftのドキュメントを読み進めると、SDカードはアダプタを介し、USBデバイスとしてならリダイレクトできるということのようです。しかし、そもそもHyper-Vが公式にUSBのリダイレクトを提供していないらしく、公式回避策としてusbipdの利用が紹介されていました。
参考:
USBIP-WINを利用する
解決策が見えたところで公式さんの手順に従って進めていくわけですが、ここでもつまづきます。
https://learn.microsoft.com/ja-jp/windows/wsl/connect-usb#install-the-usbipd-win-project
4. WSL→Windowsの通信がうまくいかない
今回、usbipdはWindows側のデーモンとなるため、WSLからWindowsへ接続する必要がありましたが、WSLのユースケースには少ないため何気にここでもしばらく詰まってしまいました。
それぞれから見えるIPアドレスを調べることができたものの、疎通に失敗する状況であったため、原因を理解するまで頭を抱えました。
結局はWindowsファイヤウォールによる着信のブロックであったことがわかり、Hyper-Vゲスト側のアドレスと思われるIP帯からの着信を許可しました。
(本来着信先をusbipdのサービスに限定すべきですが、例では接続元IPアドレスの指定のみを条件に着信を許可しています)
5. ドライバ不足のためカスタムカーネルのビルド作業が必要
紆余曲折の末に、SDカードドライブをusbデバイスとしてリダイレクトすることに成功し、lsusbで存在を確認できました。読むべきは公式さんのドキュメントだなー、なんて呑気に進められていると思っていたのですが、どうやらドライブとして認識されません。/devにSDカードのblockデバイスが現れません。。
今いちど、先のWSLのドキュメントからリンクされているフォーラムの会話を追いかけていくと、WSL2標準のカーネルにはUSBマスストレージクラスのドライバが入っていないことが判明し、さらにリンクされた以下のページにたどり着きます。カーネルか。。お、ぉぅ…やばいハードル爆上がり。
参考: usbipd-win WSLサポートwiki
microsoft/WSL2-Linux-Kernel https://github.com/microsoft/WSL2-Linux-Kernel
WSL2標準構成のカーネルconfig https://github.com/microsoft/WSL2-Linux-Kernel/blob/master/Microsoft/config-wsl
はじめてのカーネルビルド
上記のusbipd-winのサポートwiki記載手順に従い、今使っているWSL環境をエクスポート、インポートし、バックアップ(クローン)したUbuntu環境で作業します。
gitからカーネルソース一式をcloneして...menuconfigでDevice DriversからUSB masstorage関連を有効化してmake… 案外簡単?と思いましたが
6. WindowsファイルシステムとLinuxファイルシステムの差異に泣く
時間はかかるわ、 謎のエラーは出るわで手順通りいきません。
ここまでやって詰んだか。。。
エラーが謎いと思いながら作業ログを眺めていくといくつかのファイルが重複してリポジトリが正しくクローンされていないような。。。
大文字小文字が異なる同名モジュールが見える・・!
作業ディレクトリに指定していたWindows側のディレクトリの標準設定で大文字小文字は名寄せされてしまうため、ファイル重複で一部の同名の別モジュールが取得されていなかったのです。WSLでは必要のないときにWindwos側のファイルシステム使わないほうが良いのですね。
改めてビルド
ローカルリポジトリをWSLのUbuntu上のディレクトリに移動させたうえで更新を行ったところ、問題のモジュールが重複検知されずに取得され、makeも手順通り進めることができました。そして速度も一段と早い。
誤解していましたが、WSL環境からはWindowsローカルのファイルシステムよりもWSL内のLinuxファイルシステムのほうが高速であるというこでした。
SDカードのマウント(やっと)
PS C:\temp> usbipd wsl list
BUSID VID:PID DEVICE STATE
2-6 04nn:b7nn Integrated Camera, APP Mode Not attached
...
2-13 80nn:00nn SD Card Reader Not attached
PS C:\temp> usbip wsl attach -d ubuntu -b 2-13
ubuntu@WSL:/mnt/c/tmp$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 002: ID 80nn:00nn SD Card Reader
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
ubuntu@WSL:/mnt/c/tmp$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 389.8M 1 disk
sdb 8:16 0 2G 0 disk [SWAP]
sdc 8:48 0 1T 0 disk /snap
/mnt/wslg/distro
/
sdd n:xx 0 64G 0 disk
ubuntu@WSL:/mnt/c/tmp$ sudo mount /dev/sdd2 /mnt/sd2
やったー!
まとめ
今回、WSL2環境に対し、USBドライバを追加したカーネルのビルドを行い、usbipd-winを用いることで、無事にSDカードを利用することができるようになりました。
この中で、WSLの癖(ファイルシステムの速度や大文字小文字ファイル名問題)やコンフィグ、ビルドオプションなどを学び、WSL2のテクノロジの一端を少し理解することができました。
最後に
今回、初めての投稿です。思ったより時間がかかりアドベントの予定を過ぎてしまいましたがクリスマスまでに何とかできてよかったです。振り返りを行いアウトプットすることで、少し自信がついたように思います。
ですが過不足や間違いはあるかと思いますのでお気づきの点は指摘いただけると幸いです。
なお、WSLについて表記ゆれがありますが、すべてWSL2を指しています。
補足
例では手順に従いUbuntuで行いまいしたが、ビルドしたカーネルイメージは.WslconfigでWSL2環境グローバルに適用されるため、kali-linuxでも同様にSDカードを利用することができます。
余談その1
執筆にあたりいろいろ読み直していたところ、usbipではなく、iSCSIで対応した例も発見しました。これまた良いアイディアですね。今回USBデバイスとしてマウントしてやる回避策のため、内蔵SDカードスロットは利用不可、外付けのアダプタが必須したがiSCSIによる方法は内蔵スロットに適用できるかもしれません??
余談その2
「Bash の素晴らしさと PowerShell の意味」によるとあくまで本物のBashでWindows環境を操作できることがWSLの最初の到達目標であったように思われ、今回の苦労は公式の意図した使い方の外で、いわば'勝手に'苦労しているということのようです。
しかし、逆にMicrosoftの意図する以上にユーザーがWSLに利便を感じ、自ら改善に取り組んでいるとも言い換えることができそうです。コミュニティでもそれなりに困っている人がいましたし。みんな楽しそうです。