[PATCH v1 1/2] hw/vfio: sort and validate sparse mmap regions by offset

ankita@nvidia.com posted 2 patches 1 week, 3 days ago
Maintainers: Alex Williamson <alex@shazbot.org>, "Cédric Le Goater" <clg@redhat.com>
[PATCH v1 1/2] hw/vfio: sort and validate sparse mmap regions by offset
Posted by ankita@nvidia.com 1 week, 3 days ago
From: Ankit Agrawal <ankita@nvidia.com>

Sort sparse mmap regions by offset during region setup to ensure
predictable mapping order, avoid overlaps and a proper handling
of the gaps between sub-regions.

Add validation to detect overlapping sparse regions early during
setup before any mapping operations begin.

The sorting is performed on the subregions ranges during
vfio_setup_region_sparse_mmaps(). This also ensures that subsequent
mapping code can rely on subregions being in ascending offset order.

This is preparatory work for alignment adjustments needed to support
hugepfnmap on systems where device memory (e.g., Grace-based systems)
may have non-power-of-2 sizes.

cc: Alex Williamson <alex@shazbot.org>
Signed-off-by: Ankit Agrawal <ankita@nvidia.com>
---
 hw/vfio/region.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 44 insertions(+), 1 deletion(-)

diff --git a/hw/vfio/region.c b/hw/vfio/region.c
index ab39d77574..7622ae5683 100644
--- a/hw/vfio/region.c
+++ b/hw/vfio/region.c
@@ -149,6 +149,19 @@ static const MemoryRegionOps vfio_region_ops = {
     },
 };
 
+static int vfio_mmap_compare_offset(const void *a, const void *b)
+{
+    const VFIOMmap *mmap_a = a;
+    const VFIOMmap *mmap_b = b;
+
+    if (mmap_a->offset < mmap_b->offset) {
+        return -1;
+    } else if (mmap_a->offset > mmap_b->offset) {
+        return 1;
+    }
+    return 0;
+}
+
 static int vfio_setup_region_sparse_mmaps(VFIORegion *region,
                                           struct vfio_region_info *info)
 {
@@ -182,6 +195,34 @@ static int vfio_setup_region_sparse_mmaps(VFIORegion *region,
     region->nr_mmaps = j;
     region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap));
 
+    /*
+     * Sort sparse mmaps by offset to ensure proper handling of gaps
+     * and predictable mapping order in vfio_region_mmap().
+     */
+    if (region->nr_mmaps > 1) {
+        qsort(region->mmaps, region->nr_mmaps, sizeof(VFIOMmap),
+              vfio_mmap_compare_offset);
+
+        /*
+         * Validate that sparse regions dont overlap after sorting.
+         */
+        for (i = 1; i < region->nr_mmaps; i++) {
+            off_t prev_end = region->mmaps[i - 1].offset +
+                             region->mmaps[i - 1].size;
+            if (prev_end > region->mmaps[i].offset) {
+                error_report("%s: overlapping sparse mmap regions detected "
+                             "in region %d: [0x%lx-0x%lx] overlaps with [0x%lx-0x%lx]",
+                             __func__, region->nr, region->mmaps[i - 1].offset,
+                             prev_end - 1, region->mmaps[i].offset,
+                             region->mmaps[i].offset + region->mmaps[i].size - 1);
+                g_free(region->mmaps);
+                region->mmaps = NULL;
+                region->nr_mmaps = 0;
+                return -EINVAL;
+            }
+        }
+    }
+
     return 0;
 }
 
@@ -213,11 +254,13 @@ int vfio_region_setup(Object *obj, VFIODevice *vbasedev, VFIORegion *region,
 
             ret = vfio_setup_region_sparse_mmaps(region, info);
 
-            if (ret) {
+            if (ret == -ENODEV) {
                 region->nr_mmaps = 1;
                 region->mmaps = g_new0(VFIOMmap, region->nr_mmaps);
                 region->mmaps[0].offset = 0;
                 region->mmaps[0].size = region->size;
+            } else {
+                return ret;
             }
         }
     }
