Windows on ArchLinux (IOMMU)

うちの2016年現在のLinux/Windows環境。

■ 共存

  • (1) デュアルブート
  • (2) Windowsホスト上でLinuxゲスト
  • (3) Linuxホスト上でWindowsゲスト

一般的に(3)はあまり採用されていないと思う。理由はWindowsの方がLinuxよりもグラフィカルな処理が多く、仮想的なCPUリソースやメモリだけでなく、GPUを必要とするからだと思う。Linuxは最悪何も表示されなくてもよく、私も以前はVirtualBoxのHeadlessモードで立ち上げてmintty+sshで作業していたくらいだ。だからどちらをホストにしどちらをゲストにするかはあまり選択肢が無かったのではないだろうか。もちろん、Windows ServerをVPSで使うといったことはあっただろうが、ここでは「普段使いのメインPC」に絞りたい。

ここ最近Linuxホスト上でWindowsゲストを普段使いのPCとして使ってる情報(動作報告)が増えてきた。先の問題の解法を言うと、「GPUはエミュレーションではなくパススルーする」ことでWindows上でほぼベアメタルと同じパフォーマンスが出せる。

これによって得たと思ってるもの

  • ベアメタル上でRAID、LVM、Linuxで使える多数のファイルシステム(WindowsホストではNTFS一択)
  • Windowsゲストのディスクイメージレベルのバックアップ体制

これによって失ったもの

  • 安定した音声入出力
  • ストレージの本来のスループット(やはり多少は遅くなる)
  • Linuxが起動してからWindowsが起動するので起動時間は2倍くらいになる
  • ここに到達するまでの調査、検証、トライ&エラーに費やした時間

音声入出力についてはまだ決着がついていないが、現状はこれが一番の難儀ポイントだと思う。これもPCI-E接続のサウンドカードにしてパススルーするか、GPUのHDMI-Audioを使うのが無難そうだという印象をもっている。私はUSB接続のサウンドデバイス(?)を購入することでひと段落ついたことにしている。

概ね満足している。このWindowsは一見するとネイティブなのか仮想マシンなのか判断がつかない。


■切欠

ところでなぜこんなめんどくさいこと(ぁ)をすることになったのか少し経緯を書いておく。以前はベアメタルでWindows10を入れ、仮想マシンでLinuxという(2)の形でつかっていた。構成はSSDにOSを、データ類はHDDに、というとってもオーソドックスなものだった。

そこでSSDである。こいつである。同じ日に買ったSSDとHDDがあった場合に、先にSSDが壊れるとはあまり信じたくないのだが、要するにそういうことなのだ。SSDは壊れるとHDDよりも復旧が難しいらしいのかー、ふんふん、そんなことを知った自分が1か月以内にそれを見ることになるとは。

SSD error

(ちなみに専用ツールによる余命表示は直近で覚えてる値で96%であった。これはあと50年程度使えるという意味の値である。)

実は2016年に入って壊れたのはSSDだけではなく、メモリもmemtestで真っ赤になる経験をしている。これでSSDまで逝ってサルベージの大変さを味わうと人間は「カッとなって」いろいろとやって反省することになっている。

memory error

以下感想:

  • SSDだからって壊れにくいと思うな、SSDでも冗長化(RAID156)は必要だ
  • メモリは1か月に1度くらいmemtestしたほうがよい、初期不良だけがメモリの不良ではない、できればECCメモリに
  • バックアップ重要

さて、「カッとなって」なにをするかだが、とにかくメインPCが使えないのでこれの復旧にカッとなるしかない。そうしてマザボ、CPU、メモリ、SSD等々の出費のオンパレードが始まった。Windowsをゲストにしてしまおうと調査を始めたのも、パススルーの存在を知ったのもこの過程だったと思う。


■デバイスをパススルーするにはハードウェアの選定から始まる

