* [RFC v2 0/3] arm64: kprobes: Fix single-step fault and reentry handling
From: Pu Hu @ 2026-07-09 14:22 UTC (permalink / raw)
To: mhiramat@kernel.org
Cc: ada.coupriediaz@arm.com, catalin.marinas@arm.com,
davem@davemloft.net, Hongyan Xia, Pu Hu, Jiazi Li,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
naveen@kernel.org, will@kernel.org, yang@os.amperecomputing.com
From: Pu Hu <hupu@transsion.com>
This series fixes two arm64 kprobes issues observed when running
simpleperf with preemptirq tracepoints and dwarf callchains while a
kprobe is active on a frequently executed kernel function.
The crash happens in the kprobe debug exception path. While a kprobe is
preparing or executing its XOL single-step instruction, perf/trace code
can run in the same window. That code may either take a fault of its own
or hit another kprobe.
Patch 1 fixes kprobe_fault_handler() so that it only handles a fault
taken in KPROBE_HIT_SS or KPROBE_REENTER state when the faulting PC
points at the current kprobe's XOL instruction. Simulated kprobes,
which have no XOL slot at all, are filtered out at function entry so
that the normal page fault handler (including fixup_exception) can
process any fault without interference.
Patch 2 allows a kprobe hit in KPROBE_HIT_SS to be handled as a
recoverable one-level reentry, instead of treating it as unrecoverable.
This is safe because the reentry save area has not yet been consumed at
that point. Only a hit while already in KPROBE_REENTER remains
unrecoverable.
Patch 3 extends struct prev_kprobe with a saved_irqflag field so that
the outer kprobe's original DAIF state is preserved across reentry.
Without this, a nested kprobe from Patch 2 would overwrite
kcb->saved_irqflag, and the outer kprobe would restore the wrong DAIF
mask on completion, potentially leaving interrupts permanently disabled.
This follows the same logic as the existing x86 fixes:
6381c24cd6d5 ("kprobes/x86: Fix page-fault handling logic")
6a5022a56ac3 ("kprobes/x86: Allow to handle reentered kprobe on single-stepping")
v1 -> v2:
- Patch 1: moved simulated kprobe check to function entry (per
maintainer review); removed redundant xol_insn NULL check from
the inner branch.
- Patch 2: unchanged.
- Patch 3: new in v2; fixes the IRQ flag save/restore gap that
Patch 2 exposes.
- Removed the selftest patch (old Patch 3) from this series.
- Fixed Signed-off-by to use full name (Pu Hu) instead of username
(hupu).
- Updated comments and commit messages across all patches.
Reproducer:
simpleperf record -p <pid> -f 10000 \
-e preemptirq:preempt_disable \
-e preemptirq:preempt_enable \
--duration 9 --call-graph dwarf \
-o /data/local/tmp/perf.data
Before this series, the crash reproduced frequently. With all three
patches applied, it was no longer reproduced in our testing.
Pu Hu (3):
arm64: kprobes: Only handle faults originating from XOL slot
arm64: kprobes: Allow reentering kprobes while single-stepping
arm64: kprobes: Save and restore saved_irqflag in prev_kprobe
arch/arm64/include/asm/kprobes.h | 6 ++++
arch/arm64/kernel/probes/kprobes.c | 45 +++++++++++++++++++++++++++++-
2 files changed, 50 insertions(+), 1 deletion(-)
--
2.43.0
^ permalink raw reply
* [RFC v2 1/3] arm64: kprobes: Only handle faults originating from XOL slot
From: Pu Hu @ 2026-07-09 14:22 UTC (permalink / raw)
To: mhiramat@kernel.org
Cc: ada.coupriediaz@arm.com, catalin.marinas@arm.com,
davem@davemloft.net, Hongyan Xia, Pu Hu, Jiazi Li,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
naveen@kernel.org, will@kernel.org, yang@os.amperecomputing.com
In-Reply-To: <20260709142215.226872-1-hupu@transsion.com>
From: Pu Hu <hupu@transsion.com>
kprobe_fault_handler() currently treats any page fault taken while in
KPROBE_HIT_SS or KPROBE_REENTER state as a kprobe single-step fault. This
assumption does not hold: perf or tracing code may run from the debug
exception path during the single-step window and take its own page fault.
When the fault is handled as a kprobe fault, the PC is rewritten to the
probe address, corrupting the exception recovery context for the real
fault. A typical reproducer is running perf with preemptirq tracepoints
and dwarf callchains while a kprobe is installed on a frequently
executed function.
Fix this in two layers:
1. At function entry, bail out immediately for simulated kprobes
(ainsn.xol_insn == NULL), since they have no XOL slot and any fault
taken during their execution cannot be a single-step fault.
2. For kprobes with an XOL slot, only handle the fault when the
faulting PC matches the XOL instruction address. Faults from any
other PC are left to the normal page fault handler.
This follows the same principle as the x86 fix in commit 6381c24cd6d5
("kprobes/x86: Fix page-fault handling logic").
Signed-off-by: Pu Hu <hupu@transsion.com>
Signed-off-by: Hongyan Xia <hongyan.xia@transsion.com>
---
arch/arm64/kernel/probes/kprobes.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c
index 43a0361a8bf0..798e4b091d1a 100644
--- a/arch/arm64/kernel/probes/kprobes.c
+++ b/arch/arm64/kernel/probes/kprobes.c
@@ -282,9 +282,31 @@ int __kprobes kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr)
struct kprobe *cur = kprobe_running();
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
+ /*
+ * Simulated kprobes execute in the debug trap context and have no
+ * XOL slot. Any page fault taken while a simulated kprobe is in
+ * progress cannot have been caused by kprobe single-stepping and
+ * must be left alone for the normal page fault handler, including
+ * fixup_exception.
+ */
+ if (cur && !cur->ainsn.xol_insn)
+ return 0;
+
switch (kcb->kprobe_status) {
case KPROBE_HIT_SS:
case KPROBE_REENTER:
+ /*
+ * A page fault taken while in KPROBE_HIT_SS or
+ * KPROBE_REENTER state is only attributable to kprobe
+ * single-stepping if the faulting PC points to the
+ * current kprobe's XOL instruction. If the fault occurred
+ * elsewhere (e.g. in perf or tracing code invoked from the
+ * debug exception path), leave it for the normal page fault
+ * handler to process.
+ */
+ if (instruction_pointer(regs) != (unsigned long)cur->ainsn.xol_insn)
+ break;
+
/*
* We are here because the instruction being single
* stepped caused a page fault. We reset the current
--
2.43.0
^ permalink raw reply related
* [RFC v2 2/3] arm64: kprobes: Allow reentering kprobes while single-stepping
From: Pu Hu @ 2026-07-09 14:22 UTC (permalink / raw)
To: mhiramat@kernel.org
Cc: ada.coupriediaz@arm.com, catalin.marinas@arm.com,
davem@davemloft.net, Hongyan Xia, Pu Hu, Jiazi Li,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
naveen@kernel.org, will@kernel.org, yang@os.amperecomputing.com
In-Reply-To: <20260709142215.226872-1-hupu@transsion.com>
From: Pu Hu <hupu@transsion.com>
A kprobe can be hit while another kprobe is in KPROBE_HIT_SS state. This
can happen when tracing or perf code runs from the debug exception path
while the first kprobe is preparing or executing its out-of-line
single-step instruction.
Currently arm64 treats a kprobe hit in KPROBE_HIT_SS as unrecoverable,
the same as a hit in KPROBE_REENTER. This is too strict. A hit in
KPROBE_HIT_SS is still a one-level reentry and can be handled by saving
the current kprobe state and setting up single-step for the new probe,
just like reentry from KPROBE_HIT_ACTIVE or KPROBE_HIT_SSDONE.
The truly unrecoverable case is hitting another kprobe while already in
KPROBE_REENTER, because the reentry save area has already been consumed.
Move KPROBE_HIT_SS to the recoverable reentry cases and leave
KPROBE_REENTER as the unrecoverable nested reentry case.
This mirrors the x86 fix in commit 6a5022a56ac3
("kprobes/x86: Allow to handle reentered kprobe on single-stepping").
Signed-off-by: Pu Hu <hupu@transsion.com>
Signed-off-by: Hongyan Xia <hongyan.xia@transsion.com>
---
arch/arm64/kernel/probes/kprobes.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c
index 798e4b091d1a..2ca5916eca2f 100644
--- a/arch/arm64/kernel/probes/kprobes.c
+++ b/arch/arm64/kernel/probes/kprobes.c
@@ -240,10 +240,16 @@ static int __kprobes reenter_kprobe(struct kprobe *p,
switch (kcb->kprobe_status) {
case KPROBE_HIT_SSDONE:
case KPROBE_HIT_ACTIVE:
+ case KPROBE_HIT_SS:
+ /*
+ * A probe can be hit while another kprobe is preparing or
+ * executing its XOL single-step instruction. This is still a
+ * recoverable one-level reentry, so handle it in the same way as
+ * reentry from KPROBE_HIT_ACTIVE or KPROBE_HIT_SSDONE.
+ */
kprobes_inc_nmissed_count(p);
setup_singlestep(p, regs, kcb, 1);
break;
- case KPROBE_HIT_SS:
case KPROBE_REENTER:
pr_warn("Failed to recover from reentered kprobes.\n");
dump_kprobe(p);
--
2.43.0
^ permalink raw reply related
* [RFC v2 3/3] arm64: kprobes: Save and restore saved_irqflag in prev_kprobe
From: Pu Hu @ 2026-07-09 14:22 UTC (permalink / raw)
To: mhiramat@kernel.org
Cc: ada.coupriediaz@arm.com, catalin.marinas@arm.com,
davem@davemloft.net, Hongyan Xia, Pu Hu, Jiazi Li,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
naveen@kernel.org, will@kernel.org, yang@os.amperecomputing.com
In-Reply-To: <20260709142215.226872-1-hupu@transsion.com>
From: Pu Hu <hupu@transsion.com>
When a kprobe is reentered from KPROBE_HIT_SS state (allowed by the
previous patch), setup_singlestep() for the nested kprobe calls
kprobes_save_local_irqflag(), overwriting kcb->saved_irqflag with the
currently masked DAIF value. The outer kprobe's original DAIF state is
lost.
When the nested kprobe completes, restore_previous_kprobe() brings back
the outer kprobe's kp and status, but saved_irqflag still contains the
nested kprobe's value. When the outer kprobe's single-step eventually
finishes, kprobes_restore_local_irqflag() applies the wrong DAIF mask,
leaving interrupts permanently disabled.
Fix this by extending struct prev_kprobe with a saved_irqflag field, and
saving/restoring it alongside kp and status. This ensures the outer
kprobe's original interrupt state is preserved across reentry.
Signed-off-by: Pu Hu <hupu@transsion.com>
Signed-off-by: Hongyan Xia <hongyan.xia@transsion.com>
---
arch/arm64/include/asm/kprobes.h | 6 ++++++
arch/arm64/kernel/probes/kprobes.c | 15 +++++++++++++++
2 files changed, 21 insertions(+)
diff --git a/arch/arm64/include/asm/kprobes.h b/arch/arm64/include/asm/kprobes.h
index f2782560647b..35ce2c94040e 100644
--- a/arch/arm64/include/asm/kprobes.h
+++ b/arch/arm64/include/asm/kprobes.h
@@ -26,6 +26,12 @@
struct prev_kprobe {
struct kprobe *kp;
unsigned int status;
+
+ /*
+ * The original DAIF state of the outer kprobe, saved here before
+ * a nested kprobe overwrites kcb->saved_irqflag during reentry.
+ */
+ unsigned long saved_irqflag;
};
/* per-cpu kprobe control block */
diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c
index 2ca5916eca2f..4e0efad5caf2 100644
--- a/arch/arm64/kernel/probes/kprobes.c
+++ b/arch/arm64/kernel/probes/kprobes.c
@@ -174,12 +174,27 @@ static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
{
kcb->prev_kprobe.kp = kprobe_running();
kcb->prev_kprobe.status = kcb->kprobe_status;
+
+ /*
+ * Save the outer kprobe's original DAIF flags before the nested
+ * kprobe calls kprobes_save_local_irqflag() and overwrites
+ * kcb->saved_irqflag. Without this, the outer kprobe will restore
+ * the wrong DAIF state and leave interrupts permanently masked.
+ */
+ kcb->prev_kprobe.saved_irqflag = kcb->saved_irqflag;
}
static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
{
__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
kcb->kprobe_status = kcb->prev_kprobe.status;
+
+ /*
+ * Restore the outer kprobe's saved_irqflag so that when its
+ * single-step completes, kprobes_restore_local_irqflag() uses
+ * the correct original DAIF value.
+ */
+ kcb->saved_irqflag = kcb->prev_kprobe.saved_irqflag;
}
static void __kprobes set_current_kprobe(struct kprobe *p)
--
2.43.0
^ permalink raw reply related
* Re: [PATCH v2 1/4] mm/migrate: do not migrate folios mapped into VM_LOCKED VMAs under compaction
From: Lorenzo Stoakes @ 2026-07-09 15:00 UTC (permalink / raw)
To: Wandun
Cc: vbabka, david, rostedt, mhiramat, Alexander.Krabler, hughd, fvdl,
bigeasy, linux-mm, linux-kernel, linux-trace-kernel,
linux-rt-devel, akpm, surenb, mhocko, jackmanb, hannes, ziy, riel,
liam, harry, jannh, lance.yang, mathieu.desnoyers, matthew.brost,
joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
pfalcato
In-Reply-To: <f33a9dca-03d6-45f8-bd25-717b9033c75c@gmail.com>
On Thu, Jul 09, 2026 at 04:25:27PM +0800, Wandun wrote:
>
>
> On 7/7/26 21:55, Lorenzo Stoakes wrote:
> > On Tue, Jul 07, 2026 at 02:44:50PM +0100, Lorenzo Stoakes wrote:
> >> See above about deduplicating.
> >>
> >>> + ttu |= TTU_RESPECT_MLOCK;
> >>
> >> Hmm. I don't love 'respect mlock'. I guess we only know about the reason
> >> being compaction here.
> >>
> >> But I'm confused anyway. We have the folio, why aren't we just checking for
> >> PG_mlocked() here instead of getting the rmap to see if it's mapped
> >> anywhere with VMA_LOCKED_BIT?
> >
> > Also, since compaction_allow_unevictable() is a function that is accessible
> > elsewhere, you could literally just have a TTU_MIGRATION here instead and have
> > the rmap logic call compaction_allow_unevictable() instead rather than this.
> Do you mean:
> 1. change TTU_RESPECT_MLOCK to TTU_MIGRATION, that'is OK.
> 2. move call compaction_allow_unevictable() to try_to_migrate_one? but as you suggested
> migrate_mlock_allowed function, it already called compaction_allow_unevictable()
> in order to determine whether TTU_MIGRATION needs to be added. Did I misunderstand
> something somewhere?
The next paragraph addresses this.
>
> >
> > And then you could adapt the function I suggested before not to take a reason
> > parameter but rather a 'is_migration' one instead possibly and then pass (ttu &
> > TTU_MIGRATION) in.
> >
> > BUT. I still question whether this is at all needed since you have the folio you
> > can check for PG_mlocked...
>
> I described a race scenario at this link:
> https://lore.kernel.org/lkml/c372e68f-2bfc-45b6-a431-01bf55717247@gmail.com/
OK thanks. You really have to spell this out in the code in a comment, this is
really non-obvious.
I will try to look at your reply in due course (am between jobs atm).
>
>
> >
> > Cheers, Lorenzo
>
Thanks, Lorenzo
^ permalink raw reply
* Re: [PATCH 13/30] mm/vma: refactor vmg_adjust_set_range() for clarity
From: Gregory Price @ 2026-07-09 15:18 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Russell King, Dinh Nguyen, Simon Schuster,
James E . J . Bottomley, Helge Deller, Jarkko Sakkinen,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Ian Abbott, H Hartley Sweeten, Lucas Stach, David Airlie,
Simona Vetter, Patrik Jakobsson, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Clark, Dmitry Baryshkov, Tomi Valkeinen,
Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Christian Koenig, Huang Rui, Ankit Agrawal, Alex Williamson,
Alexander Viro, Christian Brauner, Dan Williams, Muchun Song,
Oscar Salvador, David Hildenbrand, Suren Baghdasaryan,
Liam R . Howlett, Matthew Wilcox, Marek Szyprowski,
Peter Zijlstra, Arnaldo Carvalho de Melo, Namhyung Kim,
Masami Hiramatsu, Oleg Nesterov, Steven Rostedt, SeongJae Park,
Miaohe Lin, Hugh Dickins, Mike Rapoport, Kees Cook, Paolo Bonzini,
linux-kernel, linux-arm-kernel, linux-parisc, linux-sgx, etnaviv,
dri-devel, linux-arm-msm, freedreno, linux-tegra, kvm,
linux-fsdevel, nvdimm, linux-mm, iommu, linux-perf-users,
linux-trace-kernel, kasan-dev, damon, Pedro Falcato, Rik van Riel,
Harry Yoo, Jann Horn
In-Reply-To: <ada7972f49ea7f1ff1df6d11e4651f270444f8fd.1782735110.git.ljs@kernel.org>
On Mon, Jun 29, 2026 at 01:23:24PM +0100, Lorenzo Stoakes wrote:
> Add comments with ASCII diagrams to describe what we're doing, avoid
> dubious use of PHYS_PFN(), and use vma_start_pgoff().
>
> The most complicated scenario represented here is vmg->__adjust_next_start
> - when this is set, vmg->[start, end] actually indicate the range to be
> retained, so take special care to describe this accurately.
>
> No functional change intended.
>
> Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
Reviewed-by: Gregory Price <gourry@gourry.net>
> + /*
> + * vmg->start vmg->end
> + * | |
> + * v merge v
> + * <------------->
> + * delta
> + * <------>
> + * |------|----------------|
> + * | prev | middle |
> + * |------|----------------|
> + * ^
> + * |
> + * middle->vm_start
> + */
Even with these diagrams, it's a bit difficult to understand what the
actual intent/result of this chunk is (but that may be a limitation of
me not spending enough time reading the surrounding code, not a comment
of your work here).
~Gregory
> + /*
> + * Originally:
> + *
> + * vmg->start vmg->end
> + * | |
> + * v merge v
> + * <------------>
> + * . .
> + * merge_existing_range() updates to:
> + * . .
> + * vmg->start vmg->end .
> + * | | .
> + * v retain v .
> + * <----------> .
> + * delta .
> + * <-----> .
> + * |----------------|------|
> + * | middle | next |
> + * |----------------|------|
> + * ^
> + * |
> + * next->vm_start
> + */
^ permalink raw reply
* Re: [PATCH 14/30] mm/vma: minor cleanup of expand_[upwards, downwards]()
From: Gregory Price @ 2026-07-09 15:20 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Russell King, Dinh Nguyen, Simon Schuster,
James E . J . Bottomley, Helge Deller, Jarkko Sakkinen,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Ian Abbott, H Hartley Sweeten, Lucas Stach, David Airlie,
Simona Vetter, Patrik Jakobsson, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Clark, Dmitry Baryshkov, Tomi Valkeinen,
Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Christian Koenig, Huang Rui, Ankit Agrawal, Alex Williamson,
Alexander Viro, Christian Brauner, Dan Williams, Muchun Song,
Oscar Salvador, David Hildenbrand, Suren Baghdasaryan,
Liam R . Howlett, Matthew Wilcox, Marek Szyprowski,
Peter Zijlstra, Arnaldo Carvalho de Melo, Namhyung Kim,
Masami Hiramatsu, Oleg Nesterov, Steven Rostedt, SeongJae Park,
Miaohe Lin, Hugh Dickins, Mike Rapoport, Kees Cook, Paolo Bonzini,
linux-kernel, linux-arm-kernel, linux-parisc, linux-sgx, etnaviv,
dri-devel, linux-arm-msm, freedreno, linux-tegra, kvm,
linux-fsdevel, nvdimm, linux-mm, iommu, linux-perf-users,
linux-trace-kernel, kasan-dev, damon, Pedro Falcato, Rik van Riel,
Harry Yoo, Jann Horn
In-Reply-To: <b24f70b72f0a9e2a37b904e5b59d80b88bd42e4a.1782735110.git.ljs@kernel.org>
On Mon, Jun 29, 2026 at 01:23:25PM +0100, Lorenzo Stoakes wrote:
> Adjust the stack expansion functions expand_upwards() and
> expand_downwards() such that they are expressed in terms of named constant
> values, and make use of vma_start_pgoff().
>
> This clearly documents that we are referencing the page offset of the start
> of the VMA.
>
> Additionally this cleans up the overflow check in expand_upwards().
>
> No functional change intended.
>
> Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
Reviewed-by: Gregory Price <gourry@gourry.net>
^ permalink raw reply
* Re: [PATCH 15/30] mm: introduce and use linear_page_delta()
From: Gregory Price @ 2026-07-09 15:22 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Russell King, Dinh Nguyen, Simon Schuster,
James E . J . Bottomley, Helge Deller, Jarkko Sakkinen,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Ian Abbott, H Hartley Sweeten, Lucas Stach, David Airlie,
Simona Vetter, Patrik Jakobsson, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Clark, Dmitry Baryshkov, Tomi Valkeinen,
Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Christian Koenig, Huang Rui, Ankit Agrawal, Alex Williamson,
Alexander Viro, Christian Brauner, Dan Williams, Muchun Song,
Oscar Salvador, David Hildenbrand, Suren Baghdasaryan,
Liam R . Howlett, Matthew Wilcox, Marek Szyprowski,
Peter Zijlstra, Arnaldo Carvalho de Melo, Namhyung Kim,
Masami Hiramatsu, Oleg Nesterov, Steven Rostedt, SeongJae Park,
Miaohe Lin, Hugh Dickins, Mike Rapoport, Kees Cook, Paolo Bonzini,
linux-kernel, linux-arm-kernel, linux-parisc, linux-sgx, etnaviv,
dri-devel, linux-arm-msm, freedreno, linux-tegra, kvm,
linux-fsdevel, nvdimm, linux-mm, iommu, linux-perf-users,
linux-trace-kernel, kasan-dev, damon, Pedro Falcato, Rik van Riel,
Harry Yoo, Jann Horn
In-Reply-To: <eedf589778aaab33e6df2ad6556dcde536e13460.1782735110.git.ljs@kernel.org>
On Mon, Jun 29, 2026 at 01:23:26PM +0100, Lorenzo Stoakes wrote:
> It's often useful to obtain the number of pages a given address lies at
> within a VMA.
>
> Add linear_page_delta() to determine this and update linear_page_index() to
> make use of it.
>
> Add comments to describe both linear_page_delta() and linear_page_index().
>
> No functional change intended.
>
> Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
Reviewed-by: Gregory Price <gourry@gourry.net>
^ permalink raw reply
* Re: [PATCH 16/30] mm/vma: use vma_start_pgoff(), linear_page_index() in mm code
From: Gregory Price @ 2026-07-09 15:29 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Russell King, Dinh Nguyen, Simon Schuster,
James E . J . Bottomley, Helge Deller, Jarkko Sakkinen,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Ian Abbott, H Hartley Sweeten, Lucas Stach, David Airlie,
Simona Vetter, Patrik Jakobsson, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Clark, Dmitry Baryshkov, Tomi Valkeinen,
Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Christian Koenig, Huang Rui, Ankit Agrawal, Alex Williamson,
Alexander Viro, Christian Brauner, Dan Williams, Muchun Song,
Oscar Salvador, David Hildenbrand, Suren Baghdasaryan,
Liam R . Howlett, Matthew Wilcox, Marek Szyprowski,
Peter Zijlstra, Arnaldo Carvalho de Melo, Namhyung Kim,
Masami Hiramatsu, Oleg Nesterov, Steven Rostedt, SeongJae Park,
Miaohe Lin, Hugh Dickins, Mike Rapoport, Kees Cook, Paolo Bonzini,
linux-kernel, linux-arm-kernel, linux-parisc, linux-sgx, etnaviv,
dri-devel, linux-arm-msm, freedreno, linux-tegra, kvm,
linux-fsdevel, nvdimm, linux-mm, iommu, linux-perf-users,
linux-trace-kernel, kasan-dev, damon, Pedro Falcato, Rik van Riel,
Harry Yoo, Jann Horn
In-Reply-To: <33d79008948391d30bab38db5ae31072ce12f0a1.1782735110.git.ljs@kernel.org>
On Mon, Jun 29, 2026 at 01:23:27PM +0100, Lorenzo Stoakes wrote:
> There are many instances in which linear_page_index() (as well as
> linear_page_delta()) is open-coded, which is confusing and inconsistent.
>
> Additionally, vma->vm_pgoff doesn't necessarily make it clear that this is
> the page offset of the start of the VMA range.
>
> Doing so also aids greppability.
>
> So use vma_start_pgoff() in favour of directly accessing vma->vm_pgoff, and
> linear_page_index() where we can.
>
> This also lays the ground for future changes which will add an anonymous
> page offset in order to be able to index MAP_PRIVATE-file backed anon
> folios in terms of their virtual page offset.
>
> No functional change intended.
>
> Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
such a nice readability improvement, thank you.
This made me wonder though whether we can make it painful for people to
open-code this in the future, otherwise I fear another one of these
patches creeping in 5-10 years down the line.
Not sure it's feasible though
Reviewed-by: Gregory Price <gourry@gourry.net>
> ---
> include/linux/huge_mm.h | 1 +
> include/linux/hugetlb.h | 3 +--
> include/linux/pagemap.h | 2 +-
> mm/damon/vaddr.c | 5 +++--
> mm/debug.c | 2 +-
> mm/filemap.c | 7 ++++---
> mm/huge_memory.c | 2 +-
> mm/hugetlb.c | 11 ++++-------
> mm/internal.h | 24 ++++++++++++++----------
> mm/khugepaged.c | 3 ++-
> mm/madvise.c | 6 +++---
> mm/mapping_dirty_helpers.c | 2 +-
> mm/memory.c | 25 +++++++++++++------------
> mm/mempolicy.c | 13 +++++++------
> mm/mremap.c | 12 ++++--------
> mm/msync.c | 4 ++--
> mm/nommu.c | 7 ++++---
> mm/pagewalk.c | 2 +-
> mm/shmem.c | 9 +++++----
> mm/userfaultfd.c | 4 ++--
> mm/util.c | 4 ++--
> mm/vma.c | 15 +++++++--------
> mm/vma_exec.c | 4 ++--
> mm/vma_init.c | 2 +-
> 24 files changed, 86 insertions(+), 83 deletions(-)
>
> diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
> index ad20f7f8c179..653b81d08fe7 100644
> --- a/include/linux/huge_mm.h
> +++ b/include/linux/huge_mm.h
> @@ -230,6 +230,7 @@ static inline bool thp_vma_suitable_order(struct vm_area_struct *vma,
>
> /* Don't have to check pgoff for anonymous vma */
> if (!vma_is_anonymous(vma)) {
> + /* vma_start_pgoff() in mm.h so not available. */
> if (!IS_ALIGNED((vma->vm_start >> PAGE_SHIFT) - vma->vm_pgoff,
> hpage_size >> PAGE_SHIFT))
> return false;
> diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
> index 2abaf99321e9..8390f50604d6 100644
> --- a/include/linux/hugetlb.h
> +++ b/include/linux/hugetlb.h
> @@ -792,8 +792,7 @@ static inline pgoff_t hugetlb_linear_page_index(struct vm_area_struct *vma,
> {
> struct hstate *h = hstate_vma(vma);
>
> - return ((address - vma->vm_start) >> huge_page_shift(h)) +
> - (vma->vm_pgoff >> huge_page_order(h));
> + return linear_page_index(vma, address) >> huge_page_order(h);
> }
>
> static inline bool order_is_gigantic(unsigned int order)
> diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
> index 644c0f25ae73..68a88d34a468 100644
> --- a/include/linux/pagemap.h
> +++ b/include/linux/pagemap.h
> @@ -1101,7 +1101,7 @@ static inline pgoff_t linear_page_index(const struct vm_area_struct *vma,
> pgoff_t pgoff;
>
> pgoff = linear_page_delta(vma, address);
> - pgoff += vma->vm_pgoff;
> + pgoff += vma_start_pgoff(vma);
> return pgoff;
> }
>
> diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
> index d27147603564..faa44aa3219b 100644
> --- a/mm/damon/vaddr.c
> +++ b/mm/damon/vaddr.c
> @@ -12,6 +12,7 @@
> #include <linux/mman.h>
> #include <linux/mmu_notifier.h>
> #include <linux/page_idle.h>
> +#include <linux/pagemap.h>
> #include <linux/pagewalk.h>
> #include <linux/sched/mm.h>
>
> @@ -627,8 +628,8 @@ static void damos_va_migrate_dests_add(struct folio *folio,
> }
>
> order = folio_order(folio);
> - ilx = vma->vm_pgoff >> order;
> - ilx += (addr - vma->vm_start) >> (PAGE_SHIFT + order);
> + ilx = vma_start_pgoff(vma) >> order;
> + ilx += linear_page_delta(vma, addr) >> order;
>
> for (i = 0; i < dests->nr_dests; i++)
> weight_total += dests->weight_arr[i];
> diff --git a/mm/debug.c b/mm/debug.c
> index 77fa8fe1d641..497654b36f1a 100644
> --- a/mm/debug.c
> +++ b/mm/debug.c
> @@ -163,7 +163,7 @@ void dump_vma(const struct vm_area_struct *vma)
> "flags: %#lx(%pGv)\n",
> vma, (void *)vma->vm_start, (void *)vma->vm_end, vma->vm_mm,
> (unsigned long)pgprot_val(vma->vm_page_prot),
> - vma->anon_vma, vma->vm_ops, vma->vm_pgoff,
> + vma->anon_vma, vma->vm_ops, vma_start_pgoff(vma),
> vma->vm_file, vma->vm_private_data,
> #ifdef CONFIG_PER_VMA_LOCK
> refcount_read(&vma->vm_refcnt),
> diff --git a/mm/filemap.c b/mm/filemap.c
> index 5af62e6abca5..bcb07b21a685 100644
> --- a/mm/filemap.c
> +++ b/mm/filemap.c
> @@ -3402,8 +3402,8 @@ static struct file *do_sync_mmap_readahead(struct vm_fault *vmf)
> * of memory.
> */
> struct vm_area_struct *vma = vmf->vma;
> - unsigned long start = vma->vm_pgoff;
> - unsigned long end = start + vma_pages(vma);
> + const unsigned long start = vma_start_pgoff(vma);
> + const unsigned long end = vma_end_pgoff(vma);
> unsigned long ra_end;
>
> ra->order = exec_folio_order();
> @@ -3921,7 +3921,8 @@ vm_fault_t filemap_map_pages(struct vm_fault *vmf,
> goto out;
> }
>
> - addr = vma->vm_start + ((start_pgoff - vma->vm_pgoff) << PAGE_SHIFT);
> + addr = vma->vm_start +
> + ((start_pgoff - vma_start_pgoff(vma)) << PAGE_SHIFT);
> vmf->pte = pte_offset_map_lock(vma->vm_mm, vmf->pmd, addr, &vmf->ptl);
> if (!vmf->pte) {
> folio_unlock(folio);
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 2bccb0a53a0a..e94f56487225 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -180,7 +180,7 @@ unsigned long __thp_vma_allowable_orders(struct vm_area_struct *vma,
> */
> if (!in_pf && shmem_file(vma->vm_file))
> return orders & shmem_allowable_huge_orders(file_inode(vma->vm_file),
> - vma, vma->vm_pgoff, 0,
> + vma, vma_start_pgoff(vma), 0,
> forced_collapse);
>
> if (!vma_is_anonymous(vma)) {
> diff --git a/mm/hugetlb.c b/mm/hugetlb.c
> index f45000149a78..d44a3ac5ee0a 100644
> --- a/mm/hugetlb.c
> +++ b/mm/hugetlb.c
> @@ -1011,8 +1011,7 @@ static long region_count(struct resv_map *resv, long f, long t)
> static pgoff_t vma_hugecache_offset(struct hstate *h,
> struct vm_area_struct *vma, unsigned long address)
> {
> - return ((address - vma->vm_start) >> huge_page_shift(h)) +
> - (vma->vm_pgoff >> huge_page_order(h));
> + return linear_page_index(vma, address) >> huge_page_order(h);
> }
>
> /*
> @@ -5372,8 +5371,7 @@ static void unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
> * from page cache lookup which is in HPAGE_SIZE units.
> */
> address = address & huge_page_mask(h);
> - pgoff = ((address - vma->vm_start) >> PAGE_SHIFT) +
> - vma->vm_pgoff;
> + pgoff = linear_page_index(vma, address);
> mapping = vma->vm_file->f_mapping;
>
> /*
> @@ -6771,7 +6769,7 @@ static unsigned long page_table_shareable(struct vm_area_struct *svma,
> struct vm_area_struct *vma,
> unsigned long addr, pgoff_t idx)
> {
> - unsigned long saddr = ((idx - svma->vm_pgoff) << PAGE_SHIFT) +
> + unsigned long saddr = ((idx - vma_start_pgoff(svma)) << PAGE_SHIFT) +
> svma->vm_start;
> unsigned long sbase = saddr & PUD_MASK;
> unsigned long s_end = sbase + PUD_SIZE;
> @@ -6856,8 +6854,7 @@ pte_t *huge_pmd_share(struct mm_struct *mm, struct vm_area_struct *vma,
> unsigned long addr, pud_t *pud)
> {
> struct address_space *mapping = vma->vm_file->f_mapping;
> - pgoff_t idx = ((addr - vma->vm_start) >> PAGE_SHIFT) +
> - vma->vm_pgoff;
> + const pgoff_t idx = linear_page_index(vma, addr);
> struct vm_area_struct *svma;
> unsigned long saddr;
> pte_t *spte = NULL;
> diff --git a/mm/internal.h b/mm/internal.h
> index 181e79f1d6a2..89e5b7efe256 100644
> --- a/mm/internal.h
> +++ b/mm/internal.h
> @@ -1143,26 +1143,28 @@ static inline bool
> folio_within_range(struct folio *folio, struct vm_area_struct *vma,
> unsigned long start, unsigned long end)
> {
> - pgoff_t pgoff, addr;
> - unsigned long vma_pglen = vma_pages(vma);
> + const unsigned long vma_pglen = vma_pages(vma);
> + pgoff_t pgoff_folio, pgoff_vma_start;
> + unsigned long addr;
>
> VM_WARN_ON_FOLIO(folio_test_ksm(folio), folio);
> if (start > end)
> return false;
>
> + pgoff_folio = folio_pgoff(folio);
> + pgoff_vma_start = vma_start_pgoff(vma);
> +
> if (start < vma->vm_start)
> start = vma->vm_start;
>
> if (end > vma->vm_end)
> end = vma->vm_end;
>
> - pgoff = folio_pgoff(folio);
> -
> /* if folio start address is not in vma range */
> - if (!in_range(pgoff, vma->vm_pgoff, vma_pglen))
> + if (!in_range(pgoff_folio, pgoff_vma_start, vma_pglen))
> return false;
>
> - addr = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
> + addr = vma->vm_start + ((pgoff_folio - pgoff_vma_start) << PAGE_SHIFT);
>
> return !(addr < start || end - addr < folio_size(folio));
> }
> @@ -1234,15 +1236,16 @@ extern pmd_t maybe_pmd_mkwrite(pmd_t pmd, struct vm_area_struct *vma);
> static inline unsigned long vma_address(const struct vm_area_struct *vma,
> pgoff_t pgoff, unsigned long nr_pages)
> {
> + const pgoff_t pgoff_start = vma_start_pgoff(vma);
> unsigned long address;
>
> - if (pgoff >= vma->vm_pgoff) {
> + if (pgoff >= pgoff_start) {
> address = vma->vm_start +
> - ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
> + ((pgoff - pgoff_start) << PAGE_SHIFT);
> /* Check for address beyond vma (or wrapped through 0?) */
> if (address < vma->vm_start || address >= vma->vm_end)
> address = -EFAULT;
> - } else if (pgoff + nr_pages - 1 >= vma->vm_pgoff) {
> + } else if (pgoff + nr_pages - 1 >= pgoff_start) {
> /* Test above avoids possibility of wrap to 0 on 32-bit */
> address = vma->vm_start;
> } else {
> @@ -1266,7 +1269,8 @@ static inline unsigned long vma_address_end(struct page_vma_mapped_walk *pvmw)
> return pvmw->address + PAGE_SIZE;
>
> pgoff = pvmw->pgoff + pvmw->nr_pages;
> - address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
> + address = vma->vm_start +
> + ((pgoff - vma_start_pgoff(vma)) << PAGE_SHIFT);
> /* Check for address beyond vma (or wrapped through 0?) */
> if (address < vma->vm_start || address > vma->vm_end)
> address = vma->vm_end;
> diff --git a/mm/khugepaged.c b/mm/khugepaged.c
> index bd5f86cf4bd8..ffef738d826c 100644
> --- a/mm/khugepaged.c
> +++ b/mm/khugepaged.c
> @@ -2145,7 +2145,8 @@ static void retract_page_tables(struct address_space *mapping, pgoff_t pgoff)
> spinlock_t *ptl;
> bool success = false;
>
> - addr = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
> + addr = vma->vm_start +
> + ((pgoff - vma_start_pgoff(vma)) << PAGE_SHIFT);
> if (addr & ~HPAGE_PMD_MASK ||
> vma->vm_end < addr + HPAGE_PMD_SIZE)
> continue;
> diff --git a/mm/madvise.c b/mm/madvise.c
> index cd9bb077072c..6730c4200a93 100644
> --- a/mm/madvise.c
> +++ b/mm/madvise.c
> @@ -253,7 +253,7 @@ static void shmem_swapin_range(struct vm_area_struct *vma,
> continue;
>
> addr = vma->vm_start +
> - ((xas.xa_index - vma->vm_pgoff) << PAGE_SHIFT);
> + ((xas.xa_index - vma_start_pgoff(vma)) << PAGE_SHIFT);
> xas_pause(&xas);
> rcu_read_unlock();
>
> @@ -318,7 +318,7 @@ static long madvise_willneed(struct madvise_behavior *madv_behavior)
> mark_mmap_lock_dropped(madv_behavior);
> get_file(file);
> offset = (loff_t)(start - vma->vm_start)
> - + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
> + + ((loff_t)vma_start_pgoff(vma) << PAGE_SHIFT);
> mmap_read_unlock(mm);
> vfs_fadvise(file, offset, end - start, POSIX_FADV_WILLNEED);
> fput(file);
> @@ -1023,7 +1023,7 @@ static long madvise_remove(struct madvise_behavior *madv_behavior)
> return -EACCES;
>
> offset = (loff_t)(start - vma->vm_start)
> - + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
> + + ((loff_t)vma_start_pgoff(vma) << PAGE_SHIFT);
>
> /*
> * Filesystem's fallocate may need to take i_rwsem. We need to
> diff --git a/mm/mapping_dirty_helpers.c b/mm/mapping_dirty_helpers.c
> index 737c407f4081..e0efa36e0a07 100644
> --- a/mm/mapping_dirty_helpers.c
> +++ b/mm/mapping_dirty_helpers.c
> @@ -95,7 +95,7 @@ static int clean_record_pte(pte_t *pte, unsigned long addr,
>
> if (pte_dirty(ptent)) {
> pgoff_t pgoff = ((addr - walk->vma->vm_start) >> PAGE_SHIFT) +
> - walk->vma->vm_pgoff - cwalk->bitmap_pgoff;
> + vma_start_pgoff(walk->vma) - cwalk->bitmap_pgoff;
> pte_t old_pte = ptep_modify_prot_start(walk->vma, addr, pte);
>
> ptent = pte_mkclean(old_pte);
> diff --git a/mm/memory.c b/mm/memory.c
> index 98c1a245f45a..f5eb06544ba4 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -725,10 +725,10 @@ static inline struct page *__vm_normal_page(struct vm_area_struct *vma,
> if (!pfn_valid(pfn))
> return NULL;
> } else {
> - unsigned long off = (addr - vma->vm_start) >> PAGE_SHIFT;
> + const pgoff_t index = linear_page_index(vma, addr);
>
> /* Only CoW'ed anon folios are "normal". */
> - if (pfn == vma->vm_pgoff + off)
> + if (pfn == index)
> return NULL;
> if (!is_cow_mapping(vma->vm_flags))
> return NULL;
> @@ -2643,7 +2643,7 @@ static int __vm_map_pages(struct vm_area_struct *vma, struct page **pages,
> int vm_map_pages(struct vm_area_struct *vma, struct page **pages,
> unsigned long num)
> {
> - return __vm_map_pages(vma, pages, num, vma->vm_pgoff);
> + return __vm_map_pages(vma, pages, num, vma_start_pgoff(vma));
> }
> EXPORT_SYMBOL(vm_map_pages);
>
> @@ -3298,7 +3298,8 @@ int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long
> unsigned long pfn;
> int err;
>
> - err = __simple_ioremap_prep(vm_len, vma->vm_pgoff, start, len, &pfn);
> + err = __simple_ioremap_prep(vm_len, vma_start_pgoff(vma), start, len,
> + &pfn);
> if (err)
> return err;
>
> @@ -4342,15 +4343,15 @@ static inline void unmap_mapping_range_tree(struct address_space *mapping,
> struct zap_details *details)
> {
> struct vm_area_struct *vma;
> - unsigned long start, size;
> struct mmu_gather tlb;
>
> mapping_interval_tree_foreach(vma, mapping, first_index, last_index) {
> - const pgoff_t start_idx = max(first_index, vma->vm_pgoff);
> + const pgoff_t start_idx = max(first_index, vma_start_pgoff(vma));
> const pgoff_t end_idx = min(last_index, vma_last_pgoff(vma)) + 1;
> -
> - start = vma->vm_start + ((start_idx - vma->vm_pgoff) << PAGE_SHIFT);
> - size = (end_idx - start_idx) << PAGE_SHIFT;
> + const pgoff_t offset = start_idx - vma_start_pgoff(vma);
> + const unsigned long offset_bytes = offset << PAGE_SHIFT;
> + const unsigned long start = vma->vm_start + offset_bytes;
> + const unsigned long size = (end_idx - start_idx) << PAGE_SHIFT;
>
> tlb_gather_mmu(&tlb, vma->vm_mm);
> zap_vma_range_batched(&tlb, vma, start, size, details);
> @@ -5684,7 +5685,7 @@ vm_fault_t finish_fault(struct vm_fault *vmf)
> } else if (nr_pages > 1) {
> pgoff_t idx = folio_page_idx(folio, page);
> /* The page offset of vmf->address within the VMA. */
> - pgoff_t vma_off = vmf->pgoff - vmf->vma->vm_pgoff;
> + pgoff_t vma_off = vmf->pgoff - vma_start_pgoff(vmf->vma);
> /* The index of the entry in the pagetable for fault page. */
> pgoff_t pte_off = pte_index(vmf->address);
>
> @@ -5796,7 +5797,7 @@ static vm_fault_t do_fault_around(struct vm_fault *vmf)
> pgoff_t nr_pages = READ_ONCE(fault_around_pages);
> pgoff_t pte_off = pte_index(vmf->address);
> /* The page offset of vmf->address within the VMA. */
> - pgoff_t vma_off = vmf->pgoff - vmf->vma->vm_pgoff;
> + pgoff_t vma_off = vmf->pgoff - vma_start_pgoff(vmf->vma);
> pgoff_t from_pte, to_pte;
> vm_fault_t ret;
>
> @@ -7274,7 +7275,7 @@ void print_vma_addr(char *prefix, unsigned long ip)
> if (vma && vma->vm_file) {
> struct file *f = vma->vm_file;
> ip -= vma->vm_start;
> - ip += vma->vm_pgoff << PAGE_SHIFT;
> + ip += vma_start_pgoff(vma) << PAGE_SHIFT;
> printk("%s%pD[%lx,%lx+%lx]", prefix, f, ip,
> vma->vm_start,
> vma->vm_end - vma->vm_start);
> diff --git a/mm/mempolicy.c b/mm/mempolicy.c
> index 36699fabd3c2..650cdb23354a 100644
> --- a/mm/mempolicy.c
> +++ b/mm/mempolicy.c
> @@ -2048,8 +2048,8 @@ struct mempolicy *get_vma_policy(struct vm_area_struct *vma,
> pol = get_task_policy(current);
> if (pol->mode == MPOL_INTERLEAVE ||
> pol->mode == MPOL_WEIGHTED_INTERLEAVE) {
> - *ilx += vma->vm_pgoff >> order;
> - *ilx += (addr - vma->vm_start) >> (PAGE_SHIFT + order);
> + *ilx += vma_start_pgoff(vma) >> order;
> + *ilx += linear_page_delta(vma, addr) >> order;
> }
> return pol;
> }
> @@ -3250,16 +3250,17 @@ EXPORT_SYMBOL_FOR_MODULES(mpol_shared_policy_init, "kvm");
> int mpol_set_shared_policy(struct shared_policy *sp,
> struct vm_area_struct *vma, struct mempolicy *pol)
> {
> - int err;
> + const pgoff_t pgoff = vma_start_pgoff(vma);
> + const pgoff_t pgoff_end = vma_end_pgoff(vma);
> struct sp_node *new = NULL;
> - unsigned long sz = vma_pages(vma);
> + int err;
>
> if (pol) {
> - new = sp_alloc(vma->vm_pgoff, vma->vm_pgoff + sz, pol);
> + new = sp_alloc(pgoff, pgoff_end, pol);
> if (!new)
> return -ENOMEM;
> }
> - err = shared_policy_replace(sp, vma->vm_pgoff, vma->vm_pgoff + sz, new);
> + err = shared_policy_replace(sp, pgoff, pgoff_end, new);
> if (err && new)
> sp_free(new);
> return err;
> diff --git a/mm/mremap.c b/mm/mremap.c
> index e9c8b1d05832..079a0ba0c4a7 100644
> --- a/mm/mremap.c
> +++ b/mm/mremap.c
> @@ -948,8 +948,7 @@ static unsigned long vrm_set_new_addr(struct vma_remap_struct *vrm)
> struct vm_area_struct *vma = vrm->vma;
> unsigned long map_flags = 0;
> /* Page Offset _into_ the VMA. */
> - pgoff_t internal_pgoff = (vrm->addr - vma->vm_start) >> PAGE_SHIFT;
> - pgoff_t pgoff = vma->vm_pgoff + internal_pgoff;
> + const pgoff_t pgoff = linear_page_index(vma, vrm->addr);
> unsigned long new_addr = vrm_implies_new_addr(vrm) ? vrm->new_addr : 0;
> unsigned long res;
>
> @@ -1255,12 +1254,10 @@ static void unmap_source_vma(struct vma_remap_struct *vrm)
> static int copy_vma_and_data(struct vma_remap_struct *vrm,
> struct vm_area_struct **new_vma_ptr)
> {
> - unsigned long internal_offset = vrm->addr - vrm->vma->vm_start;
> - unsigned long internal_pgoff = internal_offset >> PAGE_SHIFT;
> - unsigned long new_pgoff = vrm->vma->vm_pgoff + internal_pgoff;
> - unsigned long moved_len;
> + const unsigned long new_pgoff = linear_page_index(vrm->vma, vrm->addr);
> struct vm_area_struct *vma = vrm->vma;
> struct vm_area_struct *new_vma;
> + unsigned long moved_len;
> int err = 0;
> PAGETABLE_MOVE(pmc, NULL, NULL, vrm->addr, vrm->new_addr, vrm->old_len);
>
> @@ -1802,8 +1799,7 @@ static int check_prep_vma(struct vma_remap_struct *vrm)
> vrm->populate_expand = true;
>
> /* Need to be careful about a growing mapping */
> - pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
> - pgoff += vma->vm_pgoff;
> + pgoff = linear_page_index(vma, addr);
> if (pgoff + (new_len >> PAGE_SHIFT) < pgoff)
> return -EINVAL;
>
> diff --git a/mm/msync.c b/mm/msync.c
> index ac4c9bfea2e7..90b491a27a14 100644
> --- a/mm/msync.c
> +++ b/mm/msync.c
> @@ -12,6 +12,7 @@
> #include <linux/mm.h>
> #include <linux/mman.h>
> #include <linux/file.h>
> +#include <linux/pagemap.h>
> #include <linux/syscalls.h>
> #include <linux/sched.h>
>
> @@ -85,8 +86,7 @@ SYSCALL_DEFINE3(msync, unsigned long, start, size_t, len, int, flags)
> goto out_unlock;
> }
> file = vma->vm_file;
> - fstart = (start - vma->vm_start) +
> - ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
> + fstart = (loff_t)linear_page_index(vma, start) << PAGE_SHIFT;
> fend = fstart + (min(end, vma->vm_end) - start) - 1;
> start = vma->vm_end;
> if ((flags & MS_SYNC) && file &&
> diff --git a/mm/nommu.c b/mm/nommu.c
> index 6d168f69763f..60560b2c457e 100644
> --- a/mm/nommu.c
> +++ b/mm/nommu.c
> @@ -975,7 +975,7 @@ static int do_mmap_private(struct vm_area_struct *vma,
> /* read the contents of a file into the copy */
> loff_t fpos;
>
> - fpos = vma->vm_pgoff;
> + fpos = vma_start_pgoff(vma);
> fpos <<= PAGE_SHIFT;
>
> ret = kernel_read(vma->vm_file, base, len, &fpos);
> @@ -1355,7 +1355,8 @@ static int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
> delete_nommu_region(vma->vm_region);
> if (new_below) {
> vma->vm_region->vm_start = vma->vm_start = addr;
> - vma->vm_region->vm_pgoff = vma->vm_pgoff += npages;
> + vma->vm_pgoff += npages;
> + vma->vm_region->vm_pgoff = vma_start_pgoff(vma);
> } else {
> vma->vm_region->vm_end = vma->vm_end = addr;
> vma->vm_region->vm_top = addr;
> @@ -1603,7 +1604,7 @@ int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long
> unsigned long pfn = start >> PAGE_SHIFT;
> unsigned long vm_len = vma->vm_end - vma->vm_start;
>
> - pfn += vma->vm_pgoff;
> + pfn += vma_start_pgoff(vma);
> return io_remap_pfn_range(vma, vma->vm_start, pfn, vm_len, vma->vm_page_prot);
> }
> EXPORT_SYMBOL(vm_iomap_memory);
> diff --git a/mm/pagewalk.c b/mm/pagewalk.c
> index 98d090ede077..0a3bbff57d46 100644
> --- a/mm/pagewalk.c
> +++ b/mm/pagewalk.c
> @@ -813,7 +813,7 @@ int walk_page_mapping(struct address_space *mapping, pgoff_t first_index,
> mapping_interval_tree_foreach(vma, mapping, first_index,
> first_index + nr - 1) {
> /* Clip to the vma */
> - vba = vma->vm_pgoff;
> + vba = vma_start_pgoff(vma);
> vea = vba + vma_pages(vma);
> cba = first_index;
> cba = max(cba, vba);
> diff --git a/mm/shmem.c b/mm/shmem.c
> index b51f83c970bb..4e7f6bc7a389 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -1032,6 +1032,8 @@ unsigned long shmem_swap_usage(struct vm_area_struct *vma)
> struct inode *inode = file_inode(vma->vm_file);
> struct shmem_inode_info *info = SHMEM_I(inode);
> struct address_space *mapping = inode->i_mapping;
> + const pgoff_t pgoff = vma_start_pgoff(vma);
> + const pgoff_t pgoff_end = vma_end_pgoff(vma);
> unsigned long swapped;
>
> /* Be careful as we don't hold info->lock */
> @@ -1045,12 +1047,11 @@ unsigned long shmem_swap_usage(struct vm_area_struct *vma)
> if (!swapped)
> return 0;
>
> - if (!vma->vm_pgoff && vma->vm_end - vma->vm_start >= inode->i_size)
> + if (!pgoff && vma->vm_end - vma->vm_start >= inode->i_size)
> return swapped << PAGE_SHIFT;
>
> /* Here comes the more involved part */
> - return shmem_partial_swap_usage(mapping, vma->vm_pgoff,
> - vma->vm_pgoff + vma_pages(vma));
> + return shmem_partial_swap_usage(mapping, pgoff, pgoff_end);
> }
>
> /*
> @@ -2839,7 +2840,7 @@ static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma,
> * by page order, as in shmem_get_pgoff_policy() and get_vma_policy()).
> */
> *ilx = inode->i_ino;
> - index = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
> + index = linear_page_index(vma, addr);
> return mpol_shared_policy_lookup(&SHMEM_I(inode)->policy, index);
> }
>
> diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c
> index 246af12bf801..bf4518f4449d 100644
> --- a/mm/userfaultfd.c
> +++ b/mm/userfaultfd.c
> @@ -481,7 +481,7 @@ static void mfill_retry_state_save(struct mfill_retry_state *s,
> {
> s->flags = vma_flags_and_mask(&vma->flags, MFILL_RETRY_STATE_VMA_FLAGS);
> s->ops = vma_uffd_ops(vma);
> - s->pgoff = vma->vm_pgoff;
> + s->pgoff = vma_start_pgoff(vma);
>
> if (vma->vm_file)
> s->file = get_file(vma->vm_file);
> @@ -507,7 +507,7 @@ static bool mfill_retry_state_changed(struct mfill_retry_state *state,
>
> /* VMA was file backed, but file, inode or offset has changed */
> if (!vma->vm_file || vma->vm_file->f_inode != state->file->f_inode ||
> - state->file != vma->vm_file || vma->vm_pgoff != state->pgoff)
> + state->file != vma->vm_file || vma_start_pgoff(vma) != state->pgoff)
> return true;
>
> return false;
> diff --git a/mm/util.c b/mm/util.c
> index af2c2103f0d9..61e6d32b2c16 100644
> --- a/mm/util.c
> +++ b/mm/util.c
> @@ -1188,7 +1188,7 @@ void compat_set_desc_from_vma(struct vm_area_desc *desc,
> desc->start = vma->vm_start;
> desc->end = vma->vm_end;
>
> - desc->pgoff = vma->vm_pgoff;
> + desc->pgoff = vma_start_pgoff(vma);
> desc->vm_file = vma->vm_file;
> desc->vma_flags = vma->flags;
> desc->page_prot = vma->vm_page_prot;
> @@ -1379,7 +1379,7 @@ static int call_vma_mapped(struct vm_area_struct *vma)
> if (!vm_ops || !vm_ops->mapped)
> return 0;
>
> - err = vm_ops->mapped(vma->vm_start, vma->vm_end, vma->vm_pgoff,
> + err = vm_ops->mapped(vma->vm_start, vma->vm_end, vma_start_pgoff(vma),
> vma->vm_file, &vm_private_data);
> if (err)
> return err;
> diff --git a/mm/vma.c b/mm/vma.c
> index dc4c2c1077f4..ee3a8ca13d07 100644
> --- a/mm/vma.c
> +++ b/mm/vma.c
> @@ -967,10 +967,9 @@ static __must_check struct vm_area_struct *vma_merge_existing_range(
> * prev middle next
> * extend delete delete
> */
> -
> vmg->start = prev->vm_start;
> vmg->end = next->vm_end;
> - vmg->pgoff = prev->vm_pgoff;
> + vmg->pgoff = vma_start_pgoff(prev);
>
> /*
> * We already ensured anon_vma compatibility above, so now it's
> @@ -987,9 +986,8 @@ static __must_check struct vm_area_struct *vma_merge_existing_range(
> * prev middle
> * extend shrink/delete
> */
> -
> vmg->start = prev->vm_start;
> - vmg->pgoff = prev->vm_pgoff;
> + vmg->pgoff = vma_start_pgoff(prev);
>
> if (!vmg->__remove_middle)
> vmg->__adjust_middle_start = true;
> @@ -1011,13 +1009,13 @@ static __must_check struct vm_area_struct *vma_merge_existing_range(
>
> if (vmg->__remove_middle) {
> vmg->end = next->vm_end;
> - vmg->pgoff = next->vm_pgoff - pglen;
> + vmg->pgoff = vma_start_pgoff(next) - pglen;
> } else {
> /* We shrink middle and expand next. */
> vmg->__adjust_next_start = true;
> vmg->start = middle->vm_start;
> vmg->end = start;
> - vmg->pgoff = middle->vm_pgoff;
> + vmg->pgoff = vma_start_pgoff(middle);
> }
>
> err = dup_anon_vma(next, middle, &anon_dup);
> @@ -1126,7 +1124,7 @@ struct vm_area_struct *vma_merge_new_range(struct vma_merge_struct *vmg)
> if (can_merge_left) {
> vmg->start = prev->vm_start;
> vmg->target = prev;
> - vmg->pgoff = prev->vm_pgoff;
> + vmg->pgoff = vma_start_pgoff(prev);
>
> /*
> * If this merge would result in removal of the next VMA but we
> @@ -1957,7 +1955,8 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap,
> VM_BUG_ON_VMA(faulted_in_anon_vma, new_vma);
> *vmap = vma = new_vma;
> }
> - *need_rmap_locks = (new_vma->vm_pgoff <= vma->vm_pgoff);
> + *need_rmap_locks =
> + (vma_start_pgoff(new_vma) <= vma_start_pgoff(vma));
> } else {
> new_vma = vm_area_dup(vma);
> if (!new_vma)
> diff --git a/mm/vma_exec.c b/mm/vma_exec.c
> index 5cee8b7efa0f..e3644a3042e2 100644
> --- a/mm/vma_exec.c
> +++ b/mm/vma_exec.c
> @@ -37,7 +37,7 @@ int relocate_vma_down(struct vm_area_struct *vma, unsigned long shift)
> unsigned long new_end = old_end - shift;
> VMA_ITERATOR(vmi, mm, new_start);
> VMG_STATE(vmg, mm, &vmi, new_start, old_end, EMPTY_VMA_FLAGS,
> - vma->vm_pgoff);
> + vma_start_pgoff(vma));
> struct vm_area_struct *next;
> struct mmu_gather tlb;
> PAGETABLE_MOVE(pmc, vma, vma, old_start, new_start, length);
> @@ -89,7 +89,7 @@ int relocate_vma_down(struct vm_area_struct *vma, unsigned long shift)
>
> vma_prev(&vmi);
> /* Shrink the vma to just the new range */
> - return vma_shrink(&vmi, vma, new_start, new_end, vma->vm_pgoff);
> + return vma_shrink(&vmi, vma, new_start, new_end, vma_start_pgoff(vma));
> }
>
> /*
> diff --git a/mm/vma_init.c b/mm/vma_init.c
> index 3c0b65950510..a459669a1654 100644
> --- a/mm/vma_init.c
> +++ b/mm/vma_init.c
> @@ -46,7 +46,7 @@ static void vm_area_init_from(const struct vm_area_struct *src,
> dest->vm_start = src->vm_start;
> dest->vm_end = src->vm_end;
> dest->anon_vma = src->anon_vma;
> - dest->vm_pgoff = src->vm_pgoff;
> + dest->vm_pgoff = vma_start_pgoff(src);
> dest->vm_file = src->vm_file;
> dest->vm_private_data = src->vm_private_data;
> vm_flags_init(dest, src->vm_flags);
> --
> 2.54.0
>
^ permalink raw reply
* Re: [PATCH v1 06/11] rcu: Enable RCU callbacks to benefit from expedited grace periods
From: Puranjay Mohan @ 2026-07-09 15:36 UTC (permalink / raw)
To: Frederic Weisbecker
Cc: rcu, linux-kernel, linux-trace-kernel, Paul E. McKenney,
Neeraj Upadhyay, Joel Fernandes, Josh Triplett, Boqun Feng,
Uladzislau Rezki, Steven Rostedt, Mathieu Desnoyers,
Lai Jiangshan, Zqiang, Masami Hiramatsu, Davidlohr Bueso,
Breno Leitao
In-Reply-To: <ak-pI2CefDoz0D0M@localhost.localdomain>
On Thu, Jul 9, 2026 at 2:59 PM Frederic Weisbecker <frederic@kernel.org> wrote:
>
> Le Wed, Jun 24, 2026 at 06:23:48AM -0700, Puranjay Mohan a écrit :
> > Currently, RCU callbacks only track normal grace-period sequence
> > numbers. This means callbacks must wait for normal grace periods to
> > complete even when expedited grace periods have already elapsed.
>
> The changelog still misses the reason for this change. I had to read
> the lwn article to understand that this matters under memory pressure
> in order to release objects faster.
>
I will update the commit message in the next version.
Thanks for your review.
^ permalink raw reply
* Re: [PATCH 17/30] mm: prefer vma_[start,end]_pgoff() to vma->vm_pgoff in kernel/
From: Gregory Price @ 2026-07-09 15:49 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Pedro Falcato, Andrew Morton, Russell King, Dinh Nguyen,
Simon Schuster, James E . J . Bottomley, Helge Deller,
Jarkko Sakkinen, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, x86, Ian Abbott, H Hartley Sweeten, Lucas Stach,
David Airlie, Simona Vetter, Patrik Jakobsson, Maarten Lankhorst,
Maxime Ripard, Thomas Zimmermann, Rob Clark, Dmitry Baryshkov,
Tomi Valkeinen, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Christian Koenig, Huang Rui, Ankit Agrawal, Alex Williamson,
Alexander Viro, Christian Brauner, Dan Williams, Muchun Song,
Oscar Salvador, David Hildenbrand, Suren Baghdasaryan,
Liam R . Howlett, Matthew Wilcox, Marek Szyprowski,
Peter Zijlstra, Arnaldo Carvalho de Melo, Namhyung Kim,
Masami Hiramatsu, Oleg Nesterov, Steven Rostedt, SeongJae Park,
Miaohe Lin, Hugh Dickins, Mike Rapoport, Kees Cook, Paolo Bonzini,
linux-kernel, linux-arm-kernel, linux-parisc, linux-sgx, etnaviv,
dri-devel, linux-arm-msm, freedreno, linux-tegra, kvm,
linux-fsdevel, nvdimm, linux-mm, iommu, linux-perf-users,
linux-trace-kernel, kasan-dev, damon, Rik van Riel, Harry Yoo,
Jann Horn
In-Reply-To: <akZGqclqQ6gS12Vv@lucifer>
On Thu, Jul 02, 2026 at 12:30:59PM +0100, Lorenzo Stoakes wrote:
>
...
> static inline unsigned long vma_offset(const struct vm_area_struct *vma,
> const unsigned long address)
> {
> /* Retains page offset and tags. */
> return address - vma->vm_start;
> }
>
...
> And I'm not sure it's really all that useful. Perhaps retaining vma_offset()
> would be though.
>
Silly question:
What's the purpose of retaining tags in a non-address value?
That sounds like there's fragility just waiting to be broken.
(I presume you are talking about things like ARM MTE and such, right?)
> This is one that I think makes more sense.
>
> But in general, I'd rather hold off from yet more churn here.
>
> I'm making these changes to establish a basis for virtual page offsets
> introduced in [0], rather than just cleaning up in general.
>
I agree with this. If the refactors here suddenly have to think about
corner cases on things like tags, that's better resolved separately.
~Gregory
^ permalink raw reply
* Re: [PATCH 17/30] mm: prefer vma_[start,end]_pgoff() to vma->vm_pgoff in kernel/
From: Gregory Price @ 2026-07-09 15:49 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Russell King, Dinh Nguyen, Simon Schuster,
James E . J . Bottomley, Helge Deller, Jarkko Sakkinen,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Ian Abbott, H Hartley Sweeten, Lucas Stach, David Airlie,
Simona Vetter, Patrik Jakobsson, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Clark, Dmitry Baryshkov, Tomi Valkeinen,
Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Christian Koenig, Huang Rui, Ankit Agrawal, Alex Williamson,
Alexander Viro, Christian Brauner, Dan Williams, Muchun Song,
Oscar Salvador, David Hildenbrand, Suren Baghdasaryan,
Liam R . Howlett, Matthew Wilcox, Marek Szyprowski,
Peter Zijlstra, Arnaldo Carvalho de Melo, Namhyung Kim,
Masami Hiramatsu, Oleg Nesterov, Steven Rostedt, SeongJae Park,
Miaohe Lin, Hugh Dickins, Mike Rapoport, Kees Cook, Paolo Bonzini,
linux-kernel, linux-arm-kernel, linux-parisc, linux-sgx, etnaviv,
dri-devel, linux-arm-msm, freedreno, linux-tegra, kvm,
linux-fsdevel, nvdimm, linux-mm, iommu, linux-perf-users,
linux-trace-kernel, kasan-dev, damon, Pedro Falcato, Rik van Riel,
Harry Yoo, Jann Horn
In-Reply-To: <ea87349d63205bf4c26ea79854f179a9bf8cfb0b.1782735110.git.ljs@kernel.org>
On Mon, Jun 29, 2026 at 01:23:28PM +0100, Lorenzo Stoakes wrote:
> Be consistent in using vma_start_pgoff() and vma_end_pgoff(), which clearly
> indicates which part of the VMA the page offset refers to and aids
> greppability.
>
> This is part of a broader series laying the ground to provide a virtual
> page offset for MAP_PRIVATE-file backed anon folios.
>
> No functional change intended.
>
> Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
Reviewed-by: Gregory Price <gourry@gourry.net>
^ permalink raw reply
* Re: [PATCH 18/30] mm/vma: remove duplicative vma_pgoff_offset() helper
From: Gregory Price @ 2026-07-09 15:50 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Russell King, Dinh Nguyen, Simon Schuster,
James E . J . Bottomley, Helge Deller, Jarkko Sakkinen,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Ian Abbott, H Hartley Sweeten, Lucas Stach, David Airlie,
Simona Vetter, Patrik Jakobsson, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Clark, Dmitry Baryshkov, Tomi Valkeinen,
Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Christian Koenig, Huang Rui, Ankit Agrawal, Alex Williamson,
Alexander Viro, Christian Brauner, Dan Williams, Muchun Song,
Oscar Salvador, David Hildenbrand, Suren Baghdasaryan,
Liam R . Howlett, Matthew Wilcox, Marek Szyprowski,
Peter Zijlstra, Arnaldo Carvalho de Melo, Namhyung Kim,
Masami Hiramatsu, Oleg Nesterov, Steven Rostedt, SeongJae Park,
Miaohe Lin, Hugh Dickins, Mike Rapoport, Kees Cook, Paolo Bonzini,
linux-kernel, linux-arm-kernel, linux-parisc, linux-sgx, etnaviv,
dri-devel, linux-arm-msm, freedreno, linux-tegra, kvm,
linux-fsdevel, nvdimm, linux-mm, iommu, linux-perf-users,
linux-trace-kernel, kasan-dev, damon, Pedro Falcato, Rik van Riel,
Harry Yoo, Jann Horn
In-Reply-To: <10671c2fc5d0dd4e3bf497181923e63e46053df1.1782735110.git.ljs@kernel.org>
On Mon, Jun 29, 2026 at 01:23:29PM +0100, Lorenzo Stoakes wrote:
> This is doing what linear_page_index() does, so eliminate it and replace it
> with linear_page_index().
>
> Update the VMA userland tests to reflect this change.
>
> No functional change intended.
>
> Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
Reviewed-by: Gregory Price <gourry@gourry.net>
^ permalink raw reply
* Re: [PATCH v3 14/17] verification/rvgen: Add selftests for rvgen kunit
From: Gabriele Monaco @ 2026-07-09 15:52 UTC (permalink / raw)
To: Nam Cao, linux-trace-kernel, linux-kernel
Cc: Thomas Weissschuh, Tomas Glozar, John Kacur, Wen Yang,
Steven Rostedt
In-Reply-To: <87a4s0fuqx.fsf@yellow.woof>
On Thu, 2026-07-09 at 10:11 +0200, Nam Cao wrote:
> Gabriele Monaco <gmonaco@redhat.com> writes:
> > The rvgen kunit command patches monitor files and adds necessary
> > definitions for kunit tests.
> >
> > Add a test case validating its behaviour on dummy generated files and
> > comparing it against reference files, like it's done for rvgen monitor.
> >
> > Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
>
> I am not entirely sure about this. In the future, when the generation
> output is changed, all the references files also need to be updated. So
> it's not clear to me if this really saves future development effort.
Yeah that's an issue with all this testing with golden files. At least unless we
change the output drastically, changes to those should be easy to apply and to
review (and LLMs can help here too).
> But well, we will see. For now:
>
> Reviewed-by: Nam Cao <namcao@linutronix.de>
Thanks,
Gabriele
^ permalink raw reply
* Re: [PATCH 19/30] mm: use linear_page_[index, delta]() consistently
From: Gregory Price @ 2026-07-09 15:55 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Russell King, Dinh Nguyen, Simon Schuster,
James E . J . Bottomley, Helge Deller, Jarkko Sakkinen,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Ian Abbott, H Hartley Sweeten, Lucas Stach, David Airlie,
Simona Vetter, Patrik Jakobsson, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Clark, Dmitry Baryshkov, Tomi Valkeinen,
Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Christian Koenig, Huang Rui, Ankit Agrawal, Alex Williamson,
Alexander Viro, Christian Brauner, Dan Williams, Muchun Song,
Oscar Salvador, David Hildenbrand, Suren Baghdasaryan,
Liam R . Howlett, Matthew Wilcox, Marek Szyprowski,
Peter Zijlstra, Arnaldo Carvalho de Melo, Namhyung Kim,
Masami Hiramatsu, Oleg Nesterov, Steven Rostedt, SeongJae Park,
Miaohe Lin, Hugh Dickins, Mike Rapoport, Kees Cook, Paolo Bonzini,
linux-kernel, linux-arm-kernel, linux-parisc, linux-sgx, etnaviv,
dri-devel, linux-arm-msm, freedreno, linux-tegra, kvm,
linux-fsdevel, nvdimm, linux-mm, iommu, linux-perf-users,
linux-trace-kernel, kasan-dev, damon, Pedro Falcato, Rik van Riel,
Harry Yoo, Jann Horn
In-Reply-To: <bf56e2e98b512962a2fb88900d535a0e9e6769d8.1782735110.git.ljs@kernel.org>
On Mon, Jun 29, 2026 at 01:23:30PM +0100, Lorenzo Stoakes wrote:
> There are a number of places where we open code what linear_page_index()
> and linear_page_delta() calculate.
>
> Replace this code with the appropriate functions for consistency.
>
> No functional change intended.
>
> Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
one nit
Reviewed-by: Gregory Price <gourry@gourry.net>
...
> diff --git a/drivers/comedi/comedi_fops.c b/drivers/comedi/comedi_fops.c
> index c09bbe04be6c..536c25d8dcee 100644
> --- a/drivers/comedi/comedi_fops.c
> +++ b/drivers/comedi/comedi_fops.c
> @@ -25,6 +25,7 @@
> #include <linux/fs.h>
> #include <linux/comedi/comedidev.h>
> #include <linux/cdev.h>
> +#include <linux/pagemap.h>
>
> #include <linux/io.h>
> #include <linux/uaccess.h>
> @@ -2462,7 +2463,7 @@ static int comedi_vm_access(struct vm_area_struct *vma, unsigned long addr,
> {
> struct comedi_buf_map *bm = vma->vm_private_data;
> unsigned long offset =
> - addr - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT);
> + addr - vma->vm_start + (vma_start_pgoff(vma) << PAGE_SHIFT);
>
Obviously correct, but was this intended for a different patch?
~Gregory
^ permalink raw reply
* Re: [PATCH 19/30] mm: use linear_page_[index, delta]() consistently
From: Gregory Price @ 2026-07-09 15:57 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Andrew Morton, Russell King, Dinh Nguyen, Simon Schuster,
James E . J . Bottomley, Helge Deller, Jarkko Sakkinen,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
Ian Abbott, H Hartley Sweeten, Lucas Stach, David Airlie,
Simona Vetter, Patrik Jakobsson, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Clark, Dmitry Baryshkov, Tomi Valkeinen,
Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Christian Koenig, Huang Rui, Ankit Agrawal, Alex Williamson,
Alexander Viro, Christian Brauner, Dan Williams, Muchun Song,
Oscar Salvador, David Hildenbrand, Suren Baghdasaryan,
Liam R . Howlett, Matthew Wilcox, Marek Szyprowski,
Peter Zijlstra, Arnaldo Carvalho de Melo, Namhyung Kim,
Masami Hiramatsu, Oleg Nesterov, Steven Rostedt, SeongJae Park,
Miaohe Lin, Hugh Dickins, Mike Rapoport, Kees Cook, Paolo Bonzini,
linux-kernel, linux-arm-kernel, linux-parisc, linux-sgx, etnaviv,
dri-devel, linux-arm-msm, freedreno, linux-tegra, kvm,
linux-fsdevel, nvdimm, linux-mm, iommu, linux-perf-users,
linux-trace-kernel, kasan-dev, damon, Pedro Falcato, Rik van Riel,
Harry Yoo, Jann Horn
In-Reply-To: <ak_EivwcDDdn1Xvp@gourry-fedora-PF4VCD3F>
On Thu, Jul 09, 2026 at 11:55:54AM -0400, Gregory Price wrote:
> > @@ -2462,7 +2463,7 @@ static int comedi_vm_access(struct vm_area_struct *vma, unsigned long addr,
> > {
> > struct comedi_buf_map *bm = vma->vm_private_data;
> > unsigned long offset =
> > - addr - vma->vm_start + (vma->vm_pgoff << PAGE_SHIFT);
> > + addr - vma->vm_start + (vma_start_pgoff(vma) << PAGE_SHIFT);
> >
>
> Obviously correct, but was this intended for a different patch?
>
> ~Gregory
bleh already caught, sorry for the noise :]
^ permalink raw reply
* Re: [PATCH v3 06/11] mm/cma: Allow dynamically creating CMA areas
From: Thierry Reding @ 2026-07-09 15:59 UTC (permalink / raw)
To: Marek Szyprowski
Cc: David Hildenbrand (Arm), Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Jonathan Hunter, Mikko Perttunen, Yury Norov,
Rasmus Villemoes, Russell King, Alexander Gordeev,
Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, Andrew Morton,
Lorenzo Stoakes, Liam R. Howlett, Vlastimil Babka, Mike Rapoport,
Suren Baghdasaryan, Michal Hocko, Robin Murphy, Sumit Semwal,
Benjamin Gaignard, Brian Starkey, John Stultz, T.J. Mercier,
Christian König, Steven Rostedt, Masami Hiramatsu,
Mathieu Desnoyers, Catalin Marinas, Will Deacon, devicetree,
linux-tegra, linux-kernel, dri-devel, linux-media,
linux-arm-kernel, linux-s390, linux-mm, iommu, linaro-mm-sig,
linux-trace-kernel
In-Reply-To: <83e5e74d-7106-4e14-9d10-56438372f6a3@samsung.com>
[-- Attachment #1: Type: text/plain, Size: 1925 bytes --]
On Thu, Jul 09, 2026 at 07:56:45AM +0200, Marek Szyprowski wrote:
> On 08.07.2026 10:35, David Hildenbrand (Arm) wrote:
> > On 7/7/26 12:02, Marek Szyprowski wrote:
> >> On 01.07.2026 18:08, Thierry Reding wrote:
> >>> From: Thierry Reding <treding@nvidia.com>
> >>>
> >>> There is no technical reason why there should be a limited number of CMA
> >>> regions, so extract some code into helpers and use them to create extra
> >>> functions (cma_create() and cma_free()) that allow creating and freeing,
> >>> respectively, CMA regions dynamically at runtime.
> >>
> >> Well, the technical reason for not creating cma regions dynamically at
> >> runtime is that on some architectures (like 32bit ARM) the early fixup
> >> for the region is needed to make it functional for DMA.
> > Can you point me at the code that does that? Thanks!
> Check dma_contiguous_early_fixup() and dma_contiguous_remap() in
> arch/arm/mm/dma-mapping.c. Those functions ensures that the CPU mappings for
> the CMA reserved region in linear map are remapped with 4k pages instead
> of the 1M sections, so later, it will be possible to alter the mappings and
> change them to coherent when needed (altering 1M sections is not possible,
> because each process has it's own level-1 array even for the kernel linear
> mapping).
>
>
>
> However, in the use case in this patchset the reserved region is only shared
> with buddy allocator by using the CMA infrastructure, not registered to the
> regular DMA-mapping API, so it would work fine. I'm not convinced that this
> is the right API to use for this though.
Are you saying you're not convinced that CMA is the right API to use for
this? Or something else?
I certainly don't think we want to get the DMA-mapping API involved for
this because that always implies that we perform cache operations, which
we specifically don't want for this memory.
Thierry
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* [PATCH v2 0/3] tracing/remotes: Fix leak in trace_remote_alloc_buffer() error path
From: Vincent Donnefort @ 2026-07-09 16:00 UTC (permalink / raw)
To: rostedt, mhiramat, linux-trace-kernel
Cc: mathieu.desnoyers, kernel-team, linux-kernel, Vincent Donnefort
This series addresses a few issues in the trace remote buffers allocation
and descriptor handling, mostly reported by Sashiko bot on top of v1.
Changelog:
v1 -> v2:
- Leak fix: increment nr_cpus early (after meta_va allocation) instead of
in the error path.
- Added struct_len double-counting fix.
- Added sparse CPU masks support in ring_buffer_desc().
v1: https://lore.kernel.org/all/20260708133201.295072-1-vdonnefort@google.com/
Vincent Donnefort (3):
tracing/remotes: Fix leak in trace_remote_alloc_buffer() error path
tracing/remotes: Fix struct_len in trace_remote_alloc_buffer()
ring-buffer: Allow sparse CPU masks in ring_buffer_desc()
kernel/trace/ring_buffer.c | 5 +----
kernel/trace/trace_remote.c | 18 ++++++------------
2 files changed, 7 insertions(+), 16 deletions(-)
base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply
* [PATCH v2 1/3] tracing/remotes: Fix leak in trace_remote_alloc_buffer() error path
From: Vincent Donnefort @ 2026-07-09 16:00 UTC (permalink / raw)
To: rostedt, mhiramat, linux-trace-kernel
Cc: mathieu.desnoyers, kernel-team, linux-kernel, Vincent Donnefort,
Sashiko
In-Reply-To: <20260709160017.1729517-1-vdonnefort@google.com>
If page allocation fails in trace_remote_alloc_buffer(), desc->nr_cpus
is not yet incremented for the current CPU. As a consequence, on error,
half-allocated rb_desc will not be freed in trace_remote_free_buffer().
Increment desc->nr_cpus as soon as the first allocation for the current
CPU has succeeded.
Fixes: 96e43537af54 ("tracing: Introduce trace remotes")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c
index 2a6cc000ec98..d48042239d58 100644
--- a/kernel/trace/trace_remote.c
+++ b/kernel/trace/trace_remote.c
@@ -1006,6 +1006,8 @@ int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size,
if (!rb_desc->meta_va)
goto err;
+ desc->nr_cpus++;
+
for (id = 0; id < nr_pages; id++) {
rb_desc->page_va[id] = (unsigned long)__get_free_page(GFP_KERNEL);
if (!rb_desc->page_va[id])
@@ -1013,7 +1015,6 @@ int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size,
rb_desc->nr_page_va++;
}
- desc->nr_cpus++;
desc->struct_len += offsetof(struct ring_buffer_desc, page_va);
desc->struct_len += struct_size(rb_desc, page_va, rb_desc->nr_page_va);
rb_desc = __next_ring_buffer_desc(rb_desc);
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related
* [PATCH v2 2/3] tracing/remotes: Fix struct_len in trace_remote_alloc_buffer()
From: Vincent Donnefort @ 2026-07-09 16:00 UTC (permalink / raw)
To: rostedt, mhiramat, linux-trace-kernel
Cc: mathieu.desnoyers, kernel-team, linux-kernel, Vincent Donnefort,
Sashiko
In-Reply-To: <20260709160017.1729517-1-vdonnefort@google.com>
Pre-calculate desc->struct_len up-front in trace_remote_alloc_buffer()
with trace_buffer_desc_size() to fix double-counting.
While at it, use the accessor __first_ring_buffer_desc().
Fixes: 96e43537af54 ("tracing: Introduce trace remotes")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c
index d48042239d58..0f6ef5c36d84 100644
--- a/kernel/trace/trace_remote.c
+++ b/kernel/trace/trace_remote.c
@@ -979,27 +979,22 @@ EXPORT_SYMBOL_GPL(trace_remote_free_buffer);
int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size, size_t buffer_size,
const struct cpumask *cpumask)
{
+ size_t min_desc_size = trace_buffer_desc_size(buffer_size, cpumask_weight(cpumask));
unsigned int nr_pages = max(DIV_ROUND_UP(buffer_size, PAGE_SIZE), 2UL) + 1;
- void *desc_end = desc + desc_size;
struct ring_buffer_desc *rb_desc;
int cpu, ret = -ENOMEM;
- if (desc_size < struct_size(desc, __data, 0))
+ if (desc_size < min_desc_size)
return -EINVAL;
desc->nr_cpus = 0;
- desc->struct_len = struct_size(desc, __data, 0);
+ desc->struct_len = min_desc_size;
- rb_desc = (struct ring_buffer_desc *)&desc->__data[0];
+ rb_desc = __first_ring_buffer_desc(desc);
for_each_cpu(cpu, cpumask) {
unsigned int id;
- if ((void *)rb_desc + struct_size(rb_desc, page_va, nr_pages) > desc_end) {
- ret = -EINVAL;
- goto err;
- }
-
rb_desc->cpu = cpu;
rb_desc->nr_page_va = 0;
rb_desc->meta_va = (unsigned long)__get_free_page(GFP_KERNEL);
@@ -1015,8 +1010,6 @@ int trace_remote_alloc_buffer(struct trace_buffer_desc *desc, size_t desc_size,
rb_desc->nr_page_va++;
}
- desc->struct_len += offsetof(struct ring_buffer_desc, page_va);
- desc->struct_len += struct_size(rb_desc, page_va, rb_desc->nr_page_va);
rb_desc = __next_ring_buffer_desc(rb_desc);
}
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related
* [PATCH v2 3/3] ring-buffer: Allow sparse CPU masks in ring_buffer_desc()
From: Vincent Donnefort @ 2026-07-09 16:00 UTC (permalink / raw)
To: rostedt, mhiramat, linux-trace-kernel
Cc: mathieu.desnoyers, kernel-team, linux-kernel, Vincent Donnefort,
Sashiko
In-Reply-To: <20260709160017.1729517-1-vdonnefort@google.com>
No user currently relies on sparse CPU masks, but the descriptor logic already
supports them via linear fallback. Remove the arbitrary limitation.
Fixes: 2e67fabd8b77 ("ring-buffer: Introduce ring-buffer remotes")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 56a328e94395..4e7b4ce7b8a7 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -2329,10 +2329,7 @@ static struct ring_buffer_desc *ring_buffer_desc(struct trace_buffer_desc *trace
size_t len;
int i;
- if (!trace_desc)
- return NULL;
-
- if (cpu >= trace_desc->nr_cpus)
+ if (!trace_desc || !trace_desc->nr_cpus)
return NULL;
end = (struct ring_buffer_desc *)((void *)trace_desc + trace_desc->struct_len);
--
2.55.0.795.g602f6c329a-goog
^ permalink raw reply related
* Re: [PATCH v2 1/4] mm/migrate: do not migrate folios mapped into VM_LOCKED VMAs under compaction
From: Zi Yan @ 2026-07-09 16:10 UTC (permalink / raw)
To: Wandun
Cc: Lorenzo Stoakes, vbabka, david, rostedt, mhiramat,
Alexander.Krabler, hughd, fvdl, bigeasy, linux-mm, linux-kernel,
linux-trace-kernel, linux-rt-devel, akpm, surenb, mhocko,
jackmanb, hannes, riel, liam, harry, jannh, lance.yang,
mathieu.desnoyers, matthew.brost, joshua.hahnjy, rakie.kim,
byungchul, gourry, ying.huang, apopple, pfalcato
In-Reply-To: <c372e68f-2bfc-45b6-a431-01bf55717247@gmail.com>
On 8 Jul 2026, at 23:31, Wandun wrote:
> On 7/7/26 21:44, Lorenzo Stoakes wrote:
>> (Being really nitty, your subject line is too long)
>>
>> Please don't reference legacy VMA flags for newer patches 'do not migrate
>> folios mapped into mlocked VMAs...' works just as well.
> Got it.
>>
>> On Tue, Jul 07, 2026 at 08:59:22PM +0800, Wandun Chen wrote:
>>> From: Wandun Chen <chenwandun@lixiang.com>
>>>
>>> When compact_unevictable_allowed=0, unevictable pages should not be
>>> migrated. However, mlock_folio_batch in the mlock[all] syscall introduces
>>> a race, mlock_folio() sets PG_mlocked immediately but defers PG_unevictable
>>> to mlock_folio_batch(), causing pages that are about to become unevictable
>>> to be migrated, which violates the intent of compact_unevictable_allowed,
>>> and causes spike latency in RT kernels [1].
>>>
>>> In order to fix this, migration is forbidden for pages mapped into VMAs
>>> marked with VM_LOCKED. In addition, two early-return paths are introduced,
>>
>> Please don't reference legacy VMA flags. -> VMA_LOCKED_BIT.
> Got it.
>>
>>> filter out mlocked pages, return early to avoid unnecessary operations.
>>>
>>> Fixes: 90d07210ab55 ("mm: mlock: use folios and a folio batch internally")
>>
>> Hmmmm why do you think my patch caused this? That was just a folio conversion?
>
> Oh, I made a mistake, your patch was just a folio conversion.
>
> Batching mlocked page was introduced in v5.18 by:
> commit 2fbb0c10d1e8 ("mm/munlock: mlock_page() munlock_page() batch by pagevec")
>
> Setting sysctl_compact_unevictable_allowed to zero was introduced in v5.7 by:
> commit 6923aa0d8c62 ("mm/compaction: Disable compact_unevictable_allowed on RT")
>
> So this issue exist after v5.18.
>
>>
>> Also I didn't think we liked having fixes spotted about a series with non-fixes
>> tags?
> Got it, will split this series in next version.
>>
>>> Reported-by: Alexander Krabler <Alexander.Krabler@kuka.com>
>>> Closes: https://lore.kernel.org/all/DU0PR01MB10385345F7153F334100981888259A@DU0PR01MB10385.eurprd01.prod.exchangelabs.com/ [1]
>>> Suggested-by: Vlastimil Babka <vbabka@suse.cz>
>>> Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
>>> Link: https://lore.kernel.org/linux-rt-users/33275585-f2db-4779-89f0-3ae24b455a67@suse.cz/#t
>>> ---
>>> include/linux/compaction.h | 6 ++++++
>>> include/linux/rmap.h | 3 +++
>>> mm/compaction.c | 8 +++++++-
>>> mm/migrate.c | 23 +++++++++++++++++++----
>>> mm/rmap.c | 12 +++++++++---
>>> 5 files changed, 44 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/include/linux/compaction.h b/include/linux/compaction.h
>>> index f29ef0653546..04e60f65b976 100644
>>> --- a/include/linux/compaction.h
>>> +++ b/include/linux/compaction.h
>>> @@ -106,6 +106,7 @@ bool compaction_zonelist_suitable(struct alloc_context *ac, int order,
>>> extern void __meminit kcompactd_run(int nid);
>>> extern void __meminit kcompactd_stop(int nid);
>>> extern void wakeup_kcompactd(pg_data_t *pgdat, int order, int highest_zoneidx);
>>> +extern bool compaction_allow_unevictable(void);
>>
>> Don't use extern. We remove extern as we go it's not needed.
> Got it.
>>
>>>
>>> #else
>>> static inline void reset_isolation_suitable(pg_data_t *pgdat)
>>> @@ -131,6 +132,11 @@ static inline void wakeup_kcompactd(pg_data_t *pgdat,
>>> {
>>> }
>>>
>>> +static inline bool compaction_allow_unevictable(void)
>>> +{
>>> + return true;
>>> +}
>>> +
>>> #endif /* CONFIG_COMPACTION */
>>>
>>> struct node;
>>> diff --git a/include/linux/rmap.h b/include/linux/rmap.h
>>> index 8dc0871e5f00..359c7426b6b9 100644
>>> --- a/include/linux/rmap.h
>>> +++ b/include/linux/rmap.h
>>> @@ -102,6 +102,9 @@ enum ttu_flags {
>>> * do a final flush if necessary */
>>> TTU_RMAP_LOCKED = 0x80, /* do not grab rmap lock:
>>> * caller holds it */
>>> + TTU_RESPECT_MLOCK = 0x100,/* leave VM_LOCKED vmas mapped instead
>>
>> -> VMA_LOCKED_BIT please. Also maybe just say mlock'd?
> Got it.
>>
>>> + * of installing a migration entry
>>> + */
>>> };
>>>
>>> #ifdef CONFIG_MMU
>>> diff --git a/mm/compaction.c b/mm/compaction.c
>>> index f08765ade014..5d256930e389 100644
>>> --- a/mm/compaction.c
>>> +++ b/mm/compaction.c
>>> @@ -1116,7 +1116,8 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
>>> is_unevictable = folio_test_unevictable(folio);
>>>
>>> /* Compaction might skip unevictable pages but CMA takes them */
>>> - if (!(mode & ISOLATE_UNEVICTABLE) && is_unevictable)
>>> + if (!(mode & ISOLATE_UNEVICTABLE) &&
>>> + (is_unevictable || folio_test_mlocked(folio)))
>>
>> Maybe just change is_unevictable to include this check?
>>
>> Like:
>>
>> is_unevictable = folio_test_unevictable(folio) ||
>> folio_test_mlocked(folio);
>>
>> ?
> Sounds good, I'll fold mlock into is_unevictable so both checks
> stay consistent.
>>
>> Also later you have:
>>
>> if (((mode & ISOLATE_ASYNC_MIGRATE) && is_dirty) ||
>> (mapping && is_unevictable)) {
>> ...
>>
>> Which doesn't account for mlock as-is? Is that correct?
> IIUC, The is_unevictable check here mainly serves as a cheap pre-filter
> for inaccessible mappings (which are always unevictable folio).
> It's unrelated to the mlock.
>
>>
>>
>>
>>> goto isolate_fail_put;
>>>
>>> /*
>>> @@ -1898,6 +1899,11 @@ typedef enum {
>>> * compactable pages.
>>> */
>>> static int sysctl_compact_unevictable_allowed __read_mostly = CONFIG_COMPACT_UNEVICTABLE_DEFAULT;
>>> +
>>> +bool compaction_allow_unevictable(void)
>>> +{
>>> + return sysctl_compact_unevictable_allowed;
>>> +}
>>
>> You add this helper but isolate_migratepages() still references
>> sysctl_compact_unevictable_allowed directly?
> I'll route that reference through compaction_allow_unevictable()
> in next version.
>>
>>> /*
>>> * Tunable for proactive compaction. It determines how
>>> * aggressively the kernel should compact memory in the
>>> diff --git a/mm/migrate.c b/mm/migrate.c
>>> index a786549551e3..3a15eb13e82b 100644
>>> --- a/mm/migrate.c
>>> +++ b/mm/migrate.c
>>> @@ -1202,7 +1202,7 @@ static void migrate_folio_done(struct folio *src,
>>> static int migrate_folio_unmap(new_folio_t get_new_folio,
>>> free_folio_t put_new_folio, unsigned long private,
>>> struct folio *src, struct folio **dstp, enum migrate_mode mode,
>>> - struct list_head *ret)
>>> + struct list_head *ret, enum migrate_reason reason)
>>> {
>>> struct folio *dst;
>>> int rc = -EAGAIN;
>>> @@ -1210,6 +1210,7 @@ static int migrate_folio_unmap(new_folio_t get_new_folio,
>>> struct anon_vma *anon_vma = NULL;
>>> bool locked = false;
>>> bool dst_locked = false;
>>> + enum ttu_flags ttu = 0;
>>
>> You reference ttu only in an if-block below no? So why are you declaring
>> this here? Move it to the if-block.
> Got it. I'll move it to the if-block in next version.
>>
>>>
>>> dst = get_new_folio(src, private);
>>> if (!dst)
>>> @@ -1249,9 +1250,15 @@ static int migrate_folio_unmap(new_folio_t get_new_folio,
>>> folio_lock(src);
>>> }
>>> locked = true;
>>> - if (folio_test_mlocked(src))
>>> + if (folio_test_mlocked(src)) {
>>> old_folio_state |= FOLIO_WAS_MLOCKED;
>>>
>>> + if (reason == MR_COMPACTION && !compaction_allow_unevictable()) {
>>
>> This should really be a helper since you repeat yourself and it's not
>> obvious what this is checking.
>>
>> Like:
>>
>> static migrate_mlock_allowed(enum migrate_reason reason)
>> {
>> /* Only compaction is disallowed. */
>> if (reason != MR_COMPACTION)
>> return true;
>>
>> /* If we can compact unevictable folios, we are ok. */
>> if (compaction_allow_unevictable())
>> return true;
>>
>> /* Conservative: if any folio could be mlock()'d, disallow. */
>> return false;
>> }
>>
>> Then you could self-document what you're checking and avoid code duplication below.
> Got it, it is more clear, thanks.
>>
>>> + rc = -EBUSY;
>>> + goto out;
>>> + }
>>> + }
>>> +
>>> if (folio_test_writeback(src)) {
>>> /*
>>> * Only in the case of a full synchronous migration is it
>>> @@ -1324,7 +1331,14 @@ static int migrate_folio_unmap(new_folio_t get_new_folio,
>>> /* Establish migration ptes */
>>> VM_BUG_ON_FOLIO(folio_test_anon(src) &&
>>> !folio_test_ksm(src) && !anon_vma, src);
>>
>> Useful to convert VM_BUG_*() -> VM_WARN_*() (possibly _ONCE() here also) as we go!
> Got it.
>>
>>> - try_to_migrate(src, mode == MIGRATE_ASYNC ? TTU_BATCH_FLUSH : 0);
>>> +
>>> + if (mode == MIGRATE_ASYNC)
>>> + ttu |= TTU_BATCH_FLUSH;
>>> +
>>> + if (reason == MR_COMPACTION && !compaction_allow_unevictable())
>>
>> See above about deduplicating.
>>
>>> + ttu |= TTU_RESPECT_MLOCK;
>>
>> Hmm. I don't love 'respect mlock'. I guess we only know about the reason
>> being compaction here.
> Right, we only know about the reason.
>>
>> But I'm confused anyway. We have the folio, why aren't we just checking for
>> PG_mlocked() here instead of getting the rmap to see if it's mapped
>> anywhere with VMA_LOCKED_BIT?
>
> There was a race scenario without patch 02, vma may already marked with
> VMA_LOCKED_BIT but folio has't marked with mlocked, such as below:
>
>
> CPUA: mlock() CPUB: compaction / migration
>
> mmap_write_lock()
> mlock_fixup set VM_CLOKED
> mlock_pte_range
> mlock_folio(page N)
>
> isolate page N+50 (mlock hasn't reached it)
> migrate_folio_unmap
> folio_test_mlocked() --> false, but VMA:VM_LOCKED
> try_to_migrate()
> rmap_walk(P) [anon_vma rwsem / i_mmap_rwsem, read]
> try_to_migrate_one -->install migration entry
> ...reaches page N+50
> skip migration entry (without patch 02)
> mmap_write_unlock()
>
>
> access page N + 50 --> wait for migration complete
>
> migrate_folios_move
> ....
> migrate complete
>
>
>
> If apply patch 02, mlock itself will wait migration complete, so checking
> VMA_LOCKED_BIT in the rmap path is no longer necessary, but this logic is
> retained to avoid unnecessary migration operations.
>
For this race condition, since VMA has VM_LOCKED_BIT set, maybe you can
extend rwc->invalid_vma semantics to return 1:SKIP, 0:OK, -1:STOP.
Then install an invalid_vma function when !compaction_allow_unevictable().
The invalid_vma function returns -1:STOP for any vma with VM_LOCKED_BIT set.
__rmap_walk_file() and rmap_walk_anon() will need to break when -1:STOP
is returned.
This approach will not require a new TTU flag, although it requires more
code changes.
Best Regards,
Yan, Zi
^ permalink raw reply
* Re: [PATCH v3 04/11] arm64/mm: Add set_memory_device() and set_memory_normal()
From: Thierry Reding @ 2026-07-09 16:13 UTC (permalink / raw)
To: Will Deacon
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jonathan Hunter,
David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Sowjanya Komatineni, Luca Ceresoli,
Mikko Perttunen, Yury Norov, Rasmus Villemoes, Russell King,
Alexander Gordeev, Gerald Schaefer, Heiko Carstens, Vasily Gorbik,
Christian Borntraeger, Sven Schnelle, Andrew Morton,
David Hildenbrand, Lorenzo Stoakes, Liam R. Howlett,
Vlastimil Babka, Mike Rapoport, Suren Baghdasaryan, Michal Hocko,
Marek Szyprowski, Robin Murphy, Sumit Semwal, Benjamin Gaignard,
Brian Starkey, John Stultz, T.J. Mercier, Christian König,
Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
Catalin Marinas, Thierry Reding, devicetree, linux-tegra,
linux-kernel, dri-devel, linux-media, linux-arm-kernel,
linux-s390, linux-mm, iommu, linaro-mm-sig, linux-trace-kernel,
Thierry Reding, Chun Ng
In-Reply-To: <ak5CXzGStC6ZmtwI@orome>
[-- Attachment #1: Type: text/plain, Size: 7996 bytes --]
On Wed, Jul 08, 2026 at 02:50:04PM +0200, Thierry Reding wrote:
> On Tue, Jul 07, 2026 at 12:27:13PM +0100, Will Deacon wrote:
> > On Mon, Jul 06, 2026 at 03:49:24PM +0200, Thierry Reding wrote:
> > > On Fri, Jul 03, 2026 at 06:13:31PM +0100, Will Deacon wrote:
> > > > On Thu, Jul 02, 2026 at 06:41:23PM +0200, Thierry Reding wrote:
> > > > > On Thu, Jul 02, 2026 at 03:46:44PM +0200, Thierry Reding wrote:
> > > > > > On Thu, Jul 02, 2026 at 10:18:47AM +0100, Will Deacon wrote:
> > > > > > > On Wed, Jul 01, 2026 at 06:08:15PM +0200, Thierry Reding wrote:
> > > > > > > > From: Chun Ng <chunn@nvidia.com>
> > > > > > > >
> > > > > > > > Add helpers to swap PROT_NORMAL and PROT_DEVICE_nGnRnE protection bits
> > > > > > > > on a kernel-linear-map range.
> > > > > > >
> > > > > > > That sounds like a really terrible idea. Why is this necessary and how
> > > > > > > does it interact with things like load_unaligned_zeropad()?
> > > > > >
> > > > > > This is necessary because once the memory controller has walled off the
> > > > > > new memory region the CPU must not access it under any circumstances or
> > > > > > it'll cause the CPU to lock up (I think technically it'll hit an SError
> > > > > > but in practice that just means it'll freeze, as far as I can tell).
> > > > > >
> > > > > > Probably doesn't interact well at all with load_unaligned_zeropad().
> > > > > >
> > > > > > > I think you should unmap the memory from the linear map and memremap()
> > > > > > > it instead.
> > > > > >
> > > > > > Given that the memory can never be accessed by the CPU after the memory
> > > > > > controller locks it down, I don't think we'll even need memremap(). The
> > > > > > only thing we really need is the sg_table we hand out via the DMA BUFs
> > > > > > so that they can be used by device drivers to program their DMA engines
> > > > > > internally.
> > > > > >
> > > > > > Looking through some of the architecture code around this, shouldn't we
> > > > > > simply be using set_memory_encrypted() and set_memory_decrypted() for
> > > > > > this? While they might've been created for slightly other use-cases,
> > > > > > they seem to be doing exactly what we want (i.e. remove the page range
> > > > > > from the linear mapping and flushing it, or restoring the valid bit and
> > > > > > standard permissions, respectively).
> > > > >
> > > > > Ah... I guess we can't do it because we're not in a realm world and so
> > > > > the early checks in __set_memory_enc_dec() would return early and turn
> > > > > it into a no-op.
> > > > >
> > > > > How about if I extract a common helper and provide set_memory_p() and
> > > > > set_memory_np() in terms of those. Those are available on x86 and
> > > > > PowerPC as well, so fairly standard. I suppose at that point we're
> > > > > closer to set_memory_valid().
> > > >
> > > > Why not just call set_direct_map_invalid_noflush() +
> > > > flush_tlb_kernel_range() for each page? We already have APIs for this.
> > >
> > > Having a "standard" helper with a fixed and documented purposed seemed
> > > like a preferable approach for this particular case. We also may want to
> > > make the driver that uses this buildable as a module, in which case we'd
> > > need to export these rather low-level APIs. And then there's also the
> > > fact that we typically call this on a rather large region of memory
> > > (usually something like 512 MiB), so doing it page-by-page is rather
> > > suboptimal.
> > >
> > > > The big challenge I see with any linear map manipulation, however, is
> > > > that it will rely on can_set_direct_map() which likely means you need to
> > > > give up some performance and/or security to make this work. Does memory
> > > > become inaccesible dynamically at runtime? If not, the best bet would
> > > > be to describe it as a carveout in the DT and mark it as "no-map" so
> > > > we avoid mapping it in the first place.
> > >
> > > VPR exists in two modes: static and resizable. For static VPR we do
> > > exactly that: describe it as carveout in DT with no-map and deal with it
> > > accordingly in the driver. Resizable VPR is for device that have small
> > > amounts of RAM. Content-protected video playback will in the worst case
> > > consume around 1.8 GiB of RAM, so we want to be able to reuse for other
> > > purposes when VPR is unused on those devices. In that case, the memory
> > > is also described as a reserved-memory region in DT, but it is marked as
> > > reusable so that it can be managed by CMA.
> > >
> > > The resize operation is fairly slow to begin with because we need to
> > > stall the GPU and put it into reset before the operation, then take it
> > > out of reset and resume it afterwards.
> > >
> > > What kind of performance impact do you expect?
> >
> > You'll need to measure it, but we've seen reports of double-digit
> > percentage regressions in performance and power. As I said, the problem
> > is that you need to split the linear map to 4k page at runtime to unmap
> > the dynamic carveout, but that isn't something that can be done on most
> > CPUs. Therefore you end up having to use page-granular mappings for the
> > entire thing, similarly to how 'rodata_full' drives can_set_direct_map()
> > and the perf/power hit affects everything.
> >
> > It's hard to know what to suggest... I wonder if any of the memory
> > hotplug logic could help here?
>
> I've read up on memory hotplug a bit and it sounds like it could fit
> this really nicely. Given that we only use CMA (along with the extra
> patches to it) to make sure that any buffers are reclaimed for VPR use,
> we should be able to get rid of the CMA usage altogether and replace it
> with online_pages() and offline_pages() instead. Rather than using a
> fixed set of CMA areas like we currently do, each "chunk" in the VPR
> driver could represent a memory block instead (which looks like it will
> be 128 MiB for 4 KiB pages and 512 MiB for 64 KiB pages). We currently
> use 512 MiB as the chunk size, so it should be relatively similar and
> easy to adjust.
>
> One issue that we would absolutely need this memory to be ZONE_MOVABLE
> from the start. Using no-map in DT and then online_pages() probably will
> not work because there's no struct page for the memory. So we're left
> with keeping the memory onlined by default, in which case we'd need some
> way for DT to instruct the memory to be put into ZONE_MOVABLE always.
>
> There's a "hotpluggable" property for "memory" nodes, maybe that can be
> extended to apply to reserved-memory nodes as well?
I haven't been having much success with this. memblock_mark_hotplug()
doesn't have much of an effect because the kernel clears this flag
automatically at some point, so by the time the movable zone is created
there's no memory left that's marked hotpluggable. I don't know if it's
a good idea to modify the code to keep the flag.
Another thing I briefly tried was to use add_memory_driver_managed()
together with the no-map flag in an attempt to get the memory explicitly
added as movable, but that fails because __request_resource() notices
that the reserved memory is actually part of the system RAM that was
registered earlier.
I think in order for this to work the bindings would probably need to
change, such that reserved-memory nodes aren't used but it's described
using the memory nodes instead. That way a piece of system RAM could be
carved out and added by the VPR driver. I don't know if the kernel would
like this kind of splicing of the system RAM, though.
It's all very close to what I need for this, but doesn't quite fit. Any
ideas which of the options is best? Right now it sounds like finding a
way to make this region explicitly ZONE_MOVABLE would be the best. That
should allow offline_pages() and online_pages() to be used, which seems
like the cleanest approach.
Thierry
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply
* Re: [PATCH 1/3] rv/reactors: fix lockdep "Invalid wait context" in rv_react()
From: Wen Yang @ 2026-07-09 16:37 UTC (permalink / raw)
To: Thomas Weißschuh, Gabriele Monaco
Cc: Nam Cao, linux-trace-kernel, linux-kernel
In-Reply-To: <20260708174123-e5f98837-3d81-43ca-8ede-bb5f09e8ffba@linutronix.de>
On 7/8/26 23:47, Thomas Weißschuh wrote:
> On Mon, Jul 06, 2026 at 04:02:08PM +0200, Gabriele Monaco wrote:
>> On Tue, 2026-06-23 at 11:38 +0200, Thomas Weißschuh wrote:
>>> This now allows reactors to take (raw) spinlocks. The original idea was
>>> to not allow that as a reactor can be called from LD_WAIT_FREE context.
>>> So I am not sure this is the right fix. Not that I have a better one
>>> available right now.
>>
>> As far as I understand it, LD_WAIT_FREE is fairly impossible to apply on
>> preemptible code (here we see it hit by an interrupt).
>>
>> Since we kind of have to allow raw spinlock to avoid this (even if we don't take
>> them explicitly), why wouldn't a reactor ever be allowed to take raw spinlocks?
>>
>> Technically it wouldn't be wrong to take locks from RV monitors, although most
>> monitors don't do it explicitly.
>> If we ever happen to take the wrong lock explicitly from a reactor triggered by
>> a nasty event (e.g. sched_switch), I believe lockdep would still be complaining
>> down that path, so we probably don't need to be too strict in rv_react().
>>
>> Obviously we don't want to disable interrutps for LD_WAIT_FREE to hold either.
>>
>> Am I missing something?
>
> No, I was just very confused.
> Let's go ahead with this.
>
>
Hi,
How about a context-sensitive approach, eg:
NMI/hardirq (interrupts masked, scheduler cannot run):
Keep LD_WAIT_FREE. The false positive cannot arise in this path,
and the original constraint against raw spinlocks is preserved where
it is meaningful.
task/softirq/PREEMPT_RT irq thread (preemptible):
Raise to LD_WAIT_SPIN. Raw spinlocks become permitted — as Gabriele
note, this is a necessary consequence of any fix in this path.
like this:
+ static DEFINE_WAIT_OVERRIDE_MAP(rv_react_map, LD_WAIT_SPIN);
+ static DEFINE_WAIT_OVERRIDE_MAP(rv_react_map_atomic, LD_WAIT_FREE);
+ struct lockdep_map *map;
...
+ map = (in_nmi() || in_hardirq()) ? &rv_react_map_atomic :
&rv_react_map;
- lock_map_acquire_try(&rv_react_map);
+ lock_map_acquire_try(map);
...
monitor->react(msg, args);
- lock_map_release(&rv_react_map);
+ lock_map_release(map);
--
Best wishes,
Wen
^ permalink raw reply
* Re: [PATCH 3/3] rv/reactors: add KUnit tests for reactor_panic
From: Wen Yang @ 2026-07-09 16:46 UTC (permalink / raw)
To: Gabriele Monaco; +Cc: Nam Cao, linux-trace-kernel, linux-kernel
In-Reply-To: <c8c7568dd9293b0a718584c1aa193692c128d77d.camel@redhat.com>
On 7/6/26 23:00, Gabriele Monaco wrote:
> On Tue, 2026-06-16 at 00:44 +0800, wen.yang@linux.dev wrote:
>> +/*
>> + * Test 2: panic notifier chain is reachable.
>> + *
>> + * vpanic() calls atomic_notifier_call_chain(&panic_notifier_list, ...).
>> + * Drive the chain directly to verify panic notifiers receive the
>> notification —
>> + * the observable side-effect of reactor_panic without halting the system.
>> + */
>> +static void test_panic_notifier_called(struct kunit *test)
>> +{
>> + atomic_notifier_chain_register(&panic_notifier_list, &mock_panic_nb);
>> + atomic_notifier_call_chain(&panic_notifier_list, 0,
>> + "panic violation message");
>> + atomic_notifier_chain_unregister(&panic_notifier_list,
>> &mock_panic_nb);
>
> I just realised this isn't even testing the reactor, it's testing the
> notifier_chain thing, I don't think we really need this here or am I missing
> something?
>
Thanks,
Since rv_panic_reaction calls vpanic() which is __noreturn, direct
testing is not feasible in KUnit.
A preparatory v2 drops reactor_printk_kunit.c and reactor_panic_kunit.c
entirely, replacing them with a single rv_reactors_kunit.c containing
two suites:
rv_reactor_registration: register/unregister lifecycle, duplicate
rejection (-EINVAL), name-too-long rejection, and safe unregister
of a never-registered reactor.
rv_react_dispatch: null-callback guard, callback invocation check,
and the mdelay lockdep stress test.
v2 also adds EXPORT_SYMBOL_GPL for rv_react(), rv_register_reactor(),
and rv_unregister_reactor(), and the Kconfig entry is tristate.
Additional fix: rv_unregister_reactor()
Testing exposed a real bug: rv_unregister_reactor() called list_del()
unconditionally. On a never-registered reactor the list_head is
zero-initialised, so list_del() dereferences NULL->prev and crashes.
v2 adds a patch that iterates rv_reactors_list first and only calls
list_del() when the reactor is found. test_unregister_nonexistent
documents and guards this behaviour.
--
Best wishes,
Wen
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox