はじめに
Hyper-V 仮想マシンで使用している Ubuntu で、GNOME が freeze する現象が起きました。
原因が分からず回り道しましたが、結論としては hyperv_fb を使用せずに hyperv_drm で提供される hyperv_drmdrmfb フレームバッファデバイスを使用する事で解消できました。
以下、経緯について記載します。
私の Hyper-V の使い方 (Path through disk)
私は Windows11 Hyper-V で Ubuntu (22.04 LTS、23.04) を使用しています。SATA 接続の SSD 2基を Path through で Hyper-V に接続し、Hyper-V 仮想マシンとして、また実機として、両方で起動できるようにしています。詳細については、以下の過去記事 (はてなブログ) を参照ください。
古い PC で UEFI ではなく BIOS でしたので上記では Hyper-V 第一世代を使用していますが、今はUEFI ですので第二世代で仮想マシンを作成しています。
仮想マシンとして Windows11 上で動作させると共に、CPU やメモリをフルに使いたい場合には UEFI から実機で起動させて使用しています。
Hyper-V Ubuntu でログイン後に GNOME が freeze
そのような中で、Hyper-V で動作させている Ubuntu で GUI でログインした直後に GNOME が操作不能となる現象が発生しました。再現性ありです。
状況としては、
- Ubuntu 22.04 LTS と Ubuntu 23.04 の両方で発生
- kernel のアップデート後に発生し、古い kernel では正常に動作する
- linux-image-5.19.0-41-generic までは正常に動作
- Ubuntu 22.04 LTS では linux-image-5.19.0-42-generic 以降、Ubuntu 23.04 では linux-6.2.0-20-generic で発生
- gdm3 のログイン画面までは正常に動作し、仮想端末への切替 (Ctrl + Alt + F2 等) も可能
- ログインして GNOME の画面が表示されると、マウスもキーボードも使用できない
という具合でした。
事前に Windows11 から Hyper-V Ubuntu へ ssh でログインした状態で gdm3 でログインすると、GNOME は操作不能ですが、ssh でログインした端末では正常に動作していました。dmesg でも異常を示すログは見当たらず、高負荷なソフトウェアも見当たりませんでした。Hyper-V のメニューからシャットダウンを選択すると停止できるので、kernel はちゃんと動いているようでした。
実機で起動させると linux-image-5.19.0-42-generic 以降の kernel でも問題なく使用する事ができました。また、Virtualbox では GNOME の freeze は発生しませんでした。
とりあえず、linux-image-5.19.0-41-generic を残しておき、grub のメニューからこちらを選択して起動すれば問題なく使えました。とはいえ、不具合を放置したくなかったので、原因と対策を調べてみました。
同様の現象が発生していないか調査
同様の現象がないかをググってみると、以下の二つのページが見つかりました。
とはいえ、回避方法は古い linux-image-5.19.0-41-generic を使って、という事で、原因に繋がるような情報は得られませんでした。
twitter で検索すると、qiita のページが紹介されていました。
Ctrl + Alt + F3 -> Ctrl + Alt + F1 で gdm3 の画面に戻ると一時的に操作できるようになりますが、少し時間が経過するとまた freeze 状態になりますので、こちらも根本的な対策にはなりませんでした。
原因調査
Hyper-V 上で動作する Ubuntu では、hyperv_fb というフレームバッファデバイスを使用して、CUI / GUI が表示されます。また、Wayland ではなく Xorg が使用されています。(Wayland を選択できないようになっています)
画面表示の問題ですので、おそらくフレームバッファ周りの問題かと推測し、原因を調べてみました。
lsmod, dmesg, kernel config
新旧の kernel で起動して ssh でログインし、lsmod (使用されている module)、dmesg (仮想ハードウェアの認識状況)、kernel config (module の作成条件) を比較しましたが、dmesg の表示順が若干ズレている程度で、大きな違いはありませんでした。
linux-source-5.19.0-41 と linux-source-5.19.0-43 の差分
linux-source-5.19.0-43 の changelog から Hyper-V 周りの変更点を抜き出してみました。
$ cat changelog | grep -e ^linux -e hyperv -e hv_
linux-hwe-5.19 (5.19.0-43.44~22.04.1) jammy; urgency=medium
linux-hwe-5.19 (5.19.0-42.43~22.04.1) jammy; urgency=medium
- hv_netvsc: Fix missed pagebuf entries in netvsc_dma_map/unmap()
- hv_netvsc: Allocate memory in netvsc_dma_map() with GFP_ATOMIC
linux-hwe-5.19 (5.19.0-41.42~22.04.1) jammy; urgency=medium
linux-hwe-5.19 (5.19.0-40.41~22.04.1) jammy; urgency=medium
- powerpc/hv-gpci: Fix hv_gpci event list
- video: hyperv_fb: Avoid taking busy spinlock on panic path
- x86/hyperv: Remove unregister syscore call from Hyper-V cleanup
(...snip...)
5.19.0-40 で変更はありましたが、5.19.0-41 と 5.19.0-42、5.19.0-43 の間では hyperv_fb に変更はありませんでした。hv_netvsc の変更箇所はありますが、Network 周りの変更で、画面表示には直接関係ありませんので影響はないかと思います。
kernel source を diff で差分を取っても、hv_netvsc 以外に Hyper-V 周りの違いはありませんでした。
hyperv_fb を blacklist に追加して使用しないようにする -> 解消
hyperv_fb の修正もなく、module も同じように読み込まれているので、原因が分からず手詰まりとなりました。
Virtualbox の Ubuntu 22.04 LTS では linux-image-5.19.0-42-generic 以降でも問題なく起動できていた事もあり、hyperv_fb にトラブルの原因があるのではないかと考えて、これを使用しないで起動できるか試してみました。ArchWiki に設定例が載っていました。
linux kernel の 起動オプションに module_blacklist を追加します。grub の GRUB_CMDLINE_LINUX_DEFAULT に設定します。
$ cat /etc/default/grub | grep -e module_blacklist
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash module_blacklist=hyperv_fb"
$ sudo update-grub
この条件で起動すると、linux-image-5.19.0-42-generic 以降の kernel でも正常に GNOME を動作させる事ができました。
$ cat /proc/fb
0 hyperv_drmdrmfb
$ sudo dmesg -t | lv
(...snip...)
hv_vmbus: registering driver hyperv_drm
hyperv_drm 5620e0c7-8062-4dce-aeb7-520c7ef76171: [drm] Synthvid Version major 3, minor 5
Console: switching to colour dummy device 80x25
[drm] Initialized hyperv_drm 1.0.0 2020 for 5620e0c7-8062-4dce-aeb7-520c7ef76171 on minor 0
Console: switching to colour frame buffer device 128x48
hyperv_drm 5620e0c7-8062-4dce-aeb7-520c7ef76171: [drm] fb0: hyperv_drmdrmfb frame buffer device
(...snip...)
hyperv_fb の代わりに hyperv_drm モジュールが使用されて、hyperv_drmdrmfb というフレームバッファデバイスが有効になります。
Ubuntu 23.04 では、Wayland も選択・使用できるようになりました。
hyperv_drm の提供する hyperv_drmdrmfb フレームバッファデバイスは、linux-image-5.19.0-16 で追加されたようです。
$ cat changelog | grep -e ^linux -e hyperv-drm | lv
(...snip...)
linux (5.19.0-16.16) kinetic; urgency=medium
- drm/hyperv-drm: Include framebuffer and EDID headers
(...snip...)
linux の fbdev は obsolete?
古い情報ですが、linux の fbdev はメンテナンスされていない状態との記事を見つけました。
fbdevフレームワークは保守のみ行われている状態であり、すべての新しいディスプレイドライバーはDRMフレームワークで作成するよう促しています。
ここ数年DRMインターフェースは改良が施され、小型デバイスでもfbdevドライバーの代わりにDRMドライバーを利用できるようヘルパーインターフェースの追加も行われています。
https://kledgeb.blogspot.com/2016/12/linux-kernel-3-fbdevlinux-kernel.html
またDRMは、完全なfbdevエミュレーション機能の提供も提案しています。
また、blacklist には vesafb 以外は使用されないような記述もありました。
$ cat /etc/modprobe.d/blacklist-framebuffer.conf
# Framebuffer drivers are generally buggy and poorly-supported, and cause
# suspend failures, kernel panics and general mayhem. For this reason we
# never load them automatically.
(...snip...)
blacklist sstfb
blacklist tdfxfb
blacklist tridentfb
#blacklist vesafb
blacklist vfb
blacklist viafb
blacklist vt8623fb
blacklist udlfb
Framebuffer drivers are generally buggy and poorly-supported, and cause suspend failures, kernel panics and general mayhem. For this reason we never load them automatically.
フレームバッファ ドライバは一般にバグが多く、サポートが不十分であり、サスペンドの失敗、カーネル パニック、および一般的な混乱を引き起こします。このため、それらを自動的にロードすることはありません。
/etc/modprobe.d/blacklist-framebuffer.conf
ここからは推測になりますが、linux-image-5.19.0-41-generic と 42-generic の間で、fbdev の 修正がありました。
diff -ur linux-source-5.19.0-41/drivers/video/fbdev/core/fb_defio.c linux-source-5.19.0-43/drivers/video/fbdev/core/fb_defio.c
--- linux-source-5.19.0-41/drivers/video/fbdev/core/fb_defio.c 2022-08-01 06:03:01.000000000 +0900
+++ linux-source-5.19.0-43/drivers/video/fbdev/core/fb_defio.c 2023-05-22 22:39:09.000000000 +0900
@@ -313,7 +313,7 @@
}
EXPORT_SYMBOL_GPL(fb_deferred_io_open);
-void fb_deferred_io_cleanup(struct fb_info *info)
+void fb_deferred_io_release(struct fb_info *info)
{
struct fb_deferred_io *fbdefio = info->fbdefio;
struct page *page;
@@ -327,6 +327,14 @@
page = fb_deferred_io_page(info, i);
page->mapping = NULL;
}
+}
+EXPORT_SYMBOL_GPL(fb_deferred_io_release);
+
+void fb_deferred_io_cleanup(struct fb_info *info)
+{
+ struct fb_deferred_io *fbdefio = info->fbdefio;
+
+ fb_deferred_io_release(info);
kvfree(info->pagerefs);
mutex_destroy(&fbdefio->lock);
diff -ur linux-source-5.19.0-41/drivers/video/fbdev/core/fbmem.c linux-source-5.19.0-43/drivers/video/fbdev/core/fbmem.c
--- linux-source-5.19.0-41/drivers/video/fbdev/core/fbmem.c 2023-04-19 02:39:34.000000000 +0900
+++ linux-source-5.19.0-43/drivers/video/fbdev/core/fbmem.c 2023-05-22 22:39:09.000000000 +0900
@@ -1451,6 +1451,10 @@
struct fb_info * const info = file->private_data;
lock_fb_info(info);
+#if IS_ENABLED(CONFIG_FB_DEFERRED_IO)
+ if (info->fbdefio)
+ fb_deferred_io_release(info);
+#endif
if (info->fbops->fb_release)
info->fbops->fb_release(info,1);
module_put(info->fbops->owner);
この変更により、hyperv_fb が正常に動作しなくなったのではないでしょうか。
どちらにしても、hyperv_drm モジュールでもフレームバッファデバイスの機能が提供されますので、今後は hyperv_fb を使用せず、hyperv_drm モジュールを使用した方が良いかと思います。
まとめ
Hyper-V 仮想マシンの Ubuntu で GNOME が freeze する現象が発生しました。フレームバッファデバイスとして hyperv_fb ではなく hyperv_drm を使用する事で、freeze せずに正常に動作するようになりました。
今回のトラブルは、再現性はあったものの dmesg や kernel source から原因を見つける事が出来ず、かなり回り道して原因に辿り着きました。
同様のトラブルに遭った方の参考になれば幸いです。
今回のアイキャッチ画像
林の中を油絵調で生成しました。自然の多い環境で幼少期を過ごしたので、今の住まいの近くは便利であるものの、少々息苦しく感じる事が多いです。
コメント