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>, "Lyude Paul" <lyude@redhat.com>,
"Danilo Krummrich" <dakr@kernel.org>
Subject: [PATCH v16 08/12] mm/hmm: implement rollback for device page migration in HMM pagewalk
Date: Wed, 21 Oct 2026 09:05:02 +0300 [thread overview]
Message-ID: <20261021060506.2377545-9-mpenttil@redhat.com> (raw)
In-Reply-To: <20261021060506.2377545-1-mpenttil@redhat.com>
From: Mika Penttilä <mpenttil@redhat.com>
During the migration pagewalk, the PTE table could be cleared and/or
changed into PMD leaf or even another PTE table while dropped locks.
In these cases the possibly inserted migration ptes are gone. We have
to however undo the collecting done so far, so unlock the folios and
drop reference taken.
During the pagewalk we notice such scenarios if going to recollect a pfn
but have already committed to migrate the entry with HMM_PFN_MIGRATE, in
which case do rollback. Rollback clears (HMM_PFN_VALID | HMM_PFN_MIGRATE)
which is safe, as migration is entirely driven by default_flags.
If we encounter migration ptes they are just skipped to allow for restart
own walks.
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>
Suggested-by: Alistair Popple <apopple@nvidia.com>
Signed-off-by: Mika Penttilä <mpenttil@redhat.com>
---
include/linux/hmm.h | 22 +++++++++++++
mm/hmm.c | 79 +++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 101 insertions(+)
diff --git a/include/linux/hmm.h b/include/linux/hmm.h
index 4f56f3419cb4..b08ebc1343dd 100644
--- a/include/linux/hmm.h
+++ b/include/linux/hmm.h
@@ -111,6 +111,28 @@ static inline unsigned int hmm_pfn_to_map_order(unsigned long hmm_pfn)
return (hmm_pfn >> HMM_PFN_ORDER_SHIFT) & 0x1F;
}
+/*
+ * hmm_pfn_collected() - is this pfn entry prepared for migration ?
+ * If collected the folio's refcount is increased and the folio
+ * is locked.
+ */
+static inline bool hmm_pfn_collected(unsigned long hmm_pfn)
+{
+ return (hmm_pfn & (HMM_PFN_VALID | HMM_PFN_MIGRATE)) ==
+ (HMM_PFN_VALID | HMM_PFN_MIGRATE);
+}
+
+/*
+ * hmm_pfn_rollback_collected() - undoes the collection of hmm_pfn
+ *
+ * Note for total rollback the folio's refcount has to be put
+ * and folio has to be unlocked.
+ */
+static inline unsigned long hmm_pfn_rollback_collected(unsigned long hmm_pfn)
+{
+ return hmm_pfn & ~(HMM_PFN_VALID | HMM_PFN_MIGRATE | HMM_PFN_COMPOUND);
+}
+
/*
* struct hmm_range - track invalidation lock on virtual address range
*
diff --git a/mm/hmm.c b/mm/hmm.c
index 36a4edde9823..5a1471fd5d28 100644
--- a/mm/hmm.c
+++ b/mm/hmm.c
@@ -95,6 +95,11 @@ enum {
HMM_PFN_P2PDMA_BUS,
};
+static void hmm_vma_handle_migrate_prepare_rollback(const struct hmm_vma_walk *hmm_vma_walk,
+ unsigned long start,
+ unsigned long end,
+ unsigned long *hmm_pfn);
+
static int hmm_pfns_fill(unsigned long addr, unsigned long end,
struct hmm_vma_walk *hmm_vma_walk, unsigned long cpu_flags)
{
@@ -111,6 +116,8 @@ static int hmm_pfns_fill(unsigned long addr, unsigned long end,
}
}
+ hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk, addr, end, &range->hmm_pfns[i]);
+
if (migrate && thp_migration_supported() &&
(minfo & MIGRATE_VMA_SELECT_COMPOUND) &&
IS_ALIGNED(addr, HPAGE_PMD_SIZE) &&
@@ -282,6 +289,8 @@ static int hmm_vma_handle_pmd(struct mm_walk *walk, unsigned long addr,
return hmm_record_fault(addr, end, required_fault, walk);
}
+ hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk, addr,
+ end, hmm_pfns);
pfn = pmd_pfn(pmd) + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
for (i = 0; addr < end; addr += PAGE_SIZE, i++, pfn++) {
hmm_pfns[i] &= HMM_PFN_INOUT_FLAGS;
@@ -412,6 +421,9 @@ static int hmm_vma_handle_pte(struct mm_walk *walk, unsigned long addr,
new_pfn_flags = pte_pfn(pte) | cpu_flags;
out:
+ hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk, addr,
+ addr + PAGE_SIZE,
+ hmm_pfn);
*hmm_pfn = (*hmm_pfn & HMM_PFN_INOUT_FLAGS) | new_pfn_flags;
return 0;
@@ -450,6 +462,9 @@ static int hmm_vma_handle_absent_pmd(struct mm_walk *walk, unsigned long start,
if (softleaf_is_device_private_write(entry))
cpu_flags |= HMM_PFN_WRITE;
+ hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk,
+ start, end,
+ hmm_pfns);
/*
* Fully populate the PFN list though subsequent PFNs could be
* inferred, because drivers which are not yet aware of large
@@ -568,6 +583,51 @@ static int migrate_vma_split_folio(struct folio *folio,
return __migrate_vma_split_folio(folio, fault_page);
}
+/*
+ * Due to dropping ptl locks for splitting for instance, would we
+ * overwrite already collected pfns? This could happen when pmd
+ * pointing to a page table has vanished and been replaced with
+ * a leaf pmd, or another page table. In that case unref and unlock
+ * the folios, the pfns of which were collected from the disappeared
+ * page tables.
+ *
+ * Migrate mode drives fault/migration requests only via range->default_flags.
+ * (HMM_PFN_VALID | HMM_PFN_MIGRATE) denotes a collected entry and can safely
+ * be cleared from hmm_pfn[].
+ */
+static void hmm_vma_handle_migrate_prepare_rollback(const struct hmm_vma_walk *hmm_vma_walk,
+ unsigned long start,
+ unsigned long end,
+ unsigned long *hmm_pfn)
+{
+ struct hmm_range *range = hmm_vma_walk->range;
+ struct migrate_vma *migrate = range->migrate;
+ struct folio *fault_folio = NULL;
+ enum migrate_vma_info minfo;
+ struct folio *folio;
+ unsigned long i;
+
+ minfo = hmm_select_migrate(range);
+ if (!minfo)
+ return;
+
+ WARN_ON_ONCE(!migrate);
+
+ fault_folio = migrate->fault_page ?
+ page_folio(migrate->fault_page) : NULL;
+
+ for (i = 0; start < end; start += PAGE_SIZE, i++) {
+ if (hmm_pfn_collected(hmm_pfn[i])) {
+ folio = page_folio(hmm_pfn_to_page(hmm_pfn[i]));
+ if (folio != fault_folio)
+ folio_unlock(folio);
+ folio_put(folio);
+ hmm_pfn[i] = hmm_pfn_rollback_collected(hmm_pfn[i]);
+
+ }
+ }
+}
+
static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
pmd_t *pmdp,
unsigned long start,
@@ -722,6 +782,11 @@ static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
pte = ptep_get(ptep);
if (pte_none(pte)) {
+ hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk,
+ addr,
+ addr + PAGE_SIZE,
+ hmm_pfn);
+
if (vma_is_anonymous(walk->vma)) {
*hmm_pfn &= HMM_PFN_INOUT_FLAGS;
*hmm_pfn |= HMM_PFN_MIGRATE;
@@ -769,6 +834,10 @@ static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
pfn = pte_pfn(pte);
if (is_zero_pfn(pfn) &&
(minfo & MIGRATE_VMA_SELECT_SYSTEM)) {
+ hmm_vma_handle_migrate_prepare_rollback(hmm_vma_walk,
+ addr,
+ addr + PAGE_SIZE,
+ hmm_pfn);
*hmm_pfn = HMM_PFN_MIGRATE;
goto out;
}
@@ -897,6 +966,13 @@ static int hmm_vma_handle_migrate_prepare(const struct mm_walk *walk,
}
#else
+static void hmm_vma_handle_migrate_prepare_rollback(const struct hmm_vma_walk *hmm_vma_walk,
+ unsigned long start,
+ unsigned long end,
+ unsigned long *hmm_pfn)
+{
+}
+
static int hmm_vma_handle_migrate_prepare_pmd(const struct mm_walk *walk,
pmd_t *pmdp,
unsigned long start,
@@ -1117,6 +1193,9 @@ static int hmm_vma_walk_pmd(pmd_t *pmdp,
if (ptep) {
lazy_mmu_mode_enable();
hmm_vma_walk->ptelocked = true;
+ } else {
+ /* The pte table is gone */
+ hmm_vma_handle_migrate_prepare_rollback(walk->private, addr, end, hmm_pfns);
}
} else {
ptep = pte_offset_map(pmdp, addr);
--
2.55.0
next prev parent reply other threads:[~2026-10-21 6:05 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-21 6:04 [PATCH v16 00/12] migrate on fault for device pages mpenttil
2026-10-21 6:04 ` [PATCH v16 01/12] mm/Kconfig: changes for " mpenttil
2026-10-21 6:04 ` [PATCH v16 02/12] mm: add helper to convert HMM pfn to migrate pfn mpenttil
2026-10-21 6:04 ` [PATCH v16 03/12] mm/hmm: preparations for HMM to participate in migration mpenttil
2026-10-21 7:17 ` Balbir Singh
2026-10-21 8:11 ` Mika Penttilä
2026-10-21 6:04 ` [PATCH v16 04/12] mm/hmm: do the plumbing " mpenttil
2026-10-21 6:04 ` [PATCH v16 05/12] mm/hmm: migrate collection in HMM pagewalk - pte level mpenttil
2026-10-21 6:56 ` Balbir Singh
2026-10-21 7:09 ` Mika Penttilä
2026-10-21 6:05 ` [PATCH v16 06/12] mm/hmm: migrate collection in HMM pagewalk - pmd level mpenttil
2026-10-21 6:05 ` [PATCH v16 07/12] mm/hmm: add lazy MMU mode support for migration in HMM pagewalk mpenttil
2026-10-21 6:05 ` mpenttil [this message]
2026-10-21 6:05 ` [PATCH v16 09/12] mm: enable device page migration from " mpenttil
2026-10-21 6:19 ` Balbir Singh
2026-10-21 6:30 ` Mika Penttilä
2026-10-21 6:05 ` [PATCH v16 10/12] lib/test_hmm: add a new testcase for the migrate on fault mpenttil
2026-10-21 6:05 ` [PATCH v16 11/12] Documentation/mm/hmm: document migration through hmm_range_fault() mpenttil
2026-10-21 6:05 ` [PATCH v16 12/12] drm/nouveau/svm: add support for migrate on fault mpenttil
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=20261021060506.2377545-9-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=dakr@kernel.org \
--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=lyude@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®