[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen staging] tests/paging-mempool: Extend to test P2M relocation



commit 66c982a5d3614f0905952d8cf8af1b467c516994
Author:     Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
AuthorDate: Mon May 11 16:26:12 2026 +0100
Commit:     Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
CommitDate: Wed May 13 16:44:34 2026 +0100

    tests/paging-mempool: Extend to test P2M relocation
    
    XENMAPSPACE_gmfn_range was found to be buggy with overlapping ranges, and 
the
    fix is sufficiently far from clear that yours truly decided a test was in
    order.
    
    XENMAPSPACE_gmfn_range is exposed by xendevicemodel_relocate_memory() so 
take
    the opportunity to create a better example for others to copy.
    
    The test works as follows.  Populate 2M of RAM in the guest, marking the 
pages
    so they can be identified later.  Then construct four relocation test
    cases (overlapping vs non-overlapping, forwards vs backwards) using the 
marks
    in the guest pages to confirm that the P2M was adjusted correctly.
    
    The use of XEN_DOMCTL_CDF_iommu forces xenmem_add_to_physmap() to limit the
    iteration count to a maximum of 16.  Use this to force a continuation and
    exercise more of the logic.
    
    Signed-off-by: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
    Acked-by: Jan Beulich <jbeulich@xxxxxxxx>
---
 tools/tests/paging-mempool/Makefile              |   4 +
 tools/tests/paging-mempool/test-paging-mempool.c | 205 ++++++++++++++++++++++-
 xen/common/memory.c                              |   2 +-
 3 files changed, 209 insertions(+), 2 deletions(-)

diff --git a/tools/tests/paging-mempool/Makefile 
b/tools/tests/paging-mempool/Makefile
index a1e12584ce..7444d81b84 100644
--- a/tools/tests/paging-mempool/Makefile
+++ b/tools/tests/paging-mempool/Makefile
@@ -25,9 +25,13 @@ uninstall:
 
 CFLAGS += $(CFLAGS_xeninclude)
 CFLAGS += $(CFLAGS_libxenctrl)
+CFLAGS += $(CFLAGS_libxendevicemodel)
+CFLAGS += $(CFLAGS_libxenforeignmemory)
 CFLAGS += $(APPEND_CFLAGS)
 
 LDFLAGS += $(LDLIBS_libxenctrl)
+LDFLAGS += $(LDLIBS_libxendevicemodel)
+LDFLAGS += $(LDLIBS_libxenforeignmemory)
 LDFLAGS += $(APPEND_LDFLAGS)
 
 %.o: Makefile
diff --git a/tools/tests/paging-mempool/test-paging-mempool.c 
b/tools/tests/paging-mempool/test-paging-mempool.c
index 9ef8252126..3c87925288 100644
--- a/tools/tests/paging-mempool/test-paging-mempool.c
+++ b/tools/tests/paging-mempool/test-paging-mempool.c
@@ -6,6 +6,7 @@
 #include <sys/mman.h>
 
 #include <xenctrl.h>
+#include <xendevicemodel.h>
 #include <xenforeignmemory.h>
 #include <xengnttab.h>
 #include <xen-tools/common-macros.h>
@@ -19,10 +20,15 @@ static unsigned int nr_failures;
 })
 
 static xc_interface *xch;
+static xendevicemodel_handle *dh;
+static xenforeignmemory_handle *fh;
 static uint32_t domid;
 
 static struct xen_domctl_createdomain create = {
-    .flags = XEN_DOMCTL_CDF_hvm | XEN_DOMCTL_CDF_hap,
+    .flags = (XEN_DOMCTL_CDF_hvm |
+              XEN_DOMCTL_CDF_hap |
+              XEN_DOMCTL_CDF_iommu |
+              0),
     .max_vcpus = 1,
     .max_grant_frames = 1,
     .grant_opts = XEN_DOMCTL_GRANT_version(1),
@@ -146,6 +152,191 @@ static int test_paging_mempool_size(void)
     return 0;
 }
 
