[Steam Deck]Windows環境で、Ext4パーティションを含むSDカードのデータを読み書きする方法

Steam DeckでWindowsとのデュアルブート環境を構築してる方も多いだろうけど、SDカードを挿し替えるのが面倒だし、なによりSDカードを買い足す費用がかかるから、なんとかできないかともがいてみた。

WindowsでExt4パーティションを扱う方法を色々調べたところ、専用のドライバーはありそうだけど、有償だったり、メンテナンスされてなかったり、怪しい所だったり…で使う気がしなかった。そんな中、WSL2を経由すればext4がWindowsでも扱えるという情報を発見。

極力オープンソース技術を使い、かつ比較的安全と思われる方法が見つかったので記録しておく。

先に書いておくと手順が結構くどい。あとLinuxのカーネルモジュールをビルドする関係で時間がかかる。上級者向けかも。オープンソースアプリをソースからビルドした経験があると楽かも。

Steam Deckに搭載されているSDカードリーダーは、SCSI接続の模様。検証始めるまでUSBだと思ってた。

  • 簡単に言うと、WindowsからiSCSIを経由してWSLにマウントして、WSL上に立てたSambaサーバーからまたWindowsへ戻す、というループバックを行う。
  • Windows 11 Home (22H2)で検証。多分Windows 10でもできる。
  • WSL2 / Ubuntu 22.04.1 LTSを利用
  • Windows 11(10) ProだとクライアントHyper-Vが使えるので、うまくデバイスのパススルーができれば、もう少し手順が簡単になる可能性があるかも。
  • Steam Deckの内蔵カードリーダー以外にも応用可能。PCのUSBメモリ等のマスストレージデバイスでも使える。
    • USBだけ使えればいいやという方は、usbipd-winで検索すると幸せになれるかも。
  • 手順はUSB Storage Device Access on WSL2をベースに、パッケージや選択項目の不足をなど細部手順を補完したもの。

前提条件

[WSL側]カーネルモジュールのビルドとインストール

$sudo apt update

ビルドに必要なパッケージをインストール

$ sudo apt install build-essential flex bison libssl-dev libelf-dev libncurses5-dev git bc dwarves
$ mkdir src
$ cd src

WSL2用のLinuxカーネルソースをダウンロードする

$ git clone https://github.com/microsoft/WSL2-Linux-Kernel.git
$ cd WSL2-Linux-Kernel
$ export KCONFIG_CONFIG=Microsoft/config-wsl
$ make menuconfig

コンフィグ画面が出るので、下記の項目にチェックを入れる。

[*] Enable loadable module support