パススルー(Pass-Through)とは「素通り」のような意味である。ストレージのキャッシュなんかにはPass-ThroughとWrite-Backの設定がある。Write-Backだと書き込みが一旦キャッシュに貯められるが、Pass-Throughでは素通りして同期的にストレージに書き込まれる。これと同じ意味のパススルーだが、ストレージではなくPCIデバイスをユーザープロセスから見えるようにする。ホスト上のデバイスを仮想マシンのゲストに丸見えにさせることをここでは「パススルー」と言っている。仮想マシン以外の用途ではユーザースペースデバイスドライバというものがあり、代表的なものにDPDKがある。最近はそんなことができてしまうのだ。

最近のできたてのデスクトップ向けCPUならその多くはこのパススルー(IntelではVT-d、AMDではAMD-Vi、総称はI/O MMU virtualization、以下IOMMU)に対応している。そしてこれらを使うためのLinux上の機能の固有名詞がVirtual Function I/O(VFIO)となっている。

IOMMUの対応状況はCPUよりもM/Bの方に注意する必要がある。もしパススルーするなら、購入前にM/BのマニュアルをDLしてUEFI BIOSの設定画面にVT-dの説明があるかチェックしておく必要がある。たった今IOMMUのことを知った人が、自分のM/BがIOMMUに対応しているか調べたとすると、おそらく対応している人はデスクトップに限っても2~3割程度だと思う。それくらいM/B側の対応状況は悪い。メーカーで言うとASUSはあまり対応していない。ところが同じチップセットなのにASRockは対応してたりする。ASRockのハイエンドなものは概ね対応しているようだ。それからサーバー向けチップセットのものは対応している可能性が高い。

私が「カっとなって」選んだのはASUSのP10S WS。C236搭載でVT-dにしっかり対応している。蛇足だが、このM/Bには標準でNICが2つあり、しかも別々のIOMMUグループにあるので一つはLinux、もう一つはWindowsゲストにパススルー、といったことができる。ちょっと高かったがあまりにも自分にピッタリなのでこれにした。


■はまりポイント

ここではいくつかハマった点と、構成を少しメモしておく。


■GPUを指す場所

IOMMUを使う場合、M/BによってはGPUを指す場所に注意する必要がある。P10S WSの例だが、以下のBlock Diagramを見てもらいたい。

diagram

このM/BではPCIEX16_1、PCIEX16_2がSkylake CPUに接続されていて、ここにx8/x16のQSW(Quick Switchと思われ)がある。以下のスクリプトはIOMMUグループを見やすく一覧表示するものだ(ArchのWikiにある)

for iommu_group in $(find /sys/kernel/iommu_groups/ -maxdepth 1 -mindepth 1 -type d); do
    echo "IOMMU grpoup $(basename "$iommu_group")";
    for device in $(ls "$iommu_group"/devices/); do
        echo -n $'\t'; lspci -nns "$device";
    done;
done

PCIEX16_2にGPUを指すと、出力はこのようになる。

IOMMU group 0
    00:00.0 Host bridge [0600]: Intel Corporation Skylake Host Bridge/DRAM Registers [8086:1918] (rev 07)
IOMMU group 1
    00:01.0 PCI bridge [0604]: Intel Corporation Skylake PCIe Controller (x16) [8086:1901] (rev 07)
    00:01.1 PCI bridge [0604]: Intel Corporation Skylake PCIe Controller (x8) [8086:1905] (rev 07)
    02:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Turks GL [Radeon HD 6000 Series] [1002:6749]
    02:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Turks/Whistler HDMI Audio [Radeon HD 6000 Series] [1002:aa90]
IOMMU group 2
    00:02.0 VGA compatible controller [0300]: Intel Corporation HD Graphics P530 [8086:191d] (rev 06)
IOMMU group 3
    00:14.0 USB controller [0c03]: Intel Corporation Sunrise Point-H USB 3.0 xHCI Controller [8086:a12f] (rev 31)
IOMMU group 4
    00:16.0 Communication controller [0780]: Intel Corporation Sunrise Point-H CSME HECI #1 [8086:a13a] (rev 31)