-- 
2.34.1
RE: [PATCH v1 1/2] hw/vfio: sort and validate sparse mmap regions by offset
Posted by Shameer Kolothum Thodi 1 week, 3 days ago

> -----Original Message-----
> From: Ankit Agrawal <ankita@nvidia.com>
> Sent: 30 January 2026 04:07
> To: Ankit Agrawal <ankita@nvidia.com>; Vikram Sethi <vsethi@nvidia.com>;
> Jason Gunthorpe <jgg@nvidia.com>; Shameer Kolothum Thodi
> <skolothumtho@nvidia.com>; alex@shazbot.org; clg@redhat.com
> Cc: Aniket Agashe <aniketa@nvidia.com>; Neo Jia <cjia@nvidia.com>; Kirti
> Wankhede <kwankhede@nvidia.com>; Tarun Gupta (SW-GPU)
> <targupta@nvidia.com>; Zhi Wang <zhiw@nvidia.com>; Matt Ochs
> <mochs@nvidia.com>; Krishnakant Jaju <kjaju@nvidia.com>; qemu-
> devel@nongnu.org
> Subject: [PATCH v1 1/2] hw/vfio: sort and validate sparse mmap regions by
> offset
> 
> From: Ankit Agrawal <ankita@nvidia.com>
> 
> Sort sparse mmap regions by offset during region setup to ensure
> predictable mapping order, avoid overlaps and a proper handling
> of the gaps between sub-regions.
> 
> Add validation to detect overlapping sparse regions early during
> setup before any mapping operations begin.
> 
> The sorting is performed on the subregions ranges during
> vfio_setup_region_sparse_mmaps(). This also ensures that subsequent
> mapping code can rely on subregions being in ascending offset order.
> 
> This is preparatory work for alignment adjustments needed to support
> hugepfnmap on systems where device memory (e.g., Grace-based systems)
> may have non-power-of-2 sizes.
> 
> cc: Alex Williamson <alex@shazbot.org>
> Signed-off-by: Ankit Agrawal <ankita@nvidia.com>
> ---
>  hw/vfio/region.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 44 insertions(+), 1 deletion(-)
> 
> diff --git a/hw/vfio/region.c b/hw/vfio/region.c
> index ab39d77574..7622ae5683 100644
> --- a/hw/vfio/region.c
> +++ b/hw/vfio/region.c
> @@ -149,6 +149,19 @@ static const MemoryRegionOps vfio_region_ops = {
>      },
>  };
> 
> +static int vfio_mmap_compare_offset(const void *a, const void *b)
> +{
> +    const VFIOMmap *mmap_a = a;
> +    const VFIOMmap *mmap_b = b;
> +
> +    if (mmap_a->offset < mmap_b->offset) {
> +        return -1;
> +    } else if (mmap_a->offset > mmap_b->offset) {
> +        return 1;
> +    }
> +    return 0;
> +}
> +
>  static int vfio_setup_region_sparse_mmaps(VFIORegion *region,
>                                            struct vfio_region_info *info)
>  {
> @@ -182,6 +195,34 @@ static int
> vfio_setup_region_sparse_mmaps(VFIORegion *region,
>      region->nr_mmaps = j;
>      region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap));
> 
> +    /*
> +     * Sort sparse mmaps by offset to ensure proper handling of gaps
> +     * and predictable mapping order in vfio_region_mmap().
> +     */
> +    if (region->nr_mmaps > 1) {
> +        qsort(region->mmaps, region->nr_mmaps, sizeof(VFIOMmap),
> +              vfio_mmap_compare_offset);
> +
> +        /*
> +         * Validate that sparse regions dont overlap after sorting.
> +         */
> +        for (i = 1; i < region->nr_mmaps; i++) {
> +            off_t prev_end = region->mmaps[i - 1].offset +
> +                             region->mmaps[i - 1].size;
> +            if (prev_end > region->mmaps[i].offset) {
> +                error_report("%s: overlapping sparse mmap regions detected "
> +                             "in region %d: [0x%lx-0x%lx] overlaps with [0x%lx-0x%lx]",
> +                             __func__, region->nr, region->mmaps[i - 1].offset,
> +                             prev_end - 1, region->mmaps[i].offset,
> +                             region->mmaps[i].offset + region->mmaps[i].size - 1);
> +                g_free(region->mmaps);
> +                region->mmaps = NULL;
> +                region->nr_mmaps = 0;
> +                return -EINVAL;
> +            }
> +        }
> +    }
> +
>      return 0;
>  }
> 
> @@ -213,11 +254,13 @@ int vfio_region_setup(Object *obj, VFIODevice
> *vbasedev, VFIORegion *region,
> 
>              ret = vfio_setup_region_sparse_mmaps(region, info);
> 
> -            if (ret) {
> +            if (ret == -ENODEV) {
>                  region->nr_mmaps = 1;
>                  region->mmaps = g_new0(VFIOMmap, region->nr_mmaps);
>                  region->mmaps[0].offset = 0;
>                  region->mmaps[0].size = region->size;
> +            } else {
> +                return ret;
>              }

Is this now returns without the trace_xxx , right?

With that fixed:
Reviewed-by: Shameer Kolothum <skolothumtho@nvidia.com>

Thanks,
Shameer

>          }
>      }
> --
> 2.34.1
Re: [PATCH v1 1/2] hw/vfio: sort and validate sparse mmap regions by offset
Posted by Alex Williamson 1 week, 2 days ago
On Fri, 30 Jan 2026 09:33:44 +0000
Shameer Kolothum Thodi <skolothumtho@nvidia.com> wrote:

> > -----Original Message-----
> > From: Ankit Agrawal <ankita@nvidia.com>
> > Sent: 30 January 2026 04:07
> > To: Ankit Agrawal <ankita@nvidia.com>; Vikram Sethi <vsethi@nvidia.com>;
> > Jason Gunthorpe <jgg@nvidia.com>; Shameer Kolothum Thodi
> > <skolothumtho@nvidia.com>; alex@shazbot.org; clg@redhat.com
> > Cc: Aniket Agashe <aniketa@nvidia.com>; Neo Jia <cjia@nvidia.com>; Kirti
> > Wankhede <kwankhede@nvidia.com>; Tarun Gupta (SW-GPU)
> > <targupta@nvidia.com>; Zhi Wang <zhiw@nvidia.com>; Matt Ochs
> > <mochs@nvidia.com>; Krishnakant Jaju <kjaju@nvidia.com>; qemu-
> > devel@nongnu.org
> > Subject: [PATCH v1 1/2] hw/vfio: sort and validate sparse mmap regions by
> > offset
> > 
> > From: Ankit Agrawal <ankita@nvidia.com>
> > 
> > Sort sparse mmap regions by offset during region setup to ensure
> > predictable mapping order, avoid overlaps and a proper handling
> > of the gaps between sub-regions.
> > 
> > Add validation to detect overlapping sparse regions early during
> > setup before any mapping operations begin.
> > 
> > The sorting is performed on the subregions ranges during
> > vfio_setup_region_sparse_mmaps(). This also ensures that subsequent
> > mapping code can rely on subregions being in ascending offset order.
> > 
> > This is preparatory work for alignment adjustments needed to support
> > hugepfnmap on systems where device memory (e.g., Grace-based systems)
> > may have non-power-of-2 sizes.
> > 
> > cc: Alex Williamson <alex@shazbot.org>
> > Signed-off-by: Ankit Agrawal <ankita@nvidia.com>
> > ---
> >  hw/vfio/region.c | 45 ++++++++++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 44 insertions(+), 1 deletion(-)
> > 
> > diff --git a/hw/vfio/region.c b/hw/vfio/region.c
> > index ab39d77574..7622ae5683 100644
> > --- a/hw/vfio/region.c
> > +++ b/hw/vfio/region.c
> > @@ -149,6 +149,19 @@ static const MemoryRegionOps vfio_region_ops = {
> >      },
> >  };
> > 
> > +static int vfio_mmap_compare_offset(const void *a, const void *b)
> > +{
> > +    const VFIOMmap *mmap_a = a;
> > +    const VFIOMmap *mmap_b = b;
> > +
> > +    if (mmap_a->offset < mmap_b->offset) {
> > +        return -1;
> > +    } else if (mmap_a->offset > mmap_b->offset) {
> > +        return 1;
> > +    }
> > +    return 0;
> > +}
> > +
> >  static int vfio_setup_region_sparse_mmaps(VFIORegion *region,
> >                                            struct vfio_region_info *info)
> >  {
> > @@ -182,6 +195,34 @@ static int
> > vfio_setup_region_sparse_mmaps(VFIORegion *region,
> >      region->nr_mmaps = j;
> >      region->mmaps = g_realloc(region->mmaps, j * sizeof(VFIOMmap));
> > 
> > +    /*
> > +     * Sort sparse mmaps by offset to ensure proper handling of gaps
> > +     * and predictable mapping order in vfio_region_mmap().
> > +     */
> > +    if (region->nr_mmaps > 1) {
> > +        qsort(region->mmaps, region->nr_mmaps, sizeof(VFIOMmap),
> > +              vfio_mmap_compare_offset);
> > +
> > +        /*
> > +         * Validate that sparse regions dont overlap after sorting.
> > +         */
> > +        for (i = 1; i < region->nr_mmaps; i++) {
> > +            off_t prev_end = region->mmaps[i - 1].offset +
> > +                             region->mmaps[i - 1].size;
> > +            if (prev_end > region->mmaps[i].offset) {
> > +                error_report("%s: overlapping sparse mmap regions detected "
> > +                             "in region %d: [0x%lx-0x%lx] overlaps with [0x%lx-0x%lx]",
> > +                             __func__, region->nr, region->mmaps[i - 1].offset,
> > +                             prev_end - 1, region->mmaps[i].offset,
> > +                             region->mmaps[i].offset + region->mmaps[i].size - 1);
> > +                g_free(region->mmaps);
> > +                region->mmaps = NULL;
> > +                region->nr_mmaps = 0;
> > +                return -EINVAL;
> > +            }
> > +        }
> > +    }
> > +
> >      return 0;
> >  }
> > 
> > @@ -213,11 +254,13 @@ int vfio_region_setup(Object *obj, VFIODevice
> > *vbasedev, VFIORegion *region,
> > 
> >              ret = vfio_setup_region_sparse_mmaps(region, info);
> > 
> > -            if (ret) {
> > +            if (ret == -ENODEV) {
> >                  region->nr_mmaps = 1;
> >                  region->mmaps = g_new0(VFIOMmap, region->nr_mmaps);
> >                  region->mmaps[0].offset = 0;
> >                  region->mmaps[0].size = region->size;
> > +            } else {
> > +                return ret;
> >              }  
> 
> Is this now returns without the trace_xxx , right?
> 
> With that fixed:
> Reviewed-by: Shameer Kolothum <skolothumtho@nvidia.com>

Right, I think this was probably meant to be 'else if (ret)' so the
newly added -EINVAL generates an error w/o trace while the non-error
path should fall through.  Thanks,

Alex
Re: [PATCH v1 1/2] hw/vfio: sort and validate sparse mmap regions by offset
Posted by Ankit Agrawal 5 days, 13 hours ago
>> >                  region->mmaps[0].size = region->size;
>> > +            } else {
>> > +                return ret;
>> >              }
>>
>> Is this now returns without the trace_xxx , right?
>>
>> With that fixed:
>> Reviewed-by: Shameer Kolothum <skolothumtho@nvidia.com>
>
> Right, I think this was probably meant to be 'else if (ret)' so the
> newly added -EINVAL generates an error w/o trace while the non-error
> path should fall through.  Thanks,

Thanks for catching that and for the review! Will fix in v2.