General setup  --->
    [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support

Device Drivers --->
    [*] Multiple devices driver support (RAID and LVM) --->
        <*> Device mapper support
    [*] Block Devices ---> 
        <*> Loopback device support 
    SCSI device support  --->
        <*> SCSI disk support
        <*> SCSI generic support
        SCSI Transports --->
            <M> iSCSI Transport Attributes
            [*] SCSI low-level drivers  --->
                <M> iSCSI Initiator over TCP/IP     

File systems ---> 
     <*> FUSE (Filesystem in Userspace) support
     [*] UTF-8 nomalization and casefolding support
      ↑忘れずに!この機能が無いとマウントの所でエラーになる
      
[*] Networking support  --->
   Networking options  --->
      [*] TCP/IP networking 

ビルド開始。Steam Deckで30~40分程度かかる。もしエラーになった場合は、不足しているパッケージが無いか再確認する。

$ sudo make KCONFIG_CONFIG=Microsoft/config-wsl

できたモジュールをインストールする

$ sudo make modules_install

新しく作ったカーネルイメージをWindowsのユーザーディレクトリに配置

$ cp ./arch/x86_64/boot/bzImage /mnt/c/Users/(Windowsのユーザー名)/
nano /mnt/c/Users/(ユーザー名)/.wslconfig

/mnt/c/Users/(ユーザー名)/.wslconfig

[wsl2]
kernel=C:\\Users\\(ユーザー名)\\bzImage
swap=0
localhostForwarding=true

Ctrl+oで書き込みメニューを開き、Alt+dでDos Formatを選択、Enterで保存。Ctrl+xで閉じる。

PowerShellからWSLを再起動

PS > wsl --shutdown

再びWSLのコンソールを開き、モジュールをロード

$ sudo modprobe -v libiscsi
$ sudo modprobe -v scsi_transport_iscsi
$ sudo modprobe -v iscsi_tcp
$ sudo modprobe -v libiscsi_tcp

[WSL側]Systemd有効化

$ sudo nano /etc/wsl.conf

/etc/wsl.conf

[boot]
systemd=true

Ctrl+oで書き込みメニューを開き、Enterで保存。Ctrl+xで閉じる。

PowerShellからWSLを再起動。

PS > wsl --shutdown

再びWSLのコンソールを開いて起動しておく。

[Windows側]iSCSIターゲットのセットアップ

iSCSI Consoleを用いる。

https://github.com/TalAloni/iSCSIConsole

画面右側のReleasesからバイナリーのzipをダウンロードする。

zipを展開すると3つフォルダーがあるが、多分どれを選んでも同じ。(対応している.netのバージョンの違いだと思われる)

管理者権限でiSCSIConsole.exeを起動する。

SmartScreenの警告画面が出た場合は、詳細情報→実行をクリック

起動したらAdd Targetをクリック。

Add Physical Diskをクリック。

一覧にSDXCが表示されるので、それを選択してOKをクリック

ドライブをオフラインにする旨の確認画面が出るのでOKをクリック

Disksの欄にSDカードドライブが追加されるので、OKを押して閉じる

StartをクリックしてiSCSIターゲットを起動する。

ファイアーウォールの確認画面が出た場合は許可する。

[WSL側]iSCSIイニシエーターの設定

open-iscsiのインストール

$ sudo apt install open-iscsi

iSCSIターゲットとの疎通確認をする。

$ export WSLHOSTIP=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}')
$ sudo iscsiadm -m discovery -t st -p $WSLHOSTIP

172.26.240.1:3260,-1 iqn.1991-05.com.microsoft:target1

$ sudo iscsiadm -m node

172.26.240.1:3260,-1 iqn.1991-05.com.microsoft:target1

この時点で相手が表示されない場合は、iSCSI ConsoleのStartボタンの押し忘れがないか、ファイアーウォールなどでトラフィックが遮断されていないか確認する。

iSCSIターゲットへ接続。successfulが出ていれば成功

$ sudo iscsiadm -m node --targetname "iqn.1991-05.com.microsoft:target1" --portal "$WSLHOSTIP:3260" --login

Logging in to [iface: default, target: iqn.1991-05.com.microsoft:target1, portal: 172.26.240.1,3260] (multiple)
Login to [iface: default, target: iqn.1991-05.com.microsoft:target1, portal: 172.26.240.1,3260] successful.

新しくブロックデバイスが出現していることを確認

$ lsblk

SDカードのマウントを行う

$ sudo mkdir -p /mnt/sdcard/SteamLibrary

$ sudo mount /dev/sdc1 /mnt/sdcard/SteamLibrary
(↑/dev/sdc1の部分はlsblkを確認して適宜変更する)

[WSL側]Sambaサーバーのセットアップ

$ sudo apt install samba
$ sudo nano /etc/samba/smb.conf

/etc/samba/smb.confの最下行に下記を追加

[sdcard]
   path = /mnt/sdcard
   read only = no
sudo systemctl restart smbd

Samba用のパスワードを設定。

ここではSambaログイン時に利用するLinuxユーザーアカウント名を指定する。ここではdeckとしている。
必要に応じてsudo smbpasswd -a の部分は変更する

パスワードは空白でも怒られなかった。

sudo smbpasswd -a deck
New SMB Password:(そのままEnter)
Retype new SMB password:(そのままEnter) 

WSLのIPアドレスを確認しておく

$ ip addr

[Windows側]ネットワークドライブとして接続

