* fbdev deferred I/O broken in some scenarios
@ 2025-03-18 2:05 Michael Kelley
2025-03-18 8:16 ` Helge Deller
2025-03-18 8:25 ` Thomas Zimmermann
0 siblings, 2 replies; 9+ messages in thread
From: Michael Kelley @ 2025-03-18 2:05 UTC (permalink / raw)
To: linux-fbdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, linux-hyperv@vger.kernel.org
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.
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.
Michael Kelley
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: fbdev deferred I/O broken in some scenarios
2025-03-18 2:05 fbdev deferred I/O broken in some scenarios Michael Kelley
@ 2025-03-18 8:16 ` Helge Deller
2025-03-19 20:29 ` Michael Kelley
2025-03-18 8:25 ` Thomas Zimmermann
1 sibling, 1 reply; 9+ messages in thread
From: Helge Deller @ 2025-03-18 8:16 UTC (permalink / raw)
To: Michael Kelley, linux-fbdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, linux-hyperv@vger.kernel.org
Hi Michael,
On 3/18/25 03:05, Michael Kelley wrote:
> 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.
>
> 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.
Helge
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: fbdev deferred I/O broken in some scenarios
2025-03-18 2:05 fbdev deferred I/O broken in some scenarios Michael Kelley
2025-03-18 8:16 ` Helge Deller
@ 2025-03-18 8:25 ` Thomas Zimmermann
2025-03-19 20:38 ` Michael Kelley
1 sibling, 1 reply; 9+ messages in thread
From: Thomas Zimmermann @ 2025-03-18 8:25 UTC (permalink / raw)
To: Michael Kelley, linux-fbdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, linux-hyperv@vger.kernel.org
Hi
Am 18.03.25 um 03:05 schrieb Michael Kelley:
> 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 cannot help much with HyperV, but there's a get_page callback in
struct fb_deferred_io. [1] It'll allow you to provide a custom page on
each page fault. We use it in DRM to mmap SHMEM-backed pages. [2] Maybe
this helps with hyperv_fb as well.
Best regards
Thomas
[1] https://elixir.bootlin.com/linux/v6.13.7/source/include/linux/fb.h#L229
[2]
https://elixir.bootlin.com/linux/v6.13.7/source/drivers/gpu/drm/drm_fbdev_shmem.c#L82
>
> 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.
>
> Michael Kelley
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 9+ messages in thread
* RE: fbdev deferred I/O broken in some scenarios
2025-03-18 8:16 ` Helge Deller
@ 2025-03-19 20:29 ` Michael Kelley
2025-03-20 10:46 ` Geert Uytterhoeven
0 siblings, 1 reply; 9+ messages in thread
From: Michael Kelley @ 2025-03-19 20:29 UTC (permalink / raw)
To: Helge Deller, linux-fbdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, linux-hyperv@vger.kernel.org
From: Helge Deller <deller@gmx.de> Sent: Tuesday, March 18, 2025 1:16 AM
> Hi Michael,
>
> On 3/18/25 03:05, Michael Kelley wrote:
> > 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.
> >
> > 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
Do you have any ownership or status information about the last two? Neither is
listed in MAINTAINERS, so maybe they are for old devices and now effectively
abandoned. Before I make code changes to fb_defio.c, I wanted to make sure
I have all the context I can get, such as why this problem hasn't surfaced outside
of the hyperv_fb.c driver. Part of the reason is that evidently the vmalloc() based
approach is more common, and it works fine. With only two other drivers using
contiguous kernel memory allocations, and with those two perhaps being for old
and now mostly unused devices, that might explain things. The hyperv_fb.c
config that uses contiguous kernel memory is also somewhat rare, and I only
stumbled across it when debugging other problems.
In any case, I'm pretty convinced this is an issue with fb_defio.c and not
something specific to hyperv_fb.c, so I'll get to work on a fix and how it goes
from there.
Michael
^ permalink raw reply [flat|nested] 9+ messages in thread
* RE: fbdev deferred I/O broken in some scenarios
2025-03-18 8:25 ` Thomas Zimmermann
@ 2025-03-19 20:38 ` Michael Kelley
2025-03-20 7:45 ` Thomas Zimmermann
0 siblings, 1 reply; 9+ messages in thread
From: Michael Kelley @ 2025-03-19 20:38 UTC (permalink / raw)
To: Thomas Zimmermann, linux-fbdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, linux-hyperv@vger.kernel.org
From: Thomas Zimmermann <tzimmermann@suse.de> Sent: Tuesday, March 18, 2025 1:26 AM
>
> Am 18.03.25 um 03:05 schrieb Michael Kelley:
> > 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 cannot help much with HyperV, but there's a get_page callback in
> struct fb_deferred_io. [1] It'll allow you to provide a custom page on
> each page fault. We use it in DRM to mmap SHMEM-backed pages. [2] Maybe
> this helps with hyperv_fb as well.
>
Thanks for your input. See also my reply to Helge.
Unfortunately, using a custom get_page() callback doesn't help. In the problematic
case, the standard deferred I/O get_page() function works correctly for getting the
struct page. My current thinking is that the problem is in fb_deferred_io_mmap()
where the vma needs to have the VM_PFNMAP flag set when the framebuffer
memory is a direct kernel allocation and not through vmalloc(). And there may be
some implications on the mkwrite function as well, but I'll need to sort that out
once I start coding.
For the DRM code using SHMEM-backed pages, do you know where the shared
memory comes from? Is that ultimately a kernel vmalloc() allocation?
Michael
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: fbdev deferred I/O broken in some scenarios
2025-03-19 20:38 ` Michael Kelley
@ 2025-03-20 7:45 ` Thomas Zimmermann
0 siblings, 0 replies; 9+ messages in thread
From: Thomas Zimmermann @ 2025-03-20 7:45 UTC (permalink / raw)
To: Michael Kelley, linux-fbdev@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, linux-hyperv@vger.kernel.org
Hi
Am 19.03.25 um 21:38 schrieb Michael Kelley:
> From: Thomas Zimmermann <tzimmermann@suse.de> Sent: Tuesday, March 18, 2025 1:26 AM
>> Am 18.03.25 um 03:05 schrieb Michael Kelley:
>>> 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 cannot help much with HyperV, but there's a get_page callback in
>> struct fb_deferred_io. [1] It'll allow you to provide a custom page on
>> each page fault. We use it in DRM to mmap SHMEM-backed pages. [2] Maybe
>> this helps with hyperv_fb as well.
>>
> Thanks for your input. See also my reply to Helge.
>
> Unfortunately, using a custom get_page() callback doesn't help. In the problematic
> case, the standard deferred I/O get_page() function works correctly for getting the
> struct page. My current thinking is that the problem is in fb_deferred_io_mmap()
> where the vma needs to have the VM_PFNMAP flag set when the framebuffer
> memory is a direct kernel allocation and not through vmalloc(). And there may be
> some implications on the mkwrite function as well, but I'll need to sort that out
> once I start coding.
>
> For the DRM code using SHMEM-backed pages, do you know where the shared
> memory comes from? Is that ultimately a kernel vmalloc() allocation?
I think it's something special, as the regular vmalloc'ed-pages would be
handled by fb_defio automatically. In DRM we sometimes also use a
separate vmalloc'ed shadow buffer that serves as the fbdev framebuffer.
We then sync internally with the physical framebuffer memory. See [1]
for the related code. Udlfb does the as well IIRC.
Best regards
Thomas
[1]
https://elixir.bootlin.com/linux/v6.13.7/source/drivers/gpu/drm/drm_fbdev_ttm.c#L201
>
> Michael
>
--
--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Frankenstrasse 146, 90461 Nuernberg, Germany
GF: Ivo Totev, Andrew Myers, Andrew McDonald, Boudien Moerman
HRB 36809 (AG Nuernberg)
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: fbdev deferred I/O broken in some scenarios
2025-03-19 20:29 ` Michael Kelley
@ 2025-03-20 10:46 ` Geert Uytterhoeven
2025-03-20 20:15 ` Michael Kelley
0 siblings, 1 reply; 9+ messages in thread
From: Geert Uytterhoeven @ 2025-03-20 10:46 UTC (permalink / raw)
To: Michael Kelley
Cc: Helge Deller, linux-fbdev@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-hyperv@vger.kernel.org
Hi Michael,
On Wed, 19 Mar 2025 at 21:29, Michael Kelley <mhklinux@outlook.com> wrote:
> From: Helge Deller <deller@gmx.de> Sent: Tuesday, March 18, 2025 1:16 AM
> > On 3/18/25 03:05, Michael Kelley wrote:
> > > 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?
> > > 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
^ permalink raw reply [flat|nested] 9+ messages in thread
* RE: fbdev deferred I/O broken in some scenarios
2025-03-20 10:46 ` Geert Uytterhoeven
@ 2025-03-20 20:15 ` Michael Kelley
2025-03-24 13:59 ` Geert Uytterhoeven
0 siblings, 1 reply; 9+ messages in thread
From: Michael Kelley @ 2025-03-20 20:15 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Helge Deller, linux-fbdev@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-hyperv@vger.kernel.org
From: Geert Uytterhoeven <geert@linux-m68k.org> Sent: Thursday, March 20, 2025 3:46 AM
>
> Hi Michael,
>
> On Wed, 19 Mar 2025 at 21:29, Michael Kelley <mhklinux@outlook.com> wrote:
> > From: Helge Deller <deller@gmx.de> Sent: Tuesday, March 18, 2025 1:16 AM
> > > On 3/18/25 03:05, Michael Kelley wrote:
> > > > 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?
Yes. I have my own little program, but it is similar to what I see fbtest does.
>
> > > > 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.
OK, good to know. sh_mobile_lcdcfb gets its framebuffer using
dma_alloc_coherent(). Do you recall how big the framebuffer was?
If over 4 MiB, dma_alloc_coherent() would have allocated from CMA,
and that works OK.
>
> 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.
The st7735r driver appears to use fbtft-core.c, and that does a vmalloc()
for the screen buffer, so it won't have the problem I'm seeing.
Thanks for the help ....
Michael
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: fbdev deferred I/O broken in some scenarios
2025-03-20 20:15 ` Michael Kelley
@ 2025-03-24 13:59 ` Geert Uytterhoeven
0 siblings, 0 replies; 9+ messages in thread
From: Geert Uytterhoeven @ 2025-03-24 13:59 UTC (permalink / raw)
To: Michael Kelley
Cc: Helge Deller, linux-fbdev@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-hyperv@vger.kernel.org
Hi Michael,
On Thu, 20 Mar 2025 at 21:15, Michael Kelley <mhklinux@outlook.com> wrote:
> From: Geert Uytterhoeven <geert@linux-m68k.org> Sent: Thursday, March 20, 2025 3:46 AM
> > On Wed, 19 Mar 2025 at 21:29, Michael Kelley <mhklinux@outlook.com> wrote:
> > > From: Helge Deller <deller@gmx.de> Sent: Tuesday, March 18, 2025 1:16 AM
> > > > On 3/18/25 03:05, Michael Kelley wrote:
> > > > > 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.
>
> OK, good to know. sh_mobile_lcdcfb gets its framebuffer using
> dma_alloc_coherent(). Do you recall how big the framebuffer was?
> If over 4 MiB, dma_alloc_coherent() would have allocated from CMA,
> and that works OK.
1536000 bytes (800x480 (960 virtual), 16bpp), i.e. less than 4 MiB.
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
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2025-03-24 14:00 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-18 2:05 fbdev deferred I/O broken in some scenarios Michael Kelley
2025-03-18 8:16 ` Helge Deller
2025-03-19 20:29 ` Michael Kelley
2025-03-20 10:46 ` Geert Uytterhoeven
2025-03-20 20:15 ` Michael Kelley
2025-03-24 13:59 ` Geert Uytterhoeven
2025-03-18 8:25 ` Thomas Zimmermann
2025-03-19 20:38 ` Michael Kelley
2025-03-20 7:45 ` Thomas Zimmermann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).