Re: vm_area at addr ffffffffc0800000 is not marked as VM_IOREMAP

Bjorn Helgaas
2024-03-08T16:13:40Z

On Thu, Mar 07, 2024 at 07:49:16PM -0800, Alexei Starovoitov wrote:
> Ok. I think I figured it out.
> Please try the attached patch.

> PCI address range is managed independently from vmalloc range.

This suggests that the PCI maintainers should be aware of something,
but I don't know what this means. Can you elaborate on what PCI
address range management this is, e.g., what functions allocate from
it? Or how PCI should have been able to avoid this issue?

The patch is in a generic area with no obvious connection to PCI and
no obvious sign of independent management, which doesn't feel quite
right. Maybe this is what Christoph is getting at.

> Enforce flags and range in ioremap_page_range() only when
> the start address is within vmalloc range allocated by get_vm_area().

> Fixes: 3e49a866c9dc ("mm: Enforce VM_IOREMAP flag and range in ioremap_page_range.")
> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
> ---
> mm/vmalloc.c | 23 +++++++++++++----------
> 1 file changed, 13 insertions(+), 10 deletions(-)
>
> diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> index e5b8c70950bc..17eb0f974e0f 100644
> --- a/mm/vmalloc.c
> +++ b/mm/vmalloc.c
> @@ -311,16 +311,19 @@ int ioremap_page_range(unsigned long addr, unsigned long end,
> int err;
>
> area = find_vm_area((void *)addr);
> - if (!area || !(area->flags & VM_IOREMAP)) {
> - WARN_ONCE(1, "vm_area at addr %lx is not marked as VM_IOREMAP\n", addr);
> - return -EINVAL;
> - }
> - if (addr != (unsigned long)area->addr ||
> - (void *)end != area->addr + get_vm_area_size(area)) {
> - WARN_ONCE(1, "ioremap request [%lx,%lx) doesn't match vm_area [%lx, %lx)\n",
> - addr, end, (long)area->addr,
> - (long)area->addr + get_vm_area_size(area));
> - return -ERANGE;
> + if (area) {
> + if (!(area->flags & VM_IOREMAP)) {
> + WARN_ONCE(1, "vm_area at addr %lx is not marked as VM_IOREMAP\n",
> + addr);
> + return -EINVAL;
> + }
> + if (addr != (unsigned long)area->addr ||
> + (void *)end != area->addr + get_vm_area_size(area)) {
> + WARN_ONCE(1, "ioremap request [%lx,%lx) doesn't match vm_area [%lx, %lx)\n",
> + addr, end, (long)area->addr,
> + (long)area->addr + get_vm_area_size(area));
> + return -ERANGE;
> + }
> }
> err = vmap_range_noflush(addr, end, phys_addr, pgprot_nx(prot),
> ioremap_max_page_shift);
> --
> 2.43.0
>