エクスプローラーを開き、PCの所で「・・・」をクリックし、「ネットワークドライブの割り当て」をクリック

ドライブはお好みで。

フォルダーは、\\(WSLのIPアドレス)\sdcardとする

サインイン時に再接続にチェック、別の資格情報を使用して接続するにチェック。

完了をクリック。

アカウントを尋ねられるので、ユーザー:deck、パスワード:(smbpasswdで設定したパスワード)を入力

SDカードの中身が表示されていれば成功。

Steamライブラリフォルダーに追加

設定→ダウンロード→Steamライブラリフォルダーを開く。

ドライブ一覧の右にある(+)ボタンをクリック

「新しいSTEAMライブラリフォルダーを追加」のダイアログが出るので、先程追加したネットワークドライブを選択

※ネットワークドライブが一覧にない場合は、「別の場所を選択」を選び、「追加」をクリックした後、フォルダ選択画面でネットワークドライブを選択し、その配下にある「SteamLibrary」を選択した状態でOKをクリック。

最後に

これによってSteamOSでインストールしたライブラリーの共有ができると思うけど、心配なのは、Windows/Linuxの両方に対応したゲームで、かつ各プラットフォームによって配信されるファイルの内容が分かれているもの。ファイルが上書きされてうまくゲームが動かなくなったりするかも。

安全にライブラリーを共有したいという方は、フォルダを分ける(といっても歪な構造になりそう)か、事前にSDカードのバックアップをとっておくとよいでしょう。

参考

GRUBを利用したSteam Deckのデュアルブート環境インストール手順

2023/1/4更新:SteamOS 3.4ではこの方法が使えないことを確認しました。
2023/1/22更新
どうやらgrub.cfgの記述ミスが原因だったようで、SteamOS 3.4上でも動作することを確認しました!
セキュリティー上の懸念点があるため、os-proberを使わず、手動でWindowsのメニューエントリーを追加する手順に変更しました。

続きを読む

サーバースペック

備忘録を兼ねて。

パーツメーカー型番備考
CPUAMDEPYC 7443PZen 3 “Milan”、24コア / 48スレッド
メモリMicronMTA18ASF2G72PDZ-3G2R1DDR4-3200 16GB
ECC Registered ×8
(合計128GB)
マザーボードSupermicroH12SSL-NT
SSDSilicon PowerP34A801TB ×2 [RAID1] M.2 NVMe
HDDWestern DigitalWD RED WD80EFBX8TB ×2 [RAID1]
HDDケースDiracDIR-SG3403.5インチHDD4台搭載可能 ×2台
電源ThermaltakeToughpower GF1 850W
ケース汐見板金AX2 Ver1.2

YouTubeのメインのアカウントを、ブランドアカウントから本来のアカウントに移行した話

※2022年11月現在の挙動です。サービスなので、今後仕様が変わる可能性があることに注意。

メンバーシップギフトの機能が追加されてしばらく経過するが、今まで一度もギフトに当たったことがない。

調べてみると、ギフトを受け取る設定がチャンネルごとに必要なんだとか。でも自分のアカウントにはそんな設定がない。

更に調べると、「ブランドアカウントでは、メンバーシップギフトを受け取ることができない」ことが判明!自分はそれだった。過去に本名バレを防ぐために、そういう運用にしてたんだっけな。

そういうわけで、本来のアカウントでYouTubeを使う運用にすることにした。

本名バレしないのかという疑問については、YouTubeのコメントの書き込み時の名前は「アカウントに紐づいているチャンネル名」であって、そのチャンネル名は変更可能なため、問題なかった。以前の仕様だとGoogleアカウントの名前がそのまま表示されていたはずだけどね。

アカウントの移行はそんなに簡単にできるものではなかった。

ブランドアカウントでは、いくつかのチャンネルメンバーシップに入っていた。支払いは大元のGoogleアカウントに紐づいている。だから本来のアカウントでも使えるんでしょ?と思っていたが、本来のアカウントに切り替えると、「メンバーシップに入っているのにメンバー特典が使えない。でもなぜかメンバー限定動画は見られる」という中途半端な状態になってしまった。