+static int mark_guest_mem(xen_pfn_t gfn, size_t count)
+{
+    xen_pfn_t gfns[count];
+    uint32_t *mem;
+    size_t i;
+    int rc;
+
+    for ( i = 0; i < count; ++i )
+        gfns[i] = gfn + i;
+
+    mem = xenforeignmemory_map(fh, domid, PROT_READ | PROT_WRITE,
+                               count, gfns, NULL);
+    if ( !mem )
+        return fail("  Fail: mark mem foreign map: %d - %s\n",
+                    errno, strerror(errno));
+
+    for ( i = 0; i < count; ++i )
+    {
+        uint32_t *mark = &mem[i << 10];
+
+        *mark = ~i;
+    }
+
+    rc = xenforeignmemory_unmap(fh, mem, count);
+    if ( rc )
+        return fail("  Fail: mark mem foreign unmap: %d - %s\n",
+                    errno, strerror(errno));
+
+    return 0;
+}
+
+static int check_guest_marks(xen_pfn_t gfn, uint32_t mark_start, size_t count)
+{
+    xen_pfn_t gfns[count];
+    int errs[count];
+    uint32_t *mem;
+    size_t i;
+    int rc = 0;
+
+    for ( i = 0; i < count; ++i )
+        gfns[i] = gfn + i;
+
+    mem = xenforeignmemory_map(fh, domid, PROT_READ,
+                               count, gfns, errs);
+    if ( !mem )
+        return fail("    Fail: check mark foreign map: %d - %s\n",
+                    errno, strerror(errno));
+
+    for ( i = 0; i < count; ++i )
+    {
+        uint32_t *mark = &mem[i << 10];
+        uint32_t exp = ~(mark_start + i);
+
+        if ( errs[i] )
+        {
+            rc = -1;
+            fail("    Fail: check mark unable to map gfn %05lx: %d\n",
+                 gfns[i], errs[i]);
+            continue;
+        }
+
+        if ( *mark == exp )
+            continue;
+
+        fail("    Fail: check mark: gfn %05lx expecting %08x (%u), got %08x 
(%u)\n",
+               gfns[i], exp, ~exp, *mark, ~*mark);
+        rc = -1;
+    }
+
+    if ( xenforeignmemory_unmap(fh, mem, count) )
+        return fail("    Fail: check marks foreign unmap: %d - %s\n",
+                    errno, strerror(errno));
+
+    return rc;
+}
+
+static int test_p2m_relocate_memory(void)
+{
+#define GFN_2M ((2UL << 20) >> 12)
+#define GFN_4M ((4UL << 20) >> 12)
+
+    xen_pfn_t physmap[] = { GFN_2M };
+    int rc;
+
+    /*
+     * Inherited state of the domain:
+     * - Unlimited allocation
+     * - XEN_DOMCTL_CDF_iommu, which causes xendevicemodel_relocate_memory()
+     *   to undergo continuations every 16 pages
+     *
+     * Construction of the test:
+     * - Populate 2M at 2M, mark the pages.
+     */
+    printf("Test p2m memory relocation\n");
+
+    rc = xc_domain_populate_physmap_exact(
+        xch, domid, ARRAY_SIZE(physmap),
+        9 /* order 2M */, 0 /* flags */, physmap);
+    if ( rc )
+        return fail("  Fail: populate physmap: %d - %s\n",
+                    errno, strerror(errno));
+
+    rc = mark_guest_mem(GFN_2M, 1 << 9 /* order 2M */);
+    if ( rc )
+        return rc;
+
+    /* Sanity check the start and end markers. */
+    if ( (rc = check_guest_marks(GFN_2M,     0,       8)) ||
+         (rc = check_guest_marks(GFN_4M - 8, 512 - 8, 8)) )
+        return rc;
+
+
+#define GFN_PAIR(g, c) (g), ((g) + (c) - 1)
+
+    /*
+     * Move the final 32 pages below 4M forward by 32 pages.  All destination
+     * GFNs free, and no overlap.
+     */
+    printf("  Test forward, no overlap:    GFNs [%lx...%lx] -> [%lx...%lx]\n",
+           GFN_PAIR(GFN_4M - 32, 32), GFN_PAIR(GFN_4M, 32));
+
+    rc = xendevicemodel_relocate_memory(dh, domid, 32, GFN_4M - 32, GFN_4M);
+    if ( rc )
+        return fail("  Fail: relocate memory: %d - %s\n",
+                    errno, strerror(errno));
+
+    rc = check_guest_marks(GFN_4M, 512 - 32, 32);
+    if ( rc )
+        return rc;
+
+    /*
+     * Move the next 32 pages below 4M forward by 1 page.  The region is
+     * almost completely overlapping.
+     */
+    printf("  Test forward, overlapping:   GFNs [%lx...%lx] -> [%lx...%lx]\n",
+           GFN_PAIR(GFN_4M - 64, 32), GFN_PAIR(GFN_4M - 63, 32));
+
+    rc = xendevicemodel_relocate_memory(dh, domid, 32, GFN_4M - 64, GFN_4M - 
63);
+    if ( rc )
+        return fail("  Fail: relocate memory: %d - %s\n",
+                    errno, strerror(errno));
+
+    rc = check_guest_marks(GFN_4M - 63, 512 - 64, 32);
+    if ( rc )
+        return rc;
+
+    /*
+     * Move the first 32 pages above 2M backwards by 32 pages.  All
+     * destination GFNs free, and no overlap.
+     */
+    printf("  Test backwards, no overlap:  GFNs [%lx...%lx] -> [%lx...%lx]\n",
+           GFN_PAIR(GFN_2M, 32), GFN_PAIR(GFN_2M - 32, 32));
+
+    rc = xendevicemodel_relocate_memory(dh, domid, 32, GFN_2M, GFN_2M - 32);
+    if ( rc )
+        return fail("  Fail: relocate memory: %d - %s\n",
+                    errno, strerror(errno));
+
+    rc = check_guest_marks(GFN_2M - 32, 0, 32);
+    if ( rc )
+        return rc;
+
+    /*
+     * Move the next 32 pages above 2M backwards by 1 page.  The region is
+     * almost completely overlapping.
+     */
+    printf("  Test backwards, overlapping: GFNs [%lx...%lx] -> [%lx...%lx]\n",
+           GFN_PAIR(GFN_2M + 32, 32), GFN_PAIR(GFN_2M + 31, 32));
+
+    rc = xendevicemodel_relocate_memory(dh, domid, 32, GFN_2M + 32, GFN_2M + 
31);
+    if ( rc )
+        return fail("  Fail: relocate memory: %d - %s\n",
+                    errno, strerror(errno));
+
+    rc = check_guest_marks(GFN_2M + 31, 32, 32);
+    if ( rc )
+        return rc;
+
+    return 0;
+
+#undef GFN_PAIR
+#undef GFN_4M
+#undef GFN_2M
+}
+
 static int run_tests(void)
 {
     int rc;
@@ -154,6 +345,10 @@ static int run_tests(void)
     if ( rc )
         return rc;
 
+    rc = test_p2m_relocate_memory();
+    if ( rc )
+        return rc;
+
     return 0;
 }
 
@@ -167,6 +362,14 @@ int main(int argc, char **argv)
     if ( !xch )
         err(1, "xc_interface_open");
 
+    dh = xendevicemodel_open(NULL, 0);
+    if ( !dh )
+        err(1, "xendevicemodel_open");
+
+    fh = xenforeignmemory_open(NULL, 0);
+    if ( !fh )
+        err(1, "xenforeignmemory_open");
+
     rc = xc_domain_create(xch, &domid, &create);
     if ( rc )
     {
diff --git a/xen/common/memory.c b/xen/common/memory.c
index c90517e846..3672bda025 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -962,7 +962,7 @@ int xenmem_add_to_physmap(struct domain *d, struct 
xen_add_to_physmap *xatp,
     unsigned int done = 0;
     long rc = 0, adjust = 1;
     union add_to_physmap_extra extra = {};
-    struct page_info *pages[16];
+    struct page_info *pages[16]; /* If changing this, adjust 
test-paging-mempool too */
 
     if ( !paging_mode_translate(d) )
     {
--
generated by git-patchbot for /home/xen/git/xen.git#staging



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.