[RFC PATCH] test: mm/arm: pgtable: remove young bit check for pte_valid_user

Brian Ruley brian.ruley at gehealthcare.com
Fri Apr 10 04:43:36 PDT 2026


Instrumentation to print recently migrated pages in undefined
instruction handler. This was used to determine if the faulting address
was migrated earlier.

Signed-off-by: Brian Ruley <brian.ruley at gehealthcare.com>
---
Not intended for integration. This is just to share the testing details.
---
 arch/arm/kernel/traps.c |  5 ++++
 mm/migrate.c            | 53 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+)

diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index afbd2ebe5c39..64ef872f1555 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -28,6 +28,8 @@
 #include <linux/irq.h>
 #include <linux/vmalloc.h>
 
+void migrate_exec_log_dump(unsigned long fault_addr);
+
 #include <linux/atomic.h>
 #include <asm/cacheflush.h>
 #include <asm/exception.h>
@@ -490,6 +492,9 @@ asmlinkage void do_undefinstr(struct pt_regs *regs)
 		dump_instr(KERN_INFO, regs);
 	}
 #endif
+	if (user_mode(regs))
+		migrate_exec_log_dump((unsigned long)pc);
+
 	arm_notify_die("Oops - undefined instruction", regs,
 		       SIGILL, ILL_ILLOPC, pc, 0, 6);
 }
diff --git a/mm/migrate.c b/mm/migrate.c
index 2c3d489ecf51..987d0376b433 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -48,6 +48,54 @@
 
 #include <trace/events/migrate.h>
 
+
+/* Debug: track recent exec page migrations */
+#define MIGRATE_EXEC_LOG_SIZE 8
+struct migrate_exec_entry {
+	unsigned long addr;
+	unsigned long old_pfn;
+	unsigned long new_pfn;
+	unsigned int pid;
+	bool flushed;
+};
+static DEFINE_PER_CPU(struct migrate_exec_entry[MIGRATE_EXEC_LOG_SIZE], migrate_exec_log);
+static DEFINE_PER_CPU(unsigned int, migrate_exec_idx);
+
+void migrate_exec_log_add(unsigned long addr, unsigned long old_pfn,
+			  unsigned long new_pfn, bool flushed)
+{
+	unsigned int idx = __this_cpu_read(migrate_exec_idx);
+	struct migrate_exec_entry *log = this_cpu_ptr(migrate_exec_log);
+	struct migrate_exec_entry *e = &log[idx];
+
+	e->addr = addr;
+	e->old_pfn = old_pfn;
+	e->new_pfn = new_pfn;
+	e->pid = current->pid;
+	e->flushed = flushed;
+	__this_cpu_write(migrate_exec_idx, (idx + 1) % MIGRATE_EXEC_LOG_SIZE);
+}
+
+void migrate_exec_log_dump(unsigned long fault_addr)
+{
+	int cpu;
+
+	pr_err("SIGILL at %lx pid %d, recent exec migrations:\n",
+	       fault_addr, current->pid);
+	for_each_online_cpu(cpu) {
+		struct migrate_exec_entry *log = per_cpu(migrate_exec_log, cpu);
+		int i;
+		for (i = 0; i < MIGRATE_EXEC_LOG_SIZE; i++) {
+			if (log[i].addr == 0)
+				continue;
+			pr_err("  cpu%d: addr=%lx old_pfn=%lx new_pfn=%lx pid=%d flushed=%d%s\n",
+			       cpu, log[i].addr, log[i].old_pfn, log[i].new_pfn,
+			       log[i].pid, log[i].flushed,
+			       (PAGE_ALIGN(fault_addr) == PAGE_ALIGN(log[i].addr)) ?
+			       " *** MATCH ***" : "");
+		}
+	}
+}
 #include "internal.h"
 #include "swap.h"
 
@@ -434,6 +482,11 @@ static bool remove_migration_pte(struct folio *folio,
 			else
 				folio_add_file_rmap_pte(folio, new, vma);
 			set_pte_at(vma->vm_mm, pvmw.address, pvmw.pte, pte);
+
+			if (vma->vm_flags & VM_EXEC)
+				migrate_exec_log_add(pvmw.address,
+					swp_offset(entry), page_to_pfn(new),
+					pte_young(pte));
 		}
 		if (READ_ONCE(vma->vm_flags) & VM_LOCKED)
 			mlock_drain_local();
-- 
2.47.3




More information about the linux-arm-kernel mailing list