RE: hyper_bf soft lockup on Azure Gen2 VM when taking kdump or executing kexec
From: Michael Kelley
Date: Fri Feb 07 2025 - 13:38:32 EST
From: Michael Kelley <mhklinux@xxxxxxxxxxx> Sent: Thursday, February 6, 2025 1:00 PM
>
> From: Michael Kelley <mhklinux@xxxxxxxxxxx>
> >
> > From: Thomas Tai <thomas.tai@xxxxxxxxxx> Sent: Thursday, January 30, 2025 12:44 PM
> > >
> > > > -----Original Message-----
> > > > From: Michael Kelley <mhklinux@xxxxxxxxxxx> Sent: Thursday, January 30, 2025 3:20 PM
> > > >
> > > > From: Thomas Tai <thomas.tai@xxxxxxxxxx> Sent: Thursday, January 30,
> > > > 2025 10:50 AM
> > > > >
> > > > > Sorry for the typo in the subject title. It should have been 'hyperv_fb soft lockup on
> > > > > Azure Gen2 VM when taking kdump or executing kexec'
> > > > >
> > > > > Thomas
> > > > >
> > > > > >
> > > > > > Hi Michael,
> > > > > >
> > > > > > We see an issue with the mainline kernel on the Azure Gen 2 VM when
> > > > > > trying to induce a kernel panic with sysrq commands. The VM would hang
> > > > > > with soft lockup. A similar issue happens when executing kexec on the VM.
> > > > > > This issue is seen only with Gen2 VMs(with UEFI boot). Gen1 VMs with bios
> > > > > > boot are fine.
> > > > > >
> > > > > > git bisect identifies the issue is cased by the commit 20ee2ae8c5899
> > > > > > ("fbdev/hyperv_fb: Fix logic error for Gen2 VMs in hvfb_getmem()" ).
> > > > > > However, reverting the commit would cause the frame buffer not to work
> > > > > > on the Gen2 VM.
> > > > > >
> > > > > > Do you have any hints on what caused this issue?
> > > > > >
> > > > > > To reproduce the issue with kdump:
> > > > > > - Install mainline kernel on an Azure Gen 2 VM and trigger a kdump
> > > > > > - echo 1 > /proc/sys/kernel/sysrq
> > > > > > - echo c > /proc/sysrq-trigger
> > > > > >
> > > > > > To reproduce the issue with executing kexec:
> > > > > > - Install mainline kernel on Azure Gen 2 VM and use kexec
> > > > > > - sudo kexec -l /boot/vmlinuz --initrd=/boot/initramfs.img --command-
> > > > > > line="$( cat /proc/cmdline )"
> > > > > > - sudo kexec -e
> > > > > >
> > > > > > Thank you,
> > > > > > Thomas
> > > >
> > > > I will take a look, but it might be early next week before I can do so.
> > > >
> > >
> > > Thank you, Michael for your help!
> > >
> > > > It looks like your soft lockup log below is from the kdump kernel (or the newly
> > > > kexec'ed kernel). Can you confirm? Also, this looks like a subset of the full log.
> > >
> > > Yes, the soft lockup log below is from the kdump kernel.
> > >
> > > > Do you have the full serial console log that you could email to me? Seeing
> > > > everything might be helpful. Of course, I'll try to repro the problem myself
> > > > as well.
> > >
> > > I have attached the complete bootup and kdump kernel log.
> > >
> > > File: bootup_and_kdump.log
> > > Line 1 ... 984 (bootup log)
> > > Line 990 (kdump kernel booting up)
> > > Line 1351 (soft lockup)
> > >
> > > Thank you,
> > > Thomas
> > >
> >
> > I have reproduced the problem in an Azure VM running Oracle Linux
> > 9.4 with the 6.13.0 kernel. Interestingly, the problem does not occur
> > in a VM running on a locally installed Hyper-V with Ubuntu 20.04 and
> > the 6.13.0 kernel. There are several differences in the two
> > environments: the version of Hyper-V, the VM configuration, the Linux
> > distro, and the .config file used to build the 6.13.0 kernel. I'll try to
> > figure out what make the difference, and then the root cause.
> >
>
> This has been a real bear to investigate. :-( The key observation
> is that with older kernel versions, the efifb driver does *not* try
> to load when running in the kdump kernel, and everything works.
> In newer kernels, the efifb driver *does* try to load, and it appears
> to hang. (Actually, it is causing the VM to run very slowly. More on
> that in a minute.)
>
> I've bisected the kernel again, compensating for the fact that commit
> 20ee2ae8c5899 is needed to make the Hyper-V frame buffer work. With
> that compensation, the actual problematic commit is 2bebc3cd4870
> (Revert "firmware/sysfb: Clear screen_info state after consuming it").
> Doing the revert causes screen_info.orig_video_isVGA to retain its value
> of 0x70 (VIDEO_TYPE_EFI), which the kdump kernel picks up, causing it
> to load the efifb driver.
>
> Then the question is why the efifb driver doesn't work in the kdump
> kernel. Actually, it *does* work in many cases. I built the 6.13.0 kernel
> on the Oracle Linux 9.4 system, and transferred the kernel image binary
> and module binaries to an Ubuntu 20.04 VM in Azure. In that VM, the
> efifb driver is loaded as part of the kdump kernel, and it doesn't cause
> any problems. But there's an interesting difference. In the Oracle Linux
> 9.4 VM, the efifb driver finds the framebuffer at 0x40000000, while on
> the Ubuntu 20.04 VM, it finds the framebuffer at 0x40900000. This
> difference is due to differences in how the screen_info variable gets
> setup in the two VMs.
>
> When the normal kernel starts in a freshly booted VM, Hyper-V provides
> the EFI framebuffer at 0x40000000, and it works. But after the Hyper-V
> FB driver or Hyper-V DRM driver has initialized, Linux has picked a
> different MMIO address range and told Hyper-V to use the new
> address range (which often starts at 0x40900000). A kexec does *not*
> reset Hyper-V's transition to the new range, so when the efifb driver
> tries to use the framebuffer at 0x40000000, the accesses trap to
> Hyper-V and probably fail or timeout (I'm not sure of the details). After
> the guest does some number of these bad references, Hyper-V considers
> itself to be under attack from an ill-behaving guest, and throttles the
> guest so that it doesn't run for a few seconds. The throttling repeats,
> and results in extremely slow running in the kdump kernel.
>
> Somehow in the Ubuntu 20.04 VM, the location of the frame buffer
> as stored in screen_info.lfb_base gets updated to be 0x40900000. I
> haven't fully debugged how that happens. But with that update, the
> efifb driver is using the updated framebuffer address and it works. On
> the Oracle Linux 9.4 system, that update doesn't appear to happen,
> and the problem occurs.
>
> This in an interim update on the problem. I'm still investigating how
> screen_info.lfb_base is set in the kdump kernel, and why it is different
> in the Ubuntu 20.04 VM vs. in the Oracle Linux 9.4 VM. Once that is
> well understood, we can contemplate how to fix the problem. Undoing
> the revert that is commit 2bebc3cd4870 doesn't seem like the solution
> since the original code there was reported to cause many other issues.
> The solution focus will likely be on how to ensure the kdump kernel gets
> the correct framebuffer address so the efifb driver works, since the
> framebuffer address changing is a quirk of Hyper-V behavior.
>
> If anyone else has insight into what's going on here, please chime in.
> What I've learned so far is still somewhat tentative.
>
Here's what is happening. On Ubuntu 20.04, the kdump image is
loaded into crash memory using the kexec command. Ubuntu 20.04
has kexec from the kexec-tools package version 2.0.18-1ubuntu1.1,
and per the kexec man page, it defaults to using the older kexec_load()
system call. When using kexec_load(), the contents to be loaded into
crash memory is constructed in user space by the kexec command.
The kexec command gets the "screen_info" settings, including the
physical address of the frame buffer, via the FBIOGET_FSCREENINFO
ioctl against /dev/fb0. The Hyper-V FB or DRM driver registers itself
with the fbdev subsystem so that it is /dev/fb0, and the ioctl returns
the updated framebuffer address. So the efifb driver loads and runs
correctly.
On Oracle Linux 9.4, the kdump image is also loaded with the
kexec command, but from kexec-tools package version
kexec-tools-2.0.28-1.0.10.el9_5.x86_64, which is slightly later than
the version on Ubuntu 20.04. This newer kexec defaults to using the
newer kexec_file_load() system call. This system call gets the
framebuffer address from the screen_info variable in the kernel, which
has not been updated to reflect the new framebuffer address. Hence
in the kdump kernel, the efifb driver uses the old framebuffer address,
and hence the problem.
To further complicate matters, the kexec on Oracle Linux 9.4 seems to
have a bug when the -c option forces the use of kexec_load() instead
of kexec_file_load(). As an experiment, I modified the kdumpctl shell
script to add the "-c" option to kexec, but in that case the value "0x0"
is passed as the framebuffer address, which is wrong. Furthermore,
the " screen_info.orig_video_isVGA" value (which I mentioned earlier
in connection with commit 2bebc3cd4870) is also set to 0, so the
kdump kernel no longer thinks it has an EFI framebuffer. Hence the
efifb driver isn't loaded, and the kdump works, though for the wrong
reasons. If kexec 2.0.18 from Ubuntu is copied onto the Oracle Linux 9.4
VM, then kdump works as expected, with the efifb driver being loaded
and using the correct framebuffer address. So something is going wrong
with kexec 2.0.28 in how it sets up the screen_info when the -c option
is used. I'll leave the debugging of the kexec bug to someone else.
I'm still thinking about alternatives to fix this mess. Please chime
in if you have suggestions.
Michael