memory: overlapping XENMAPSPACE_gmfn_range requests

Overlapping requests may need processing backwards, or else the intended
effect wouldn't be achieved (and instead some pages would be moved more
than once).

With some adjustment there this also covers XEN_DMOP_relocate_memory,
where the potential issue was first noticed.

Fixes: a04811a315 ("mm: New XENMEM space, XENMAPSPACE_gmfn_range")
Reported-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
Tested-by: Andrew Cooper <andrew.cooper3@citrix.com>
master commit: 7acc7dd36b
master date: 2026-05-13 09:59:19 +0200
This commit is contained in:
Jan Beulich committed 2026-05-19 13:36:20 +02:00
1 parent fd2ccd79ab
commit 7372acade2
2 files changed
+46 -9

No files matched your search

+6 -2
View File
@@ -569,12 +569,16 @@ int dm_op(const struct dmop_args *op_args)
rc = xenmem_add_to_physmap(d, &xatp, 0);
if ( rc == 0 && data->size != xatp.size )
{
rc = xatp.size;
xatp.idx += rc;
xatp.gpfn += rc;
}
if ( rc > 0 )
{
data->size -= rc;
data->src_gfn += rc;
data->dst_gfn += rc;
data->src_gfn = xatp.idx;
data->dst_gfn = xatp.gpfn;
const_op = false;
rc = -ERESTART;
}
+40 -7
View File
@@ -850,7 +850,7 @@ int xenmem_add_to_physmap(struct domain *d, struct xen_add_to_physmap *xatp,
unsigned int start)
{
unsigned int done = 0;
long rc = 0;
long rc = 0, adjust = 1;
union add_to_physmap_extra extra = {};
struct page_info *pages[16];
@@ -885,8 +885,25 @@ int xenmem_add_to_physmap(struct domain *d, struct xen_add_to_physmap *xatp,
return -EOVERFLOW;
}
xatp->idx += start;
xatp->gpfn += start;
/*
* Overlapping ranges need processing backwards when destination is above
* source.
*/
if ( xatp->gpfn > xatp->idx &&
unlikely(xatp->gpfn < xatp->idx + xatp->size) )
{
adjust = -1;
/* Both fields store "next item to process". */
xatp->idx += xatp->size - start - 1;
xatp->gpfn += xatp->size - start - 1;
}
else
{
xatp->idx += start;
xatp->gpfn += start;
}
xatp->size -= start;
#ifdef CONFIG_HAS_PASSTHROUGH
@@ -904,8 +921,8 @@ int xenmem_add_to_physmap(struct domain *d, struct xen_add_to_physmap *xatp,
if ( rc < 0 )
break;
xatp->idx++;
xatp->gpfn++;
xatp->idx += adjust;
xatp->gpfn += adjust;
if ( extra.ppage )
++extra.ppage;
@@ -928,7 +945,10 @@ int xenmem_add_to_physmap(struct domain *d, struct xen_add_to_physmap *xatp,
this_cpu(iommu_dont_flush_iotlb) = 0;
ret = iommu_iotlb_flush(d, _dfn(xatp->idx - done), done,
if ( likely(adjust > 0) )
adjust = done;
ret = iommu_iotlb_flush(d, _dfn(xatp->idx - adjust), done,
IOMMU_FLUSHF_modified);
if ( unlikely(ret) && rc >= 0 )
rc = ret;
@@ -942,13 +962,26 @@ int xenmem_add_to_physmap(struct domain *d, struct xen_add_to_physmap *xatp,
for ( i = 0; i < done; ++i )
put_page(pages[i]);
ret = iommu_iotlb_flush(d, _dfn(xatp->gpfn - done), done,
ret = iommu_iotlb_flush(d, _dfn(xatp->gpfn - adjust), done,
IOMMU_FLUSHF_added | IOMMU_FLUSHF_modified);
if ( unlikely(ret) && rc >= 0 )
rc = ret;
}
#endif
/*
* For internal callers (e.g. XEN_DMOP_relocate_memory handling) leave
* the GFNs from where to resume in *xatp (they're correct already when
* we worked forwards). These are the values not biased for a possible
* non-zero "start" that a subsequent invocation might use, so also do
* this updating only when incoming "start" was 0.
*/
if ( rc > 0 && !start && unlikely(adjust < 0) )
{
xatp->idx -= xatp->size - rc - 1;
xatp->gpfn -= xatp->size - rc - 1;
}
return rc;
}
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.