Thread (9 messages) 9 messages, 4 authors, 2025-03-24

Re: fbdev deferred I/O broken in some scenarios

From: Geert Uytterhoeven <geert@linux-m68k.org>
Date: 2025-03-20 10:46:32
Also in: linux-fbdev, lkml

Hi Michael,

On Wed, 19 Mar 2025 at 21:29, Michael Kelley [off-list ref] wrote:
From: Helge Deller <deller@gmx.de> Sent: Tuesday, March 18, 2025 1:16 AM
quoted
On 3/18/25 03:05, Michael Kelley wrote:
quoted
I've been trying to get mmap() working with the hyperv_fb.c fbdev driver, which
is for Linux guests running on Microsoft's Hyper-V hypervisor. The hyperv_fb driver
uses fbdev deferred I/O for performance reasons. But it looks to me like fbdev
deferred I/O is fundamentally broken when the underlying framebuffer memory
is allocated from kernel memory (alloc_pages or dma_alloc_coherent).

The hyperv_fb.c driver may allocate the framebuffer memory in several ways,
depending on the size of the framebuffer specified by the Hyper-V host and the VM
"Generation".  For a Generation 2 VM, the framebuffer memory is allocated by the
Hyper-V host and is assigned to guest MMIO space. The hyperv_fb driver does a
vmalloc() allocation for deferred I/O to work against. This combination handles mmap()
of /dev/fb<n> correctly and the performance benefits of deferred I/O are substantial.

But for a Generation 1 VM, the hyperv_fb driver allocates the framebuffer memory in
contiguous guest physical memory using alloc_pages() or dma_alloc_coherent(), and
informs the Hyper-V host of the location. In this case, mmap() with deferred I/O does
not work. The mmap() succeeds, and user space updates to the mmap'ed memory are
correctly reflected to the framebuffer. But when the user space program does munmap()
or terminates, the Linux kernel free lists become scrambled and the kernel eventually
panics. The problem is that when munmap() is done, the PTEs in the VMA are cleaned
up, and the corresponding struct page refcounts are decremented. If the refcount goes
to zero (which it typically will), the page is immediately freed. In this way, some or all
of the framebuffer memory gets erroneously freed. From what I see, the VMA should
be marked VM_PFNMAP when allocated memory kernel is being used as the
framebuffer with deferred I/O, but that's not happening. The handling of deferred I/O
page faults would also need updating to make this work.
I assume this is triggered by running any fbdev userspace that uses
mmap(), e.g. fbtest?
quoted
quoted
The fbdev deferred I/O support was originally added to the hyperv_fb driver in the
5.6 kernel, and based on my recent experiments, it has never worked correctly when
the framebuffer is allocated from kernel memory. fbdev deferred I/O support for using
kernel memory as the framebuffer was originally added in commit 37b4837959cb9
back in 2008 in Linux 2.6.29. But I don't see how it ever worked properly, unless
changes in generic memory management somehow broke it in the intervening years.

I think I know how to fix all this. But before working on a patch, I wanted to check
with the fbdev community to see if this might be a known issue and whether there
is any additional insight someone might offer. Thanks for any comments or help.
I haven't heard of any major deferred-i/o issues since I've jumped into fbdev
maintenance. But you might be right, as I haven't looked much into it yet and
there are just a few drivers using it.
Thanks for the input. In the fbdev directory, there are 9 drivers using deferred I/O.
Of those, 6 use vmalloc() to allocate the framebuffer, and that path works just fine.
The other 3 use alloc_pages(), dma_alloc_coherent(), or __get_free_pages(), all of
which manifest the underlying problem when munmap()'ed.  Those 3 drivers are:

* hyperv_fb.c, which I'm working with
* sh_mobile_lcdcfb.c
* ssd1307fb.c
Nowadays sh_mobile_lcdcfb is used only on various SuperH boards
(I have no hardware to test).

sh_mobile_lcdcfb was used on ARM-based SH/R-Mobile SoCs until DT
support was added to the DRM driver for the corresponding hardware.
The platform using it was migrated to DRM in commit 138588e9fa237f97
("ARM: dts: renesas: r8a7740: Add LCDC nodes") in v6.8). At the time
of the conversion, fbtest worked fine with sh_mobile_lcdcfb.

Deferred I/O is also used in DRM drivers for displays that are connected
using I2C or SPI.  Last time I tried the st7735r driver, it worked fine
with fbtest.  That was also on arm32, though.

Gr{oetje,eeting}s,

                        Geert


--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help