このトピックでは、最近のカーネルバージョンを実行している Elastic Compute Service (ECS) インスタンスから virtio デバイスをホットアンプラグする際に発生する Oops 例外の解決方法について説明します。
症状
特定の最近のカーネルバージョンを実行している ECS インスタンスからディスクや NIC などの virtio デバイスをホットアンプラグすると、Oops 例外が発生し、以下のいずれかの結果になることがあります。
-
インスタンスが
kernel.panic_on_oops = 1と設定されている場合、カーネルパニックが発生します。 -
インスタンスが
kernel.panic_on_oops = 0と設定されている場合、カーネルは無応答になります。
kernel.panic_on_oopsは、カーネルが Oops (カーネルエラー) に遭遇した際の動作を制御するカーネルパラメータです。
-
カーネルパニック:システムは現在のタスクを停止し、デバッグ情報を保存した後、再起動またはシャットダウンします。これにより、問題に迅速に対応し、潜在的な損害を最小限に抑えることができます。
-
カーネルの無応答:カーネルは実行を継続しようとします。これはデータ破損やその他の重大な問題につながる可能性があるため、本番環境では推奨されません。
原因
この問題は、Linux アップストリームコミュニティがこのコミットで、virtio デバイスの admin virtqueue のサポートを追加した際に混入したものです。
このコミットにより、以下の変更が導入されました。
-
admin virtqueue の存在を確認するために、
virtio_pci_deviceの定義にis_avq関数ポインタが追加されました。 -
モダン virtio デバイスの初期化を担当する
virtio_pci_modern_probe関数が、is_avq関数ポインタに値を割り当てます。@@ -588,6 +658,7 @@ int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev) vp_dev->config_vector = vp_config_vector; vp_dev->setup_vq = setup_vq; vp_dev->del_vq = del_vq; + vp_dev->is_avq = vp_is_avq; vp_dev->isr = mdev->isr; vp_dev->vdev.id = mdev->id; -
virtio デバイスがホットアンプラグされると、コードは現在のキューが admin virtqueue であるかどうかを確認します。
@@ -236,6 +236,9 @@ void vp_del_vqs(struct virtio_device *vdev) int i; list_for_entry_safe(vq, n, &vdev->vqs, list) { + if (vp_dev->is_avq(vdev, vq->index)) + continue; + if (vp_dev->per_vq_vectors) { int v = vp_dev->vqs[vq->index]->msix_vector; } }
しかし、レガシ virtio デバイスの場合、is_avq関数ポインタは初期化されず、ヌルポインタのままです。その結果、レガシ virtio デバイスをホットアンプラグすると、if (vp_dev->is_avq(vdev, vq->index))の呼び出しがヌルポインタをデリファレンスしようとします。これにより例外がトリガーされ、システムクラッシュを引き起こす可能性があります。
影響範囲
-
Linux アップストリームコミュニティ
アップストリームコミュニティは、このコミットでこの問題を解決しました。この修正では、
is_avq関数ポインタを呼び出す前にヌルチェックが追加されています。 -
オペレーティングシステム
-
Ubuntu 24
-
admin virtqueue のサポートを取り込んでいるが、is_avq のヌルチェックパッチが適用されていない、6.8 前後のカーネルバージョンを持つ他のオペレーティングシステム。
説明uname -rコマンドを実行してカーネルバージョンを確認できます。
-
-
virtio デバイス
この問題は、レガシ virtio デバイスが ECS インスタンスからホットアンプラグされる際に影響します。
ソリューション
-
ソリューション 1:第8世代以降のインスタンスファミリーなど、モダン virtio デバイスを使用するインスタンスファミリーに切り替えます。これらのインスタンスファミリーはこの問題の影響を受けません。詳細については、「インスタンスタイプの変更」をご参照ください。インスタンスファミリーの詳細については、「インスタンスファミリー」をご参照ください。
-
ソリューション 2:
-
最新のカーネルパッケージにアップグレードし、virtio-pci: Check if is_avq is NULL パッチが含まれていることを確認します。
-
(条件付きで必須) 最新のカーネルにパッチが含まれていない場合は、手動で適用する必要があります。
-
付録:用語
このセクションでは、virtio デバイス、admin virtqueue、virtio_pci_device など、このトピックで使用される主要な用語について説明します。
|
用語 |
説明 |
|
virtio デバイス |
Virtio は、仮想マシンがホストの仮想ハードウェアと効率的に対話できるようにする、I/O 仮想化のための標準化されたフレームワークです。ディスクや NIC などの virtio デバイスは、仮想化環境におけるエミュレートされたデバイスです。これらのデバイスは、主に使用する設定インターフェイスによって区別され、レガシまたはモダンに分類されます。 |
|
admin virtqueue |
admin virtqueue は、デバイスステータスのクエリや設定変更の適用など、デバイス管理操作に使用される特別なキューです。すべての virtio デバイスが admin virtqueue をサポートしているわけではありません。 |
|
virtio_pci_device |
これは、カーネル内で virtio PCI デバイスを表すデータ構造です。特定のキューが admin virtqueue であるかどうかを確認するために使用される |
|
is_avq |
割り当てられると、特定の virtio キューが admin virtqueue であるかどうかをチェックする関数を指す関数ポインタです。 |
|
virtio_pci_modern_probe |
この関数は、virtio PCI デバイスの検出と初期化を担当します。システムがデバイスを検出した後、この関数が呼び出されて設定空間の読み取り、デバイス機能の検出、必要なリソースの割り当てなどのセットアップを完了します。 |
|
RIP |
x86 CPU の RIP (命令ポインタ) レジスタは、次に実行する命令のアドレスを格納します。ヌルポインタのデリファレンス試行などの例外が発生した場合、RIP は障害を発生させた命令のアドレスを指します。 |