Add HMM_DMIRROR_FLAG_FAIL_ALLOC flag to simulate large page allocation
failures, enabling testing of split migration code paths.

This test flag allows validation of the fallback behavior when
destination device cannot allocate compound pages. This is useful
for testing the split migration functionality.

Cc: Andrew Morton <[email protected]>
Cc: David Hildenbrand <[email protected]>
Cc: Zi Yan <[email protected]>
Cc: Joshua Hahn <[email protected]>
Cc: Rakie Kim <[email protected]>
Cc: Byungchul Park <[email protected]>
Cc: Gregory Price <[email protected]>
Cc: Ying Huang <[email protected]>
Cc: Alistair Popple <[email protected]>
Cc: Oscar Salvador <[email protected]>
Cc: Lorenzo Stoakes <[email protected]>
Cc: Baolin Wang <[email protected]>
Cc: "Liam R. Howlett" <[email protected]>
Cc: Nico Pache <[email protected]>
Cc: Ryan Roberts <[email protected]>
Cc: Dev Jain <[email protected]>
Cc: Barry Song <[email protected]>
Cc: Lyude Paul <[email protected]>
Cc: Danilo Krummrich <[email protected]>
Cc: David Airlie <[email protected]>
Cc: Simona Vetter <[email protected]>
Cc: Ralph Campbell <[email protected]>
Cc: Mika Penttilä <[email protected]>
Cc: Matthew Brost <[email protected]>
Cc: Francois Dugast <[email protected]>

Signed-off-by: Balbir Singh <[email protected]>
---
 lib/test_hmm.c      | 61 ++++++++++++++++++++++++++++++---------------
 lib/test_hmm_uapi.h |  3 +++
 2 files changed, 44 insertions(+), 20 deletions(-)

diff --git a/lib/test_hmm.c b/lib/test_hmm.c
index 6455707df902..bb9324b9b04c 100644
--- a/lib/test_hmm.c
+++ b/lib/test_hmm.c
@@ -92,6 +92,7 @@ struct dmirror {
        struct xarray                   pt;
        struct mmu_interval_notifier    notifier;
        struct mutex                    mutex;
+       __u64                   flags;
 };
 
 /*
@@ -699,7 +700,12 @@ static void dmirror_migrate_alloc_and_copy(struct 
migrate_vma *args,
                     page_to_pfn(spage)))
                        goto next;
 
-               dpage = dmirror_devmem_alloc_page(dmirror, is_large);
+               if (dmirror->flags & HMM_DMIRROR_FLAG_FAIL_ALLOC) {
+                       dmirror->flags &= ~HMM_DMIRROR_FLAG_FAIL_ALLOC;
+                       dpage = NULL;
+               } else
+                       dpage = dmirror_devmem_alloc_page(dmirror, is_large);
+
                if (!dpage) {
                        struct folio *folio;
                        unsigned long i;
@@ -959,44 +965,55 @@ static vm_fault_t 
dmirror_devmem_fault_alloc_and_copy(struct migrate_vma *args,
 
                spage = BACKING_PAGE(spage);
                order = folio_order(page_folio(spage));
-
                if (order)
+                       *dst = MIGRATE_PFN_COMPOUND;
+               if (*src & MIGRATE_PFN_WRITE)
+                       *dst |= MIGRATE_PFN_WRITE;
+
+               if (dmirror->flags & HMM_DMIRROR_FLAG_FAIL_ALLOC) {
+                       dmirror->flags &= ~HMM_DMIRROR_FLAG_FAIL_ALLOC;
+                       *dst &= ~MIGRATE_PFN_COMPOUND;
+                       dpage = NULL;
+               } else if (order) {
                        dpage = folio_page(vma_alloc_folio(GFP_HIGHUSER_MOVABLE,
                                                order, args->vma, addr), 0);
-               else
-                       dpage = alloc_page_vma(GFP_HIGHUSER_MOVABLE, args->vma, 
addr);
-
-               /* Try with smaller pages if large allocation fails */
-               if (!dpage && order) {
+               } else {
                        dpage = alloc_page_vma(GFP_HIGHUSER_MOVABLE, args->vma, 
addr);
-                       if (!dpage)
-                               return VM_FAULT_OOM;
-                       order = 0;
                }
 
+               if (!dpage && !order)
+                       return VM_FAULT_OOM;
+
                pr_debug("migrating from sys to dev pfn src: 0x%lx pfn dst: 
0x%lx\n",
                                page_to_pfn(spage), page_to_pfn(dpage));
-               lock_page(dpage);
-               xa_erase(&dmirror->pt, addr >> PAGE_SHIFT);
-               copy_highpage(dpage, spage);
-               *dst = migrate_pfn(page_to_pfn(dpage));
-               if (*src & MIGRATE_PFN_WRITE)
-                       *dst |= MIGRATE_PFN_WRITE;
-               if (order)
-                       *dst |= MIGRATE_PFN_COMPOUND;
+
+               if (dpage) {
+                       lock_page(dpage);
+                       *dst |= migrate_pfn(page_to_pfn(dpage));
+               }
 
                for (i = 0; i < (1 << order); i++) {
                        struct page *src_page;
                        struct page *dst_page;
 
+                       /* Try with smaller pages if large allocation fails */
+                       if (!dpage && order) {
+                               dpage = alloc_page_vma(GFP_HIGHUSER_MOVABLE, 
args->vma, addr);
+                               lock_page(dpage);
+                               dst[i] = migrate_pfn(page_to_pfn(dpage));
+                               dst_page = pfn_to_page(page_to_pfn(dpage));
+                               dpage = NULL; /* For the next iteration */
+                       } else {
+                               dst_page = pfn_to_page(page_to_pfn(dpage) + i);
+                       }
+
                        src_page = pfn_to_page(page_to_pfn(spage) + i);
-                       dst_page = pfn_to_page(page_to_pfn(dpage) + i);
 
                        xa_erase(&dmirror->pt, addr >> PAGE_SHIFT);
+                       addr += PAGE_SIZE;
                        copy_highpage(dst_page, src_page);
                }
 next:
-               addr += PAGE_SIZE << order;
                src += 1 << order;
                dst += 1 << order;
        }
@@ -1514,6 +1531,10 @@ static long dmirror_fops_unlocked_ioctl(struct file 
*filp,
                dmirror_device_remove_chunks(dmirror->mdevice);
                ret = 0;
                break;
+       case HMM_DMIRROR_FLAGS:
+               dmirror->flags = cmd.npages;
+               ret = 0;
+               break;
 
        default:
                return -EINVAL;
diff --git a/lib/test_hmm_uapi.h b/lib/test_hmm_uapi.h
index 8c818a2cf4f6..f94c6d457338 100644
--- a/lib/test_hmm_uapi.h
+++ b/lib/test_hmm_uapi.h
@@ -37,6 +37,9 @@ struct hmm_dmirror_cmd {
 #define HMM_DMIRROR_EXCLUSIVE          _IOWR('H', 0x05, struct hmm_dmirror_cmd)
 #define HMM_DMIRROR_CHECK_EXCLUSIVE    _IOWR('H', 0x06, struct hmm_dmirror_cmd)
 #define HMM_DMIRROR_RELEASE            _IOWR('H', 0x07, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_FLAGS              _IOWR('H', 0x08, struct hmm_dmirror_cmd)
+
+#define HMM_DMIRROR_FLAG_FAIL_ALLOC    (1ULL << 0)
 
 /*
  * Values returned in hmm_dmirror_cmd.ptr for HMM_DMIRROR_SNAPSHOT.
-- 
2.50.1

Reply via email to