IOMMU group 5
    00:17.0 SATA controller [0106]: Intel Corporation Sunrise Point-H SATA controller [AHCI mode] [8086:a102] (rev 31)
IOMMU group 6
    00:1b.0 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Root Port #17 [8086:a167] (rev f1)
IOMMU group 7
    00:1c.0 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Express Root Port #1 [8086:a110] (rev f1)
IOMMU group 8
    00:1d.0 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Express Root Port #9 [8086:a118] (rev f1)
IOMMU group 9
    00:1d.2 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Express Root Port #11 [8086:a11a] (rev f1)
IOMMU group 10
    00:1d.3 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Express Root Port #12 [8086:a11b] (rev f1)
IOMMU group 11
    00:1f.0 ISA bridge [0601]: Intel Corporation Sunrise Point-H LPC Controller [8086:a149] (rev 31)
    00:1f.2 Memory controller [0580]: Intel Corporation Sunrise Point-H PMC [8086:a121] (rev 31)
    00:1f.3 Audio device [0403]: Intel Corporation Sunrise Point-H HD Audio [8086:a170] (rev 31)
    00:1f.4 SMBus [0c05]: Intel Corporation Sunrise Point-H SMBus [8086:a123] (rev 31)
IOMMU group 12
    05:00.0 USB controller [0c03]: ASMedia Technology Inc. ASM1142 USB 3.1 Host Controller [1b21:1242]
IOMMU group 13
    06:00.0 Ethernet controller [0200]: Intel Corporation I210 Gigabit Network Connection [8086:1533] (rev 03)
IOMMU group 14
    07:00.0 Ethernet controller [0200]: Intel Corporation I210 Gigabit Network Connection [8086:1533] (rev 03)

GPU(02:00.0)がIOMMU group 1にあるが、そこにはIntel Corporation Skylake PCIe Controller(00:01.0) (QSWを行う主体と思われる)も入っているので、このグループはunbindできない、あるいはできてもとても不安定になる。VFIOはデバイスではなくIOMMUグループの単位で開放する。この場合GPUはC236側、PCIEX16_3かPCIEX16_4に指したほうがよい。

参考: PCI passthrough via OVMF: Plugging your guest GPU in an unisolated CPU-based PCIe slot

最終的には以下のようになっている。GPUを変えているのは置いといて、それはIOMMU group 12に移っている。

IOMMU group 0
    00:00.0 Host bridge [0600]: Intel Corporation Skylake Host Bridge/DRAM Registers [8086:1918] (rev 07)
IOMMU group 1
    00:02.0 VGA compatible controller [0300]: Intel Corporation HD Graphics P530 [8086:191d] (rev 06)
IOMMU group 2
    00:14.0 USB controller [0c03]: Intel Corporation Sunrise Point-H USB 3.0 xHCI Controller [8086:a12f] (rev 31)
IOMMU group 3
    00:16.0 Communication controller [0780]: Intel Corporation Sunrise Point-H CSME HECI #1 [8086:a13a] (rev 31)
IOMMU group 4
    00:17.0 SATA controller [0106]: Intel Corporation Sunrise Point-H SATA controller [AHCI mode] [8086:a102] (rev 31)
IOMMU group 5
    00:1b.0 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Root Port #17 [8086:a167] (rev f1)
IOMMU group 6
    00:1c.0 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Express Root Port #1 [8086:a110] (rev f1)
IOMMU group 7
    00:1c.4 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Express Root Port #5 [8086:a114] (rev f1)
IOMMU group 8
    00:1d.0 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Express Root Port #9 [8086:a118] (rev f1)
IOMMU group 9
    00:1d.2 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Express Root Port #11 [8086:a11a] (rev f1)
IOMMU group 10
    00:1d.3 PCI bridge [0604]: Intel Corporation Sunrise Point-H PCI Express Root Port #12 [8086:a11b] (rev f1)
