Kexec

提供: ArchWiki
2023年8月2日 (水) 15:48時点におけるKgx (トーク | 投稿記録)による版 (→‎トラブルシューティング: カーネルモードを設定しない (Nvidia)を翻訳して追加)
ナビゲーションに移動 検索に移動

関連記事

Kexec は動作中のカーネルから他のカーネルをロード・起動するためのシステムコールです。カーネル開発者など、BIOS のブートプロセスが終わるまで待たないで素早く再起動する必要がある場合に有用です。デバイスが完全に再初期化されず、kexec が上手く動作しないこともありますが、それはとてもレアなケースです。

インストール

kexec-tools パッケージをインストールしてください。

kexec で再起動

手動

kexec を手動で実行するには:

# kexec -l /boot/vmlinuz-linux --initrd=/boot/initramfs-linux.img --reuse-cmdline
# kexec -e
警告: kexec -e を直接実行するとアクティブなファイルシステムがアンマウントされません。また、実行中のサービスが安全に終了されません。

手動でカーネルをロードしてから systemd でサービスのシャットダウンや kexec を処理させることも可能です:

# kexec -l /boot/vmlinuz-linux --initrd=/boot/initramfs-linux.img --reuse-cmdline
# systemctl kexec

Systemd

systemd-boot を使っていて、前に kexec -l を使って手動でカーネルをロードしたことがない場合、デフォルトで systemd はデフォルトのブートローダーエントリに指定されたカーネルをロードします。例えば、システムを更新した後に新しいカーネルに再起動したいときは、以下のコマンドを実行するだけで起動できます:

# systemctl kexec

複数の initrd エントリ (例えばマイクロコードのアップデートのためのエントリなど) が存在する場合は上記のコマンドは起動を拒否します。

カスタムユニットファイル

デフォルトで起動できない場合やカスタムカーネルをロードしたい場合、サービスユニットでカーネルのロードをラッピングできます。ユニットファイル kexec-load@.service を作成して、kexec するカーネルをロードさせる必要があります:

/etc/systemd/system/kexec-load@.service
[Unit]
Description=load %i kernel into the current kernel
Documentation=man:kexec(8)
DefaultDependencies=no
Before=shutdown.target umount.target final.target

[Service]
Type=oneshot
ExecStart=/usr/bin/kexec -l /boot/vmlinuz-%i --initrd=/boot/initramfs-%i.img --reuse-cmdline

[Install]
WantedBy=kexec.target

ロードしたいカーネルを指定してサービスファイルを有効化してください、例えばデフォルトカーネル linux を使用する場合:

# systemctl enable kexec-load@linux
ln -s '/etc/systemd/system/kexec-load@.service' '/etc/systemd/system/kexec.target.wants/kexec-load@linux.service'

/etc/mkinitcpio.confHOOKS 行から shutdown フックを削除して initramfs イメージにフックを含めないようにしてください。削除したら mkinitcpio -p linux で initrd イメージを再生成します。

その後 kexec を実行します:

# systemctl kexec

別のカーネルをロードしたいときは (例: linux-lts)、現在のカーネルのサービスを無効化してから新しいカーネルのサービスを有効化してください:

# systemctl disable kexec-load@linux
# systemctl enable kexec-load@linux-lts

/boot パーティションの分割

/boot が root ファイルシステム上にない場合、上記の systemd ユニットファイルは動作しません。kexec-load ユニットファイルを実行する前に /boot が systemd によってアンマウントされてしまうからです。その場合、起動時には何もせず終了時に kexec を呼び出す "hook" ユニットファイルをロードします。このユニットファイルを kexec.target と衝突させるようにすることで、新しいカーネルを systemctl kexec コマンドの直後に確実にロードさせることができます。上記の規定どおりに作成した /etc/systemd/system/kexec-load@.service ファイルは以下のようになります:

[Unit]
Description=hook to load vmlinuz-%i kernel upon kexec
Documentation=man:kexec(8)
DefaultDependencies=no
Requires=sysinit.target
After=sysinit.target

[Service]
Type=oneshot
ExecStart=-/usr/bin/true
RemainAfterExit=yes
ExecStop=/usr/bin/kexec -l /boot/vmlinuz-%i --initrd=/boot/initramfs-%i.img --reuse-cmdline

[Install]
WantedBy=basic.target

Conflicts=shutdown.target は省略してもかまいません。sysinit.target を指定するだけで暗示的に Conflicts=shutdown.target に設定されるためです。

トラブルシューティング

"kexec_core: Starting new kernel" の後にシステムがフリーズしたり再起動する

その場合、一般的なトラブルシューティング#起動時の問題 の情報が問題を診断するのに役立つかもしれません。

特に、acpi=off カーネルパラメータを追加したときに kexec が正しく動作するようになる場合、[1] で説明されているように kexec コマンドラインに acpi_rsdp カーネルパラメータを追加することで ACPI を無効化することなく問題を解決できる可能性があります [2]

カーネルモードを設定しない (Nvidia)

kexec の前にグラフィックスドライバーをアンロードする必要があります。そうしないと、次のカーネルがデバイスの排他制御を取得できなくなります。GPU の排他制御が必要なプログラム (Xorg、ディスプレイマネージャー) が実行されていてはいけないため、これを手動で実現するのは困難です。以下は、kexec の直前に KMS ドライバーをアンロードする systemd service の例です。これには、systemctl kexec を使用する必要があります。

/etc/systemd/system/unmodeset.service
[Unit]
Description=Unload nvidia modesetting modules from kernel
Documentation=man:modprobe(8)
DefaultDependencies=no
After=umount.target
Before=kexec.target

[Service]
Type=oneshot
ExecStart=modprobe -r nvidia_drm

[Install]
WantedBy=kexec.target

その後、unmodeset.service有効化 します。

参照