From: mpenttil@redhat.com
To: linux-mm@kvack.org
Cc: dri-devel@lists.freedesktop.org, intel-xe@lists.freedesktop.org,
linux-kernel@vger.kernel.org,
"Mika Penttilä" <mpenttil@redhat.com>,
"David Hildenbrand" <david@kernel.org>,
"Jason Gunthorpe" <jgg@nvidia.com>,
"Leon Romanovsky" <leonro@nvidia.com>,
"Alistair Popple" <apopple@nvidia.com>,
"Balbir Singh" <balbirs@nvidia.com>, "Zi Yan" <ziy@nvidia.com>,
"Matthew Brost" <matthew.brost@intel.com>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Lorenzo Stoakes" <ljs@kernel.org>,
"Liam R. Howlett" <Liam.Howlett@oracle.com>,
"Vlastimil Babka" <vbabka@suse.cz>,
"Mike Rapoport" <rppt@kernel.org>,
"Suren Baghdasaryan" <surenb@google.com>,
"Michal Hocko" <mhocko@suse.com>,
"Marco Pagani" <marpagan@redhat.com>
Subject: [PATCH v13 11/11] lib/test_hmm: add a new testcase for the migrate on fault
Date: Tue, 4 Aug 2026 07:26:31 +0300 [thread overview]
Message-ID: <20260804042631.2175585-12-mpenttil@redhat.com> (raw)
In-Reply-To: <20260804042631.2175585-1-mpenttil@redhat.com>
From: Mika Penttilä <mpenttil@redhat.com>
Enhance the hmm test driver (lib/test_hmm) with migrate on fault case.
Cc: David Hildenbrand <david@kernel.org>
Cc: Jason Gunthorpe <jgg@nvidia.com>
Cc: Leon Romanovsky <leonro@nvidia.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: Zi Yan <ziy@nvidia.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Marco Pagani <marpagan@redhat.com>
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
---
lib/test_hmm.c | 130 ++++++++++++++++++++++++-
lib/test_hmm_uapi.h | 19 ++--
tools/testing/selftests/mm/hmm-tests.c | 54 ++++++++++
3 files changed, 190 insertions(+), 13 deletions(-)
diff --git a/lib/test_hmm.c b/lib/test_hmm.c
index 79cb7487d211..46a83e0cb709 100644
--- a/lib/test_hmm.c
+++ b/lib/test_hmm.c
@@ -36,6 +36,7 @@
#define DMIRROR_RANGE_FAULT_TIMEOUT 1000
#define DEVMEM_CHUNK_SIZE (256 * 1024 * 1024U)
#define DEVMEM_CHUNKS_RESERVE 16
+#define PFNS_ARRAY_SIZE 64
/*
* For device_private pages, dpage is just a dummy struct page
@@ -355,6 +356,7 @@ static int dmirror_range_fault(struct dmirror *dmirror,
struct mm_struct *mm = dmirror->notifier.mm;
unsigned long timeout =
jiffies + msecs_to_jiffies(HMM_RANGE_DEFAULT_TIMEOUT);
+ bool migrate = range->default_flags & HMM_PFN_REQ_MIGRATE;
int ret;
while (true) {
@@ -364,9 +366,15 @@ static int dmirror_range_fault(struct dmirror *dmirror,
}
range->notifier_seq = mmu_interval_read_begin(range->notifier);
- mmap_read_lock(mm);
- ret = hmm_range_fault(range);
- mmap_read_unlock(mm);
+
+ /* mmap lock held for whole migrate on fault operation */
+ if (!migrate) {
+ mmap_read_lock(mm);
+ ret = hmm_range_fault(range);
+ mmap_read_unlock(mm);
+ } else {
+ ret = hmm_range_fault(range);
+ }
if (ret) {
if (ret == -EBUSY)
continue;
@@ -382,7 +390,9 @@ static int dmirror_range_fault(struct dmirror *dmirror,
break;
}
- ret = dmirror_do_fault(dmirror, range);
+ /* update device page table after migration */
+ if (!migrate)
+ ret = dmirror_do_fault(dmirror, range);
mutex_unlock(&dmirror->mutex);
out:
@@ -1281,6 +1291,114 @@ static int dmirror_migrate_to_device(struct dmirror *dmirror,
return ret;
}
+static int do_fault_and_migrate(struct dmirror *dmirror, struct hmm_range *range)
+{
+ struct migrate_vma *migrate = range->migrate;
+ int ret;
+
+ mmap_read_lock(dmirror->notifier.mm);
+
+ /* Fault-in pages for migration */
+ ret = dmirror_range_fault(dmirror, range);
+ /*
+ * Set this up even on error: hmm_range_fault() may have collected
+ * part of the range before failing.
+ */
+ migrate_hmm_range_setup(range);
+ if (ret) {
+ /*
+ * dst[] entries are empty, so this marks every collected migration
+ * as failed. finalize then restores the source mappings and drops
+ * the associated locks/references.
+ */
+ migrate_vma_pages(migrate);
+ migrate_vma_finalize(migrate);
+ goto out;
+ }
+
+ pr_debug("Migrating from sys mem to device mem\n");
+
+ dmirror_migrate_alloc_and_copy(migrate, dmirror);
+ migrate_vma_pages(migrate);
+ dmirror_migrate_finalize_and_map(migrate, dmirror);
+ migrate_vma_finalize(migrate);
+out:
+ mmap_read_unlock(dmirror->notifier.mm);
+ return ret;
+}
+
+static int dmirror_fault_and_migrate_to_device(struct dmirror *dmirror,
+ struct hmm_dmirror_cmd *cmd)
+{
+ unsigned long start, size, end, next;
+ unsigned long src_pfns[PFNS_ARRAY_SIZE] = { 0 };
+ unsigned long dst_pfns[PFNS_ARRAY_SIZE] = { 0 };
+ struct migrate_vma migrate = { 0 };
+ struct hmm_range range = { 0 };
+ struct dmirror_bounce bounce;
+ int ret = 0;
+
+ /* Whole range */
+ start = cmd->addr;
+ size = cmd->npages << PAGE_SHIFT;
+ end = start + size;
+
+ if (!mmget_not_zero(dmirror->notifier.mm)) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ migrate.pgmap_owner = dmirror->mdevice;
+ migrate.src = src_pfns;
+ migrate.dst = dst_pfns;
+ migrate.flags = MIGRATE_VMA_SELECT_SYSTEM;
+
+ range.migrate = &migrate;
+ range.hmm_pfns = src_pfns;
+ range.pfn_flags_mask = 0;
+ range.default_flags = HMM_PFN_REQ_FAULT | HMM_PFN_REQ_MIGRATE;
+ range.dev_private_owner = dmirror->mdevice;
+ range.notifier = &dmirror->notifier;
+
+ for (next = start; next < end; next = range.end) {
+ range.start = next;
+ range.end = min(end, next + (PFNS_ARRAY_SIZE << PAGE_SHIFT));
+
+ pr_debug("Fault and migrate range start:%#lx end:%#lx\n",
+ range.start, range.end);
+
+ ret = do_fault_and_migrate(dmirror, &range);
+ if (ret)
+ goto out_mmput;
+ }
+
+ /*
+ * Return the migrated data for verification.
+ * Only for pages in device zone
+ */
+ ret = dmirror_bounce_init(&bounce, start, size);
+ if (ret)
+ goto out_mmput;
+
+ mutex_lock(&dmirror->mutex);
+ ret = dmirror_do_read(dmirror, start, end, &bounce);
+ mutex_unlock(&dmirror->mutex);
+ if (ret == 0) {
+ ret = copy_to_user(u64_to_user_ptr(cmd->ptr), bounce.ptr, bounce.size);
+ if (ret)
+ ret = -EFAULT;
+ }
+
+ cmd->cpages = bounce.cpages;
+ dmirror_bounce_fini(&bounce);
+
+
+out_mmput:
+ mmput(dmirror->notifier.mm);
+out:
+ return ret;
+}
+
static void dmirror_mkentry(struct dmirror *dmirror, struct hmm_range *range,
unsigned char *perm, unsigned long entry)
{
@@ -1547,6 +1665,10 @@ static long dmirror_fops_unlocked_ioctl(struct file *filp,
ret = dmirror_migrate_to_device(dmirror, &cmd);
break;
+ case HMM_DMIRROR_MIGRATE_ON_FAULT_TO_DEV:
+ ret = dmirror_fault_and_migrate_to_device(dmirror, &cmd);
+ break;
+
case HMM_DMIRROR_MIGRATE_TO_SYS:
ret = dmirror_migrate_to_system(dmirror, &cmd);
break;
diff --git a/lib/test_hmm_uapi.h b/lib/test_hmm_uapi.h
index f94c6d457338..0b6e7a419e36 100644
--- a/lib/test_hmm_uapi.h
+++ b/lib/test_hmm_uapi.h
@@ -29,15 +29,16 @@ struct hmm_dmirror_cmd {
};
/* Expose the address space of the calling process through hmm device file */
-#define HMM_DMIRROR_READ _IOWR('H', 0x00, struct hmm_dmirror_cmd)
-#define HMM_DMIRROR_WRITE _IOWR('H', 0x01, struct hmm_dmirror_cmd)
-#define HMM_DMIRROR_MIGRATE_TO_DEV _IOWR('H', 0x02, struct hmm_dmirror_cmd)
-#define HMM_DMIRROR_MIGRATE_TO_SYS _IOWR('H', 0x03, struct hmm_dmirror_cmd)
-#define HMM_DMIRROR_SNAPSHOT _IOWR('H', 0x04, 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_READ _IOWR('H', 0x00, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_WRITE _IOWR('H', 0x01, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_MIGRATE_TO_DEV _IOWR('H', 0x02, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_MIGRATE_ON_FAULT_TO_DEV _IOWR('H', 0x03, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_MIGRATE_TO_SYS _IOWR('H', 0x04, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_SNAPSHOT _IOWR('H', 0x05, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_EXCLUSIVE _IOWR('H', 0x06, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_CHECK_EXCLUSIVE _IOWR('H', 0x07, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_RELEASE _IOWR('H', 0x08, struct hmm_dmirror_cmd)
+#define HMM_DMIRROR_FLAGS _IOWR('H', 0x09, struct hmm_dmirror_cmd)
#define HMM_DMIRROR_FLAG_FAIL_ALLOC (1ULL << 0)
diff --git a/tools/testing/selftests/mm/hmm-tests.c b/tools/testing/selftests/mm/hmm-tests.c
index 2f2b9879d100..4ac17cf6f866 100644
--- a/tools/testing/selftests/mm/hmm-tests.c
+++ b/tools/testing/selftests/mm/hmm-tests.c
@@ -283,6 +283,13 @@ static int hmm_migrate_sys_to_dev(int fd,
return hmm_dmirror_cmd(fd, HMM_DMIRROR_MIGRATE_TO_DEV, buffer, npages);
}
+static int hmm_migrate_on_fault_sys_to_dev(int fd,
+ struct hmm_buffer *buffer,
+ unsigned long npages)
+{
+ return hmm_dmirror_cmd(fd, HMM_DMIRROR_MIGRATE_ON_FAULT_TO_DEV, buffer, npages);
+}
+
static int hmm_migrate_dev_to_sys(int fd,
struct hmm_buffer *buffer,
unsigned long npages)
@@ -990,6 +997,53 @@ TEST_F(hmm, migrate)
hmm_buffer_free(buffer);
}
+
+/*
+ * Fault and migrate anonymous memory to device private memory.
+ */
+TEST_F(hmm, migrate_on_fault)
+{
+ struct hmm_buffer *buffer;
+ unsigned long npages;
+ unsigned long size;
+ unsigned long i;
+ int *ptr;
+ int ret;
+
+ npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
+ ASSERT_NE(npages, 0);
+ size = npages << self->page_shift;
+
+ buffer = malloc(sizeof(*buffer));
+ ASSERT_NE(buffer, NULL);
+
+ buffer->fd = -1;
+ buffer->size = size;
+ buffer->mirror = malloc(size);
+ ASSERT_NE(buffer->mirror, NULL);
+
+ buffer->ptr = mmap(NULL, size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ buffer->fd, 0);
+ ASSERT_NE(buffer->ptr, MAP_FAILED);
+
+ /* Initialize buffer in system memory. */
+ for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
+ ptr[i] = i;
+
+ /* Fault and migrate memory to device. */
+ ret = hmm_migrate_on_fault_sys_to_dev(self->fd, buffer, npages);
+ ASSERT_EQ(ret, 0);
+ ASSERT_EQ(buffer->cpages, npages);
+
+ /* Check what the device read. */
+ for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
+ ASSERT_EQ(ptr[i], i);
+
+ hmm_buffer_free(buffer);
+}
+
/*
* Migrate private file memory to device private memory.
*/
--
2.55.0
next prev parent reply other threads:[~2026-08-04 4:27 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-04 4:26 [PATCH v13 00/11] migrate on fault for device pages mpenttil
2026-08-04 4:26 ` [PATCH v13 01/11] mm/Kconfig: changes for " mpenttil
2026-08-04 4:26 ` [PATCH v13 02/11] mm: add helper to convert HMM pfn to migrate pfn mpenttil
2026-08-04 4:26 ` [PATCH v13 03/11] mm/hmm: preparations for HMM to participate in migration mpenttil
2026-08-04 4:26 ` [PATCH v13 04/11] mm/hmm: do the plumbing " mpenttil
2026-08-04 4:26 ` [PATCH v13 05/11] mm/hmm: implement folio split for migrate needs in HMM pagewalk mpenttil
2026-08-04 4:26 ` [PATCH v13 06/11] mm/hmm: migrate collection in HMM pagewalk - pte level mpenttil
2026-08-04 4:26 ` [PATCH v13 07/11] mm/hmm: migrate collection in HMM pagewalk - pmd level mpenttil
2026-08-04 4:26 ` [PATCH v13 08/11] mm/hmm: add lazy MMU mode support for migration in HMM pagewalk mpenttil
2026-08-04 4:26 ` [PATCH v13 09/11] mm/hmm: implement rollback for device page " mpenttil
2026-08-04 4:26 ` [PATCH v13 10/11] mm: enable device page migration from " mpenttil
2026-08-04 4:26 ` mpenttil [this message]
2026-08-04 4:35 ` ✗ CI.checkpatch: warning for Migrate on fault for device pages (rev5) Patchwork
2026-08-04 4:35 ` ✗ CI.KUnit: failure " Patchwork
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260804042631.2175585-12-mpenttil@redhat.com \
--to=mpenttil@redhat.com \
--cc=Liam.Howlett@oracle.com \
--cc=akpm@linux-foundation.org \
--cc=apopple@nvidia.com \
--cc=balbirs@nvidia.com \
--cc=david@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=intel-xe@lists.freedesktop.org \
--cc=jgg@nvidia.com \
--cc=leonro@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ljs@kernel.org \
--cc=marpagan@redhat.com \
--cc=matthew.brost@intel.com \
--cc=mhocko@suse.com \
--cc=rppt@kernel.org \
--cc=surenb@google.com \
--cc=vbabka@suse.cz \
--cc=ziy@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.