IOMMU group 11
    00:1f.0 ISA bridge [0601]: Intel Corporation Sunrise Point-H LPC Controller [8086:a149] (rev 31)
    00:1f.2 Memory controller [0580]: Intel Corporation Sunrise Point-H PMC [8086:a121] (rev 31)
    00:1f.3 Audio device [0403]: Intel Corporation Sunrise Point-H HD Audio [8086:a170] (rev 31)
    00:1f.4 SMBus [0c05]: Intel Corporation Sunrise Point-H SMBus [8086:a123] (rev 31)
IOMMU group 12
    03:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga PRO [Radeon R9 285/380] [1002:6939] (rev f1)
    03:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga HDMI Audio [Radeon R9 285/380] [1002:aad8]
IOMMU group 13
    04:00.0 USB controller [0c03]: ASMedia Technology Inc. ASM1142 USB 3.1 Host Controller [1b21:1242]
IOMMU group 14
    05:00.0 Ethernet controller [0200]: Intel Corporation I210 Gigabit Network Connection [8086:1533] (rev 03)
IOMMU group 15
    06:00.0 Ethernet controller [0200]: Intel Corporation I210 Gigabit Network Connection [8086:1533] (rev 03)

私の場合、以下のものを仮想マシンにパススルーしたい。

IOMMU group 12
    03:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga PRO [Radeon R9 285/380] [1002:6939] (rev f1)
    03:00.1 Audio device [0403]: Advanced Micro Devices, Inc. [AMD/ATI] Tonga HDMI Audio [Radeon R9 285/380] [1002:aad8]
IOMMU grpoup 15
    06:00.0 Ethernet controller [0200]: Intel Corporation I210 Gigabit Network Connection [8086:1533] (rev 03)

そのためのQEmuのオプションはこのようになる。

    -device virtio-serial-pci \
    -device vfio-pci,host=03:00.0,addr=09.0,x-vga=on,multifunction=on \
    -device vfio-pci,host=03:00.1,addr=09.1 \
    -device vfio-pci,host=06:00.0,addr=08.0 \

■ストレージ

Linuxの/やWindowsゲストのC:はSSDx2のRAID1(mdraid)になっている。仮想マシンはディスクイメージのファイルではなくて、ブロックデバイスをformat=rawで割り当てているが、LVMの論理ボリューム(LV)なので何か間違ってそっちがブートしてしまうようなことはない。またWindowsのディスク管理ではディスクの拡張が行えるので、論理ボリュームを拡大すれば容量を増やすことができる。VGには少し余裕をもたせているが、当分は拡大する必要はなさそうである。なお、NTFSの透過圧縮はOFFにしている。

Linuxの/var/home/home/sharow/dataはHDDのbtrfs(RAID1)のサブボリュームになっている。/home/home/sharow/dataを分けた理由はsnapperでスナップショットをとる単位を調整したかったから。(ところでsnapperはイイですよ)

WindowsゲストのデータドライブD:はこの/home/sharow/data/vm以下にあり、こちらはディスクイメージのファイル(format=raw)になっている。拡大可能なのでとりあえず200GB。これに対してはbtrfsのCoW(コピーオンライト)をOFFにする。

$ chattr +C /home/sharow/data/vm/image/

こちらはNTFSの透過圧縮をONにしている。そういうわけでbtrfsの透過圧縮は切る。

$ sudo btrfs property set /home/sharow/data/vm/image/ compression ""

これらを設定したうえで.../vm/image/以下にディスクイメージファイルを用意する。作った後ではアトリビュートの変更はできない。

QEmuのドライブ設定は以下のようになっている。

    -drive file=/dev/vg_array/lv_vmroot,index=0,media=disk,format=raw,discard=on,if=virtio \
    -drive file=/home/sharow/data/vm/image/data.raw,index=1,media=disk,format=raw,discard=off,if=virtio \

■問題の音声入出力

QEmuからはALSAとpulseaudio(PA)が使えるが双方ともあまりよくない。言葉で伝えるのが難しいが、例えば音楽なら、すべてがPortal風になる、といえば通じるだろうか。あるいは定期的にブツブツいう。この問題はWindowsゲスト関係の海外フォーラムでも最もホットなトピック(?)だと思う。