このことについてサポートに問い合わせたところ、「チャンネルメンバーシップについては、ブランドアカウントで登録した場合は、そのブランドアカウントでのみ特典が使え、本来のアカウントからは特典が使えないとのこと。その逆も同じで、本来のアカウントで登録している場合は、ブランドアカウントでは特典が使えない」とのこと。

なので仕方なく、ブランドアカウントでメンバーシップを解約し、本来のアカウントで登録し直すことにした。すぐ移行できるんでしょ?と思っていたが、これもそんなことはなかった。解約しても期限が切れるまでは効力があるらしく、本来のアカウントから登録しようとすると、エラーになったり、空白の画面が表示されるだけだった。

期限切れを待って、ようやく本来のアカウントで登録できるようになった。なお、メンバーの期間についてはアカウント間で共通らしく、引き継がれる模様。これはありがたいけど、なんか複雑な仕様…

[Rust]クライアントとの通信にSteam Networkingを利用する

2023/07 接続に問題が出るため、現在は使わないよう公式からアナウンスが出ています。

Rustはデフォルトでは、RakNetと呼ばれるネットコードを利用してクライアントと通信をしているが、私の環境では、40名程度がサーバーに参加すると、サーバー全体が不安定になる症状が出た。

プレイヤーがサーバーに参加したタイミングで、トラフィックが大きくスパイクしてしまい、ラグが発生するのだ。

ルーター(RTX830)から見たトラフィックのグラフ。
サーバーから見て上りのLAN IN、WAN OUTのトラフィックが大きく振れている。
Rustのプレイヤーリストの一部。ping値が数千になっているクライアントが多数。一方、少数のクライアントは、正常に通信できている
このような不整脈みたいな波形が出てしまうと、
サーバーはほとんど応答しなくなってしまう。

サーバー上のパケット数の制限値を引き上げたりしてみたが効果なし。

いろいろ設定について調べていたところ、2020年10月「エレベーターアップデート」に興味深い開発者の記事を見つけた。

「RakNetはもうメンテナンスされていないし、脆弱性も我々でパッチしなければならないので、解決策としてSteam Networkingをサポートした」というのだ。RakNetはもう枯れすぎた技術なんでしょうかね…

Steam Networkingは、その名の通りValve社によって開発されたネットコード。オープンソース版もGithubにあるようだ。

通信にSteam Networkingを使用するには、サーバー側に下記の設定が必要。

  • 起動時のオプションに、”-swnet“、”-queryport (クエリー用のポート番号)”を指定
  • ルーター側で-queryportで指定したポート番号の開放

使ってみた感想は、「サーバーに入るのが少し大変だけど、一度サーバーに入れれば快適。トラフィックのグラフも安定してる」といった感じ。

ただしいくつか注意点もある。

  • WebRconやserverinfoコマンドで、ネットワークのトラフィックの情報が表示できなくなる
    常に0が返ってくる。
  • サーバー接続時に、「disconnecting: Entities Out Of Order: expected xxxx, received xxxx」が表示される
    これが厄介。多分Rustのバグなんだけど、Rustの公式Discordにも明確な原因や、解決策が載ってない。
    2か月程度運用した限りだと、拠点が密集しているところでログアウトすると、次回の接続時に起きやすくなる模様。
    下記のことを試したところ、サーバーに入れるようになったという報告がある。
    • 再接続
    • Rustの再起動
    • Steamの再起動
    • PCの再起動
    • Steamworks共通再頒布可能コンポーネントの整合性チェック
    • Rustの整合性チェック
    • 管理者がkillplayerコマンドで当該プレイヤーをキルする

「デフォルトがSteam Networkingに変更されない限り、コミュニティーサーバーではRakNetの使用を勧める」ということだが、公式サーバーでは既に使われているのだろうかねえ。

サーバー参加時の大きなラグで困っている管理者がいたら、試してみてほしい。