これ用にUSBのサウンドデバイスを買う場合、それがUSB3.0なのかUSB2.0なのか、どっちが良さそうか、動作報告はあるか、よく調べたほうがよいかもしれない。この件は自分もまだ検証・調整中で、詳しい人がいたら教えてほしいくらいだ。今のところありそうな選択肢は

  • QEmuのALSA or pulseaudioを使う(Portal化)
  • USB接続のサウンドデバイスを使ってQEmuでUSBパススルー(多少不安定&CPU負荷増)
  • PCI-E接続のUSBホストアダプタをPCIパススルーさせてUSB接続のサウンドデバイスを使う(良さそうに思える:もし買ったら後日検証) → PCIe接続のUSBホストをパススルー
  • PCI-E接続のサウンドデバイス(HDMI-audio含む)をPCIパススルー
  • Windows版pulseaudioクライアントを使ってネットワーク経由でLinuxのpulseaudioサーバに送る


■健康管理とバックアップ

ストレージやECCメモリのステータス確認は以下のコマンドで行える。

$ cat /proc/mdstat
Personalities : [raid1]
md0 : active raid1 sda2[0] sdb2[1]
      124355904 blocks super 1.2 [2/2] [UU]
      bitmap: 1/1 pages [4KB], 65536KB chunk

unused devices: <none>
$
$ sudo btrfs dev st /btrfs
[/dev/sdc1].write_io_errs   0
[/dev/sdc1].read_io_errs    0
[/dev/sdc1].flush_io_errs   0
[/dev/sdc1].corruption_errs 0
[/dev/sdc1].generation_errs 0
[/dev/sdd1].write_io_errs   0
[/dev/sdd1].read_io_errs    0
[/dev/sdd1].flush_io_errs   0
[/dev/sdd1].corruption_errs 0
[/dev/sdd1].generation_errs 0
$
$ sudo edac-util -v
mc0: 0 Uncorrected Errors with no DIMM info
mc0: 0 Corrected Errors with no DIMM info
mc0: csrow0: 0 Uncorrected Errors
mc0: csrow0: mc#0csrow#0channel#0: 0 Corrected Errors
mc0: csrow0: mc#0csrow#0channel#1: 0 Corrected Errors
mc0: csrow1: 0 Uncorrected Errors
mc0: csrow1: mc#0csrow#1channel#0: 0 Corrected Errors
mc0: csrow1: mc#0csrow#1channel#1: 0 Corrected Errors
mc0: csrow2: 0 Uncorrected Errors
mc0: csrow2: mc#0csrow#2channel#0: 0 Corrected Errors
mc0: csrow2: mc#0csrow#2channel#1: 0 Corrected Errors
mc0: csrow3: 0 Uncorrected Errors
mc0: csrow3: mc#0csrow#3channel#0: 0 Corrected Errors
mc0: csrow3: mc#0csrow#3channel#1: 0 Corrected Errors
edac-util: No errors to report.
$

ちなみにSkylake世代のECCメモリは新しいカーネルか、それ用にパッチ済みのカーネルでないと未対応になる。ArchLinuxなら問題ない。

WindowsゲストのC:のバックアップは現状アホみたいに簡単なものになっている。

TS=`date '+%Y_%m_%d_%H'`
dd if=/dev/vg_array/lv_vmroot bs=4096 | pv | lz4 -z  > vmroot_${TS}.lz4
cp /home/sharow/data/vm/ovmf/vars/OVMF_VARS-pure-efi.fd ./OVMF_VARS-pure-efi.${TS}.fd

C:は64GiBだが、バックアップはだいたい5分くらいで完了する。圧縮がよく効くようで、バックアップ後は16GiBくらいに収まってくれる。


■エクスペリエンスインデックスとか

score

ふむ。悪くない。

ちなみにコア割り当ては3コアなので珍しいタスクマネージャの表示になる。

score

アフィニティは設定していない。


■参考リンク


Contents © 2017 sharow - Powered by Nikola