Linux Trace Kernel
 help / color / mirror / Atom feed
* Re: [PATCH v3 09/17] rv: Add KUnit tests for some DA/HA monitors
From: Nam Cao @ 2026-07-07  6:52 UTC (permalink / raw)
  To: Gabriele Monaco, linux-trace-kernel, linux-kernel, Steven Rostedt,
	Gabriele Monaco, Masami Hiramatsu
  Cc: Thomas Weissschuh, Tomas Glozar, John Kacur, Wen Yang
In-Reply-To: <20260625121440.116317-10-gmonaco@redhat.com>

Gabriele Monaco <gmonaco@redhat.com> writes:
> + * Automatically generated by rvgen kunit.

I was slightly confused by this, as I wasn't aware that rvgen can
generate this.

The patch adding generation support into rvgen should be before
this patch. But oh well, no big deal.

Reviewed-by: Nam Cao <namcao@linutronix.de>

^ permalink raw reply

* Re: [PATCH v3 11/17] rv: Prevent unintentional tracepoints during KUnit tests
From: Nam Cao @ 2026-07-07  7:00 UTC (permalink / raw)
  To: Gabriele Monaco, linux-trace-kernel, linux-kernel, Steven Rostedt,
	Gabriele Monaco, Masami Hiramatsu
  Cc: Thomas Weissschuh, Tomas Glozar, John Kacur, Wen Yang
In-Reply-To: <20260625121440.116317-12-gmonaco@redhat.com>

Gabriele Monaco <gmonaco@redhat.com> writes:
> Monitor initialisation also called during KUnit tests may register some
> tracepoints, this can lead to issues since we don't expect real monitor
> events running during KUnit tests.
>
> Prevent tracepoint registration if an RV KUnit test is running.
>
> Reviewed-by: Nam Cao <namcao@linutronix.de>
> Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>

Somehow I have no recollection of seeing this patch.

But since we already hold rv_interface_lock during the test, is this
really necessary?

Nam

^ permalink raw reply

* Re: [PATCH v3 12/17] rv: Add KUnit tests for some LTL monitors
From: Nam Cao @ 2026-07-07  7:04 UTC (permalink / raw)
  To: Gabriele Monaco, linux-trace-kernel, linux-kernel, Steven Rostedt,
	Gabriele Monaco, Masami Hiramatsu
  Cc: Thomas Weissschuh, Tomas Glozar, John Kacur, Wen Yang
In-Reply-To: <20260625121440.116317-13-gmonaco@redhat.com>

Gabriele Monaco <gmonaco@redhat.com> writes:
> Validate the functionality of LTL monitors by injecting events in a
> controlled environment (KUnit) and expecting reactions, just like it is
> done in DA monitors.
>
> Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>

Reviewed-by: Nam Cao <namcao@linutronix.de>

^ permalink raw reply

* Re: [PATCH v3 11/17] rv: Prevent unintentional tracepoints during KUnit tests
From: Gabriele Monaco @ 2026-07-07  7:23 UTC (permalink / raw)
  To: Nam Cao, linux-trace-kernel, linux-kernel
  Cc: Thomas Weissschuh, Tomas Glozar, John Kacur, Wen Yang,
	Steven Rostedt, Masami Hiramatsu
In-Reply-To: <878q7n2six.fsf@yellow.woof>

On Tue, 2026-07-07 at 09:00 +0200, Nam Cao wrote:
> Gabriele Monaco <gmonaco@redhat.com> writes:
> > Monitor initialisation also called during KUnit tests may register some
> > tracepoints, this can lead to issues since we don't expect real monitor
> > events running during KUnit tests.
> > 
> > Prevent tracepoint registration if an RV KUnit test is running.
> > 
> > Reviewed-by: Nam Cao <namcao@linutronix.de>
> > Signed-off-by: Gabriele Monaco <gmonaco@redhat.com>
> 
> Somehow I have no recollection of seeing this patch.

Well, I'm fairly sure you reviewed it ;)

> But since we already hold rv_interface_lock during the test, is this
> really necessary?

This is for things like ltl_monitor_init() that attaches the newtask probe.
The function is also doing a few other things we may not want to do, to be fair,
but calling the monitor_init() function as-is was the easiest solution I could
think of. Also ha_monitor_init() may attach a probe.

I suppose I could also do some more targeted initialisation/destruction, in fact
right now, the LTL initialisation does a bunch of stuff tests don't need and
doesn't do what they do need (initialise the dummy tasks, which aren't part of
the task list).

I should probably rethink this a little.

Thanks,
Gabriele


^ permalink raw reply

* Re: [PATCH net-next] net/tcp: Add explicit tracepoint for tcp_syn_ack_timeout()
From: Eric Dumazet @ 2026-07-07  7:52 UTC (permalink / raw)
  To: Emil Tsalapatis
  Cc: netdev, linux-trace-kernel, ncardwell, kuniyu, rostedt, mhiramat,
	davem, kuba, pabeni
In-Reply-To: <20260707010151.43976-1-emil@etsalapatis.com>

On Mon, Jul 6, 2026 at 6:01 PM Emil Tsalapatis <emil@etsalapatis.com> wrote:
>
> Clang can inline the tcp_syn_ack_timeout() function during compilation,
> making it impossible to use kprobes for tracing without preventing
> inlining. Add an explicit tracepoint to it instead.

So much copy/pasting for a very small issue :/

>
> Signed-off-by: Emil Tsalapatis <emil@etsalapatis.com>
> ---
>  include/trace/events/tcp.h | 72 ++++++++++++++++++++++++++++++++++++++
>  net/ipv4/tcp_timer.c       |  3 ++
>  2 files changed, 75 insertions(+)
>

tcp_syn_ack_timeout() is hardly a fast path, so you can instead:

diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 322db13333c7..ab2c3de19e46 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -748,7 +748,7 @@ static void tcp_write_timer(struct timer_list *t)
        sock_put(sk);
 }

-void tcp_syn_ack_timeout(const struct request_sock *req)
+noinline_for_tracing void tcp_syn_ack_timeout(const struct request_sock *req)
 {
        struct net *net = read_pnet(&inet_rsk(req)->ireq_net);

^ permalink raw reply related

* Re: [PATCH v3 06/11] mm/cma: Allow dynamically creating CMA areas
From: Marek Szyprowski @ 2026-07-07 10:02 UTC (permalink / raw)
  To: Thierry Reding, 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, David Hildenbrand, 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
  Cc: 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: <20260701-tegra-vpr-v3-6-d80f7b871bb4@nvidia.com>

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.


I would add a comment about that in the cma_create() and ensure that its
future callers explicitly depend on !ARM_32BIT.


> The static array of CMA areas cannot be replaced by dynamically created
> areas because for many of them, allocation must not fail and some cases
> may need to initialize them before the slab allocator is even available.
> To account for this, keep these "early" areas in a separate list and
> track the dynamic areas in a separate list.
>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
> ---
> Changes in v3:
> - rebase on top of recent linux-next, update kernel/dma/contiguous.c
> - use kzalloc_obj() instead of kzalloc() with sizeof()
>
> Changes in v2:
> - rename fixed number of CMA areas to reflect their main use
> - account for pages in dynamically allocated regions
> ---
> arch/arm/mm/dma-mapping.c | 2 +-
> arch/s390/mm/init.c | 2 +-
> include/linux/cma.h | 8 +-
> kernel/dma/contiguous.c | 2 +-
> mm/cma.c | 187 +++++++++++++++++++++++++++++++++++++---------
> mm/cma.h | 5 +-
> 6 files changed, 165 insertions(+), 41 deletions(-)
>
> diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
> index f9bc53b60f99..934952ab2102 100644
> --- a/arch/arm/mm/dma-mapping.c
> +++ b/arch/arm/mm/dma-mapping.c
> @@ -254,7 +254,7 @@ struct dma_contig_early_reserve {
> unsigned long size;
> };
> -static struct dma_contig_early_reserve dma_mmu_remap[MAX_CMA_AREAS] __initdata;
> +static struct dma_contig_early_reserve dma_mmu_remap[MAX_EARLY_CMA_AREAS] __initdata;
> static int dma_mmu_remap_num __initdata;
> diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
> index f07168a0d3dd..f8f78f1434ea 100644
> --- a/arch/s390/mm/init.c
> +++ b/arch/s390/mm/init.c
> @@ -241,7 +241,7 @@ static int s390_cma_mem_notifier(struct notifier_block *nb,
> mem_data.start = arg->start_pfn << PAGE_SHIFT;
> mem_data.end = mem_data.start + (arg->nr_pages << PAGE_SHIFT);
> if (action == MEM_GOING_OFFLINE)
> - rc = cma_for_each_area(s390_cma_check_range, &mem_data);
> + rc = cma_for_each_early_area(s390_cma_check_range, &mem_data);
> return notifier_from_errno(rc);
> }
> diff --git a/include/linux/cma.h b/include/linux/cma.h
> index 8555d38a97b1..fb7a4923c3ba 100644
> --- a/include/linux/cma.h
> +++ b/include/linux/cma.h
> @@ -7,7 +7,7 @@
> #include <linux/numa.h>
> #ifdef CONFIG_CMA_AREAS
> -#define MAX_CMA_AREAS CONFIG_CMA_AREAS
> +#define MAX_EARLY_CMA_AREAS CONFIG_CMA_AREAS
> #endif
> #define CMA_MAX_NAME 64
> @@ -57,8 +57,14 @@ struct page *cma_alloc_frozen_compound(struct cma *cma, unsigned int order);
> bool cma_release_frozen(struct cma *cma, const struct page *pages,
> unsigned long count);
> +extern int cma_for_each_early_area(int (*it)(struct cma *cma, void *data), void *data);
> extern int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data);
> extern bool cma_intersects(struct cma *cma, unsigned long start, unsigned long end);
> extern void cma_reserve_pages_on_error(struct cma *cma);
> +
> +extern struct cma *cma_create(phys_addr_t base, phys_addr_t size,
> + unsigned int order_per_bit, const char *name);
> +extern void cma_free(struct cma *cma);
> +
> #endif
> diff --git a/kernel/dma/contiguous.c b/kernel/dma/contiguous.c
> index f754079a287d..7975551f69b3 100644
> --- a/kernel/dma/contiguous.c
> +++ b/kernel/dma/contiguous.c
> @@ -52,7 +52,7 @@
> #define CMA_SIZE_MBYTES 0
> #endif
> -static struct cma *dma_contiguous_areas[MAX_CMA_AREAS];
> +static struct cma *dma_contiguous_areas[MAX_EARLY_CMA_AREAS];
> static unsigned int dma_contiguous_areas_num;
> static int dma_contiguous_insert_area(struct cma *cma)
> diff --git a/mm/cma.c b/mm/cma.c
> index a13ce4999b39..f989e2e98594 100644
> --- a/mm/cma.c
> +++ b/mm/cma.c
> @@ -34,7 +34,12 @@
> #include "internal.h"
> #include "cma.h"
> -struct cma cma_areas[MAX_CMA_AREAS];
> +static DEFINE_MUTEX(cma_lock);
> +
> +struct cma cma_early_areas[MAX_EARLY_CMA_AREAS];
> +unsigned int cma_early_area_count;
> +
> +static LIST_HEAD(cma_areas);
> unsigned int cma_area_count;
> phys_addr_t cma_get_base(const struct cma *cma)
> @@ -198,7 +203,6 @@ static void __init cma_activate_area(struct cma *cma)
> free_reserved_page(pfn_to_page(pfn));
> }
> }
> - totalcma_pages -= cma->count;
> cma->available_count = cma->count = 0;
> pr_err("CMA area %s could not be activated\n", cma->name);
> }
> @@ -207,8 +211,8 @@ static int __init cma_init_reserved_areas(void)
> {
> int i;
> - for (i = 0; i < cma_area_count; i++)
> - cma_activate_area(&cma_areas[i]);
> + for (i = 0; i < cma_early_area_count; i++)
> + cma_activate_area(&cma_early_areas[i]);
> return 0;
> }
> @@ -219,41 +223,77 @@ void __init cma_reserve_pages_on_error(struct cma *cma)
> set_bit(CMA_RESERVE_PAGES_ON_ERROR, &cma->flags);
> }
> +static void __init cma_init_area(struct cma *cma, const char *name,
> + phys_addr_t size, unsigned int order_per_bit)
> +{
> + if (name)
> + strscpy(cma->name, name);
> + else
> + snprintf(cma->name, CMA_MAX_NAME, "cma%d\n", cma_area_count);
> +
> + cma->available_count = cma->count = size >> PAGE_SHIFT;
> + cma->order_per_bit = order_per_bit;
> +
> + INIT_LIST_HEAD(&cma->node);
> +}
> +
> static int __init cma_new_area(const char *name, phys_addr_t size,
> unsigned int order_per_bit,
> struct cma **res_cma)
> {
> struct cma *cma;
> - if (cma_area_count == ARRAY_SIZE(cma_areas)) {
> + if (cma_early_area_count == ARRAY_SIZE(cma_early_areas)) {
> pr_err("Not enough slots for CMA reserved regions!\n");
> return -ENOSPC;
> }
> + mutex_lock(&cma_lock);
> +
> /*
> * Each reserved area must be initialised later, when more kernel
> * subsystems (like slab allocator) are available.
> */
> - cma = &cma_areas[cma_area_count];
> - cma_area_count++;
> + cma = &cma_early_areas[cma_early_area_count];
> + cma_early_area_count++;
> - if (name)
> - strscpy(cma->name, name);
> - else
> - snprintf(cma->name, CMA_MAX_NAME, "cma%d\n", cma_area_count);
> + cma_init_area(cma, name, size, order_per_bit);
> - cma->available_count = cma->count = size >> PAGE_SHIFT;
> - cma->order_per_bit = order_per_bit;
> - *res_cma = cma;
> totalcma_pages += cma->count;
> + *res_cma = cma;
> +
> + mutex_unlock(&cma_lock);
> return 0;
> }
> static void __init cma_drop_area(struct cma *cma)
> {
> + mutex_lock(&cma_lock);
> totalcma_pages -= cma->count;
> - cma_area_count--;
> + cma_early_area_count--;
> + mutex_unlock(&cma_lock);
> +}
> +
> +static int __init cma_check_memory(phys_addr_t base, phys_addr_t size)
> +{
> + if (!size || !memblock_is_region_reserved(base, size))
> + return -EINVAL;
> +
> + /*
> + * CMA uses CMA_MIN_ALIGNMENT_BYTES as alignment requirement which
> + * needs pageblock_order to be initialized. Let's enforce it.
> + */
> + if (!pageblock_order) {
> + pr_err("pageblock_order not yet initialized. Called during early boot?\n");
> + return -EINVAL;
> + }
> +
> + /* ensure minimal alignment required by mm core */
> + if (!IS_ALIGNED(base | size, CMA_MIN_ALIGNMENT_BYTES))
> + return -EINVAL;
> +
> + return 0;
> }
> /**
> @@ -276,22 +316,9 @@ int __init cma_init_reserved_mem(phys_addr_t base, phys_addr_t size,
> struct cma *cma;
> int ret;
> - /* Sanity checks */
> - if (!size || !memblock_is_region_reserved(base, size))
> - return -EINVAL;
> -
> - /*
> - * CMA uses CMA_MIN_ALIGNMENT_BYTES as alignment requirement which
> - * needs pageblock_order to be initialized. Let's enforce it.
> - */
> - if (!pageblock_order) {
> - pr_err("pageblock_order not yet initialized. Called during early boot?\n");
> - return -EINVAL;
> - }
> -
> - /* ensure minimal alignment required by mm core */
> - if (!IS_ALIGNED(base | size, CMA_MIN_ALIGNMENT_BYTES))
> - return -EINVAL;
> + ret = cma_check_memory(base, size);
> + if (ret < 0)
> + return ret;
> ret = cma_new_area(name, size, order_per_bit, &cma);
> if (ret != 0)
> @@ -444,7 +471,7 @@ static int __init __cma_declare_contiguous_nid(phys_addr_t *basep,
> pr_debug("%s(size %pa, base %pa, limit %pa alignment %pa)\n",
> __func__, &size, &base, &limit, &alignment);
> - if (cma_area_count == ARRAY_SIZE(cma_areas)) {
> + if (cma_early_area_count == ARRAY_SIZE(cma_early_areas)) {
> pr_err("Not enough slots for CMA reserved regions!\n");
> return -ENOSPC;
> }
> @@ -1051,12 +1078,12 @@ bool cma_release_frozen(struct cma *cma, const struct page *pages,
> return true;
> }
> -int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data)
> +int cma_for_each_early_area(int (*it)(struct cma *cma, void *data), void *data)
> {
> int i;
> - for (i = 0; i < cma_area_count; i++) {
> - int ret = it(&cma_areas[i], data);
> + for (i = 0; i < cma_early_area_count; i++) {
> + int ret = it(&cma_early_areas[i], data);
> if (ret)
> return ret;
> @@ -1065,6 +1092,25 @@ int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data)
> return 0;
> }
> +int cma_for_each_area(int (*it)(struct cma *cma, void *data), void *data)
> +{
> + struct cma *cma;
> +
> + mutex_lock(&cma_lock);
> +
> + list_for_each_entry(cma, &cma_areas, node) {
> + int ret = it(cma, data);
> +
> + if (ret) {
> + mutex_unlock(&cma_lock);
> + return ret;
> + }
> + }
> +
> + mutex_unlock(&cma_lock);
> + return 0;
> +}
> +
> bool cma_intersects(struct cma *cma, unsigned long start, unsigned long end)
> {
> int r;
> @@ -1147,3 +1193,74 @@ void __init *cma_reserve_early(struct cma *cma, unsigned long size)
> return ret;
> }
> +
> +struct cma *__init cma_create(phys_addr_t base, phys_addr_t size,
> + unsigned int order_per_bit, const char *name)
> +{
> + struct cma *cma;
> + int ret;
> +
> + ret = cma_check_memory(base, size);
> + if (ret < 0)
> + return ERR_PTR(ret);
> +
> + cma = kzalloc_obj(*cma, GFP_KERNEL);
> + if (!cma)
> + return ERR_PTR(-ENOMEM);
> +
> + cma_init_area(cma, name, size, order_per_bit);
> + cma->ranges[0].base_pfn = PFN_DOWN(base);
> + cma->ranges[0].early_pfn = PFN_DOWN(base);
> + cma->ranges[0].count = cma->count;
> + cma->nranges = 1;
> +
> + cma_activate_area(cma);
> +
> + mutex_lock(&cma_lock);
> + list_add_tail(&cma->node, &cma_areas);
> + totalcma_pages += cma->count;
> + cma_area_count++;
> + mutex_unlock(&cma_lock);
> +
> + return cma;
> +}
> +
> +void cma_free(struct cma *cma)
> +{
> + unsigned int i;
> +
> + /*
> + * Safety check to prevent a CMA with active allocations from being
> + * released.
> + */
> + for (i = 0; i < cma->nranges; i++) {
> + unsigned long nbits = cma_bitmap_maxno(cma, &cma->ranges[i]);
> +
> + if (!bitmap_empty(cma->ranges[i].bitmap, nbits)) {
> + WARN(1, "%s: range %u not empty\n", cma->name, i);
> + return;
> + }
> + }
> +
> + /* free reserved pages and the bitmap */
> + for (i = 0; i < cma->nranges; i++) {
> + struct cma_memrange *cmr = &cma->ranges[i];
> + unsigned long end_pfn, pfn;
> +
> + end_pfn = cmr->base_pfn + cmr->count;
> + for (pfn = cmr->base_pfn; pfn < end_pfn; pfn++)
> + free_reserved_page(pfn_to_page(pfn));
> +
> + bitmap_free(cmr->bitmap);
> + }
> +
> + mutex_destroy(&cma->alloc_mutex);
> +
> + mutex_lock(&cma_lock);
> + totalcma_pages -= cma->count;
> + list_del(&cma->node);
> + cma_area_count--;
> + mutex_unlock(&cma_lock);
> +
> + kfree(cma);
> +}
> diff --git a/mm/cma.h b/mm/cma.h
> index c70180c36559..ae4db9819e38 100644
> --- a/mm/cma.h
> +++ b/mm/cma.h
> @@ -41,6 +41,7 @@ struct cma {
> unsigned long available_count;
> unsigned int order_per_bit; /* Order of pages represented by one bit */
> spinlock_t lock;
> + struct list_head node;
> struct mutex alloc_mutex;
> #ifdef CONFIG_CMA_DEBUGFS
> struct hlist_head mem_head;
> @@ -71,8 +72,8 @@ enum cma_flags {
> CMA_ACTIVATED,
> };
> -extern struct cma cma_areas[MAX_CMA_AREAS];
> -extern unsigned int cma_area_count;
> +extern struct cma cma_early_areas[MAX_EARLY_CMA_AREAS];
> +extern unsigned int cma_early_area_count;
> static inline unsigned long cma_bitmap_maxno(struct cma *cma,
> struct cma_memrange *cmr)
>
Best regards

-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland


^ permalink raw reply

* Re: [PATCH 17/30] mm: prefer vma_[start,end]_pgoff() to vma->vm_pgoff in kernel/
From: Marek Szyprowski @ 2026-07-07 10:20 UTC (permalink / raw)
  To: Lorenzo Stoakes, Andrew Morton
  Cc: 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
In-Reply-To: <ea87349d63205bf4c26ea79854f179a9bf8cfb0b.1782735110.git.ljs@kernel.org>

On 29.06.2026 14:23, 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>
> ---
>  kernel/dma/coherent.c      |  7 ++++---
>  kernel/dma/direct.c        |  6 ++++--
>  kernel/dma/mapping.c       |  8 +++++---
>  kernel/dma/ops_helpers.c   |  4 ++--


Acked-by: Marek Szyprowski <m.szyprowski@samsung.com> # for kernel/dma


>  kernel/events/core.c       | 20 +++++++++++---------
>  kernel/events/uprobes.c    | 11 +++++++----
>  kernel/kcov.c              |  2 +-
>  kernel/trace/ring_buffer.c |  3 ++-
>  8 files changed, 36 insertions(+), 25 deletions(-)
>
> diff --git a/kernel/dma/coherent.c b/kernel/dma/coherent.c
> index bcdc0f76d2e8..2d3195eb7e83 100644
> --- a/kernel/dma/coherent.c
> +++ b/kernel/dma/coherent.c
> @@ -236,14 +236,15 @@ static int __dma_mmap_from_coherent(struct dma_coherent_mem *mem,
>  {
>  	if (mem && vaddr >= mem->virt_base && vaddr + size <=
>  		   (mem->virt_base + ((dma_addr_t)mem->size << PAGE_SHIFT))) {
> -		unsigned long off = vma->vm_pgoff;
> +		const pgoff_t pgoff_start = vma_start_pgoff(vma);
> +		const pgoff_t pgoff_end = vma_end_pgoff(vma);
>  		int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
>  		unsigned long user_count = vma_pages(vma);
>  		int count = PAGE_ALIGN(size) >> PAGE_SHIFT;
>  
>  		*ret = -ENXIO;
> -		if (off < count && user_count <= count - off) {
> -			unsigned long pfn = mem->pfn_base + start + off;
> +		if (pgoff_start < count && pgoff_end <= count) {
> +			unsigned long pfn = mem->pfn_base + start + pgoff_start;
>  			*ret = remap_pfn_range(vma, vma->vm_start, pfn,
>  					       user_count << PAGE_SHIFT,
>  					       vma->vm_page_prot);
> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
> index 4391b797d4db..436310d6e4a2 100644
> --- a/kernel/dma/direct.c
> +++ b/kernel/dma/direct.c
> @@ -534,6 +534,8 @@ int dma_direct_mmap(struct device *dev, struct vm_area_struct *vma,
>  	unsigned long user_count = vma_pages(vma);
>  	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
>  	unsigned long pfn = PHYS_PFN(dma_to_phys(dev, dma_addr));
> +	const pgoff_t pgoff_start = vma_start_pgoff(vma);
> +	const pgoff_t pgoff_end = vma_end_pgoff(vma);
>  	int ret = -ENXIO;
>  
>  	vma->vm_page_prot = dma_pgprot(dev, vma->vm_page_prot, attrs);
> @@ -545,9 +547,9 @@ int dma_direct_mmap(struct device *dev, struct vm_area_struct *vma,
>  	if (dma_mmap_from_global_coherent(vma, cpu_addr, size, &ret))
>  		return ret;
>  
> -	if (vma->vm_pgoff >= count || user_count > count - vma->vm_pgoff)
> +	if (pgoff_start >= count || pgoff_end > count)
>  		return -ENXIO;
> -	return remap_pfn_range(vma, vma->vm_start, pfn + vma->vm_pgoff,
> +	return remap_pfn_range(vma, vma->vm_start, pfn + pgoff_start,
>  			user_count << PAGE_SHIFT, vma->vm_page_prot);
>  }
>  
> diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c
> index 4fe04669e5e6..c986639044e9 100644
> --- a/kernel/dma/mapping.c
> +++ b/kernel/dma/mapping.c
> @@ -761,12 +761,14 @@ EXPORT_SYMBOL_GPL(dma_free_pages);
>  int dma_mmap_pages(struct device *dev, struct vm_area_struct *vma,
>  		size_t size, struct page *page)
>  {
> -	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
> +	const pgoff_t pgoff_start = vma_start_pgoff(vma);
> +	const pgoff_t pgoff_end = vma_end_pgoff(vma);
> +	const unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
>  
> -	if (vma->vm_pgoff >= count || vma_pages(vma) > count - vma->vm_pgoff)
> +	if (pgoff_start >= count || pgoff_end > count)
>  		return -ENXIO;
>  	return remap_pfn_range(vma, vma->vm_start,
> -			       page_to_pfn(page) + vma->vm_pgoff,
> +			       page_to_pfn(page) + pgoff_start,
>  			       vma_pages(vma) << PAGE_SHIFT, vma->vm_page_prot);
>  }
>  EXPORT_SYMBOL_GPL(dma_mmap_pages);
> diff --git a/kernel/dma/ops_helpers.c b/kernel/dma/ops_helpers.c
> index 20caf9cabf69..6b5f9208d31c 100644
> --- a/kernel/dma/ops_helpers.c
> +++ b/kernel/dma/ops_helpers.c
> @@ -39,7 +39,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
>  #ifdef CONFIG_MMU
>  	unsigned long user_count = vma_pages(vma);
>  	unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT;
> -	unsigned long off = vma->vm_pgoff;
> +	unsigned long off = vma_start_pgoff(vma);
>  	struct page *page = dma_common_vaddr_to_page(cpu_addr);
>  	int ret = -ENXIO;
>  
> @@ -52,7 +52,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
>  		return -ENXIO;
>  
>  	return remap_pfn_range(vma, vma->vm_start,
> -			page_to_pfn(page) + vma->vm_pgoff,
> +			page_to_pfn(page) + vma_start_pgoff(vma),
>  			user_count << PAGE_SHIFT, vma->vm_page_prot);
>  #else
>  	return -ENXIO;
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index 954c36e28101..d6d2d557ccb8 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -6998,7 +6998,7 @@ static void perf_mmap_open(struct vm_area_struct *vma)
>  	refcount_inc(&event->mmap_count);
>  	refcount_inc(&event->rb->mmap_count);
>  
> -	if (vma->vm_pgoff)
> +	if (vma_start_pgoff(vma))
>  		refcount_inc(&event->rb->aux_mmap_count);
>  
>  	if (mapped)
> @@ -7032,7 +7032,7 @@ static void perf_mmap_close(struct vm_area_struct *vma)
>  	 * The AUX buffer is strictly a sub-buffer, serialize using aux_mutex
>  	 * to avoid complications.
>  	 */
> -	if (rb_has_aux(rb) && vma->vm_pgoff == rb->aux_pgoff &&
> +	if (rb_has_aux(rb) && vma_start_pgoff(vma) == rb->aux_pgoff &&
>  	    refcount_dec_and_mutex_lock(&rb->aux_mmap_count, &rb->aux_mutex)) {
>  		/*
>  		 * Stop all AUX events that are writing to this buffer,
> @@ -7190,7 +7190,8 @@ static int map_range(struct perf_buffer *rb, struct vm_area_struct *vma)
>  	 */
>  	for (pagenum = 0; pagenum < nr_pages; pagenum++) {
>  		unsigned long va = vma->vm_start + PAGE_SIZE * pagenum;
> -		struct page *page = perf_mmap_to_page(rb, vma->vm_pgoff + pagenum);
> +		struct page *page = perf_mmap_to_page(rb,
> +				vma_start_pgoff(vma) + pagenum);
>  
>  		if (page == NULL) {
>  			err = -EINVAL;
> @@ -7348,6 +7349,7 @@ static int perf_mmap_aux(struct vm_area_struct *vma, struct perf_event *event,
>  	u64 aux_offset, aux_size;
>  	struct perf_buffer *rb;
>  	int ret, rb_flags = 0;
> +	const pgoff_t pgoff_start = vma_start_pgoff(vma);
>  
>  	rb = event->rb;
>  	if (!rb)
> @@ -7366,11 +7368,11 @@ static int perf_mmap_aux(struct vm_area_struct *vma, struct perf_event *event,
>  	if (aux_offset < perf_data_size(rb) + PAGE_SIZE)
>  		return -EINVAL;
>  
> -	if (aux_offset != vma->vm_pgoff << PAGE_SHIFT)
> +	if (aux_offset != pgoff_start << PAGE_SHIFT)
>  		return -EINVAL;
>  
>  	/* already mapped with a different offset */
> -	if (rb_has_aux(rb) && rb->aux_pgoff != vma->vm_pgoff)
> +	if (rb_has_aux(rb) && rb->aux_pgoff != pgoff_start)
>  		return -EINVAL;
>  
>  	if (aux_size != nr_pages * PAGE_SIZE)
> @@ -7400,7 +7402,7 @@ static int perf_mmap_aux(struct vm_area_struct *vma, struct perf_event *event,
>  		if (vma->vm_flags & VM_WRITE)
>  			rb_flags |= RING_BUFFER_WRITABLE;
>  
> -		ret = rb_alloc_aux(rb, event, vma->vm_pgoff, nr_pages,
> +		ret = rb_alloc_aux(rb, event, pgoff_start, nr_pages,
>  				   event->attr.aux_watermark, rb_flags);
>  		if (ret) {
>  			refcount_dec(&rb->mmap_count);
> @@ -7457,7 +7459,7 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma)
>  		if (event->state <= PERF_EVENT_STATE_REVOKED)
>  			return -ENODEV;
>  
> -		if (vma->vm_pgoff == 0)
> +		if (!vma_start_pgoff(vma))
>  			ret = perf_mmap_rb(vma, event, nr_pages);
>  		else
>  			ret = perf_mmap_aux(vma, event, nr_pages);
> @@ -9884,7 +9886,7 @@ static bool perf_addr_filter_vma_adjust(struct perf_addr_filter *filter,
>  					struct perf_addr_filter_range *fr)
>  {
>  	unsigned long vma_size = vma->vm_end - vma->vm_start;
> -	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
> +	unsigned long off = vma_start_pgoff(vma) << PAGE_SHIFT;
>  	struct file *file = vma->vm_file;
>  
>  	if (!perf_addr_filter_match(filter, file, off, vma_size))
> @@ -9974,7 +9976,7 @@ void perf_event_mmap(struct vm_area_struct *vma)
>  			/* .tid */
>  			.start  = vma->vm_start,
>  			.len    = vma->vm_end - vma->vm_start,
> -			.pgoff  = (u64)vma->vm_pgoff << PAGE_SHIFT,
> +			.pgoff  = (u64)vma_start_pgoff(vma) << PAGE_SHIFT,
>  		},
>  		/* .maj (attr_mmap2 only) */
>  		/* .min (attr_mmap2 only) */
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index f23cebacbc6d..244651380ca1 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -144,12 +144,14 @@ static bool valid_vma(struct vm_area_struct *vma, bool is_register)
>  
>  static unsigned long offset_to_vaddr(struct vm_area_struct *vma, loff_t offset)
>  {
> -	return vma->vm_start + offset - ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
> +	return vma->vm_start + offset -
> +		((loff_t)vma_start_pgoff(vma) << PAGE_SHIFT);
>  }
>  
>  static loff_t vaddr_to_offset(struct vm_area_struct *vma, unsigned long vaddr)
>  {
> -	return ((loff_t)vma->vm_pgoff << PAGE_SHIFT) + (vaddr - vma->vm_start);
> +	return ((loff_t)vma_start_pgoff(vma) << PAGE_SHIFT) +
> +		(vaddr - vma->vm_start);
>  }
>  
>  /**
> @@ -1482,7 +1484,7 @@ static int unapply_uprobe(struct uprobe *uprobe, struct mm_struct *mm)
>  		    file_inode(vma->vm_file) != uprobe->inode)
>  			continue;
>  
> -		offset = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
> +		offset = (loff_t)vma_start_pgoff(vma) << PAGE_SHIFT;
>  		if (uprobe->offset <  offset ||
>  		    uprobe->offset >= offset + vma->vm_end - vma->vm_start)
>  			continue;
> @@ -2453,7 +2455,8 @@ static struct uprobe *find_active_uprobe_speculative(unsigned long bp_vaddr)
>  	if (!vm_file)
>  		return NULL;
>  
> -	offset = (loff_t)(vma->vm_pgoff << PAGE_SHIFT) + (bp_vaddr - vma->vm_start);
> +	offset = (loff_t)(vma_start_pgoff(vma) << PAGE_SHIFT) +
> +		(bp_vaddr - vma->vm_start);
>  	uprobe = find_uprobe_rcu(vm_file->f_inode, offset);
>  	if (!uprobe)
>  		return NULL;
> diff --git a/kernel/kcov.c b/kernel/kcov.c
> index 1df373fb562b..b19b473c366a 100644
> --- a/kernel/kcov.c
> +++ b/kernel/kcov.c
> @@ -512,7 +512,7 @@ static int kcov_mmap(struct file *filep, struct vm_area_struct *vma)
>  
>  	spin_lock_irqsave(&kcov->lock, flags);
>  	size = kcov->size * sizeof(unsigned long);
> -	if (kcov->area == NULL || vma->vm_pgoff != 0 ||
> +	if (kcov->area == NULL || vma_start_pgoff(vma) ||
>  	    vma->vm_end - vma->vm_start != size) {
>  		res = -EINVAL;
>  		goto exit;
> diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
> index 56a328e94395..dfa493d54ef9 100644
> --- a/kernel/trace/ring_buffer.c
> +++ b/kernel/trace/ring_buffer.c
> @@ -7613,7 +7613,8 @@ static int __rb_inc_dec_mapped(struct ring_buffer_per_cpu *cpu_buffer,
>  static int __rb_map_vma(struct ring_buffer_per_cpu *cpu_buffer,
>  			struct vm_area_struct *vma)
>  {
> -	unsigned long nr_subbufs, nr_pages, nr_vma_pages, pgoff = vma->vm_pgoff;
> +	unsigned long nr_subbufs, nr_pages, nr_vma_pages;
> +	pgoff_t pgoff = vma_start_pgoff(vma);
>  	unsigned int subbuf_pages, subbuf_order;
>  	struct page **pages __free(kfree) = NULL;
>  	int p = 0, s = 0;

Best regards
-- 
Marek Szyprowski, PhD
Samsung R&D Institute Poland


^ permalink raw reply

* Re: [PATCH] rtla: Also link in ctype.c
From: Tomas Glozar @ 2026-07-07 10:22 UTC (permalink / raw)
  To: Bastian Blank, Steven Rostedt, Tomas Glozar, linux-trace-kernel,
	linux-kernel
In-Reply-To: <ako2S4mzIqWwYuas@steamhammer.waldi.eu.org>

ne 5. 7. 2026 v 12:55 odesílatel Bastian Blank <waldi@debian.org> napsal:
>
> rtla started to only link parts of the tools library.  It now misses the
> ctype information used by all the related string operations.  Just add
> another single file to make it build again.
>
> Signed-off-by: Bastian Blank <waldi@debian.org>
> ---
>  tools/tracing/rtla/Makefile | 14 ++++++++++----
>  1 file changed, 10 insertions(+), 4 deletions(-)
>

Thank you. It appears that GCC LTO drops the symbol use of "_ctype",
so I didn't see it earlier. With removed -flto=auto from
Makefile.rtla, I can reproduce it:

 LINK    /linux-7.2-rc2/tools/tracing/rtla/rtla
/usr/bin/x86_64-linux-gnu-ld.bfd:
/linux-7.2-rc2/tools/tracing/rtla/lib/string.o: warning: relocation
against `_ctype' in read-only section `.text'
/usr/bin/x86_64-linux-gnu-ld.bfd:
/linux-7.2-rc2/tools/tracing/rtla/lib/string.o: in function
`skip_spaces':
/linux-7.2-rc2/tools/lib/string.c:126:(.text+0x14c): undefined
reference to `_ctype'
/usr/bin/x86_64-linux-gnu-ld.bfd:
/linux-7.2-rc2/tools/tracing/rtla/lib/string.o: in function `strim':
/linux-7.2-rc2/tools/lib/string.c:149:(.text+0x187): undefined
reference to `_ctype'
/usr/bin/x86_64-linux-gnu-ld.bfd: warning: creating DT_TEXTREL in a PIE
collect2: error: ld returned 1 exit status
make: *** [Makefile:121: /linux-7.2-rc2/tools/tracing/rtla/rtla] Error 1

> diff --git a/tools/tracing/rtla/Makefile b/tools/tracing/rtla/Makefile
> index 60a102538988..387bc6cc18f0 100644
> --- a/tools/tracing/rtla/Makefile
> +++ b/tools/tracing/rtla/Makefile
> @@ -45,6 +45,9 @@ else
>    LIB_OUTPUT = $(CURDIR)/lib
>  endif
>
> +LIB_CTYPE = $(LIB_OUTPUT)/ctype.o
> +LIB_CTYPE_SRC = $(srctree)/tools/lib/ctype.c
> +
>  LIB_STRING = $(LIB_OUTPUT)/string.o
>  LIB_STRING_SRC = $(srctree)/tools/lib/string.c
>
> @@ -117,12 +120,12 @@ tests/bpf/bpf_action_map.o: tests/bpf/bpf_action_map.c
>         $(Q)echo "BPF skeleton support is disabled, skipping tests/bpf/bpf_action_map.o"
>  endif
>
> -$(RTLA): $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R)
> -       $(QUIET_LINK)$(CC) $(LDFLAGS) -o $(RTLA) $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R) $(EXTLIBS)
> +$(RTLA): $(RTLA_IN) $(LIBSUBCMD) $(LIB_CTYPE) $(LIB_STRING) $(LIB_STR_ERROR_R)
> +       $(QUIET_LINK)$(CC) $(LDFLAGS) -o $(RTLA) $(RTLA_IN) $(LIBSUBCMD) $(LIB_CTYPE) $(LIB_STRING) $(LIB_STR_ERROR_R) $(EXTLIBS)
>
> -static: $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R)
> +static: $(RTLA_IN) $(LIBSUBCMD) $(LIB_CTYPE) $(LIB_STRING) $(LIB_STR_ERROR_R)
>         $(eval LDFLAGS += -static)
> -       $(QUIET_LINK)$(CC) -static $(LDFLAGS) -o $(RTLA)-static $(RTLA_IN) $(LIBSUBCMD) $(LIB_STRING) $(LIB_STR_ERROR_R) $(EXTLIBS)
> +       $(QUIET_LINK)$(CC) -static $(LDFLAGS) -o $(RTLA)-static $(RTLA_IN) $(LIBSUBCMD) $(LIB_CTYPE) $(LIB_STRING) $(LIB_STR_ERROR_R) $(EXTLIBS)
>
>  rtla.%: fixdep FORCE
>         make -f $(srctree)/tools/build/Makefile.build dir=. $@
> @@ -150,6 +153,9 @@ $(LIB_STR_ERROR_R): $(LIB_STR_ERROR_R_SRC) | $(LIB_OUTPUT)
>  $(LIB_STRING): $(LIB_STRING_SRC) | $(LIB_OUTPUT)
>         $(QUIET_CC)$(CC) $(CFLAGS) -c -o $@ $<
>
> +$(LIB_CTYPE): $(LIB_CTYPE_SRC) | $(LIB_OUTPUT)
> +       $(QUIET_CC)$(CC) $(CFLAGS) -c -o $@ $<
> +
>  libsubcmd-clean:
>         $(call QUIET_CLEAN, libsubcmd)
>         $(Q)$(RM) -r -- $(LIBSUBCMD_OUTPUT)
> --
> 2.53.0
>

The list of libraries is getting a bit long. Maybe it's time to
collapse it into one variable in a future release.

Anyway, I'll take this and attach:

Fixes: 48209d763c22 ("rtla: Add libsubcmd dependency")

Tomas


^ permalink raw reply

* Re: [PATCH 21/30] mm/vma: add and use vma_[add/sub]_pgoff()
From: Lorenzo Stoakes @ 2026-07-07 10:22 UTC (permalink / raw)
  To: Pedro Falcato
  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, Rik van Riel, Harry Yoo,
	Jann Horn
In-Reply-To: <akZI0n1U32Ptd0ye@pedro-suse.lan>

On Thu, Jul 02, 2026 at 12:20:10PM +0100, Pedro Falcato wrote:
> On Mon, Jun 29, 2026 at 01:23:32PM +0100, Lorenzo Stoakes wrote:
> > Add helpers for adding or subtracting to a VMA's page offset, exposed
> > internally for VMA users within mm in mm/vma.h.
> >
> > This is to lay the foundations for tracking anonymous page offset for
> > MAP_PRIVATE file-backed mappings, where adding and subtracting from this
> > value must be reflected in both the file and anonymous offsets.
> >
> > These are used on VMA split and downward stack expansion.
> >
> > No functional change intended.
> >
> > Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
> > ---
> >  mm/nommu.c                      |  6 ++++--
> >  mm/vma.c                        |  6 +++---
> >  mm/vma.h                        | 12 ++++++++++++
> >  tools/testing/vma/include/dup.h | 13 ++++++++++++-
> >  4 files changed, 31 insertions(+), 6 deletions(-)
> >
> > diff --git a/mm/nommu.c b/mm/nommu.c
> > index 7333d855e974..c7fafcd87c14 100644
> > --- a/mm/nommu.c
> > +++ b/mm/nommu.c
> > @@ -41,6 +41,7 @@
> >  #include <asm/tlbflush.h>
> >  #include <asm/mmu_context.h>
> >  #include "internal.h"
> > +#include "vma.h"
> >
> >  unsigned long highest_memmap_pfn;
> >  int heap_stack_gap = 0;
> > @@ -1338,7 +1339,8 @@ static int split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
> >  		region->vm_top = region->vm_end = new->vm_end = addr;
> >  	} else {
> >  		region->vm_start = new->vm_start = addr;
> > -		region->vm_pgoff = new->vm_pgoff += npages;
> > +		vma_add_pgoff(new, npages);
> > +		region->vm_pgoff = vma_start_pgoff(new);
> >  	}
> >
> >  	vma_iter_config(vmi, new->vm_start, new->vm_end);
> > @@ -1355,7 +1357,7 @@ 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_pgoff += npages;
> > +		vma_add_pgoff(vma, npages);
> >  		vma->vm_region->vm_pgoff = vma_start_pgoff(vma);
> >  	} else {
> >  		vma->vm_region->vm_end = vma->vm_end = addr;
> > diff --git a/mm/vma.c b/mm/vma.c
> > index 185d07397ca6..cb7222e20c93 100644
> > --- a/mm/vma.c
> > +++ b/mm/vma.c
> > @@ -517,7 +517,7 @@ __split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
> >  		new->vm_end = addr;
> >  	} else {
> >  		new->vm_start = addr;
> > -		new->vm_pgoff += linear_page_delta(vma, addr);
> > +		vma_add_pgoff(new, linear_page_delta(vma, addr));
> >  	}
> >
> >  	err = -ENOMEM;
> > @@ -556,7 +556,7 @@ __split_vma(struct vma_iterator *vmi, struct vm_area_struct *vma,
> >
> >  	if (new_below) {
> >  		vma->vm_start = addr;
> > -		vma->vm_pgoff += (addr - new->vm_start) >> PAGE_SHIFT;
> > +		vma_add_pgoff(vma, (addr - new->vm_start) >> PAGE_SHIFT);
> >  	} else {
> >  		vma->vm_end = addr;
> >  	}
> > @@ -3305,7 +3305,7 @@ int expand_downwards(struct vm_area_struct *vma, unsigned long address)
> >  				vm_stat_account(mm, vma->vm_flags, grow);
> >  				anon_vma_interval_tree_pre_update_vma(vma);
> >  				vma->vm_start = address;
> > -				vma->vm_pgoff -= grow;
> > +				vma_sub_pgoff(vma, grow);
> >  				/* Overwrite old entry in mtree. */
> >  				vma_iter_store_overwrite(&vmi, vma);
> >  				anon_vma_interval_tree_post_update_vma(vma);
> > diff --git a/mm/vma.h b/mm/vma.h
> > index 2342516ce00e..47fe35e5307e 100644
> > --- a/mm/vma.h
> > +++ b/mm/vma.h
> > @@ -247,6 +247,18 @@ static inline pgoff_t vmg_end_pgoff(const struct vma_merge_struct *vmg)
> >  	return vmg_start_pgoff(vmg) + vmg_pages(vmg);
> >  }
> >
> > +static inline void vma_add_pgoff(struct vm_area_struct *vma, pgoff_t delta)
> > +{
> > +	vma_assert_can_modify(vma);
> > +	vma->vm_pgoff += delta;
> > +}
> > +
> > +static inline void vma_sub_pgoff(struct vm_area_struct *vma, pgoff_t delta)
> > +{
> > +	vma_assert_can_modify(vma);
> > +	vma->vm_pgoff -= delta;
> > +}
> > +
> >  #define VMG_STATE(name, mm_, vmi_, start_, end_, vma_flags_, pgoff_)	\
> >  	struct vma_merge_struct name = {				\
> >  		.mm = mm_,						\
> > diff --git a/tools/testing/vma/include/dup.h b/tools/testing/vma/include/dup.h
> > index 7ed165c8d9bc..41fea90a344d 100644
> > --- a/tools/testing/vma/include/dup.h
> > +++ b/tools/testing/vma/include/dup.h
> > @@ -1163,6 +1163,11 @@ static inline struct vm_area_struct *vma_next(struct vma_iterator *vmi)
> >  	return mas_find(&vmi->mas, ULONG_MAX);
> >  }
> >
> > +static inline bool vma_is_attached(struct vm_area_struct *vma)
> > +{
> > +	return refcount_read(&vma->vm_refcnt);
> > +}
> > +
> >  /*
> >   * WARNING: to avoid racing with vma_mark_attached()/vma_mark_detached(), these
> >   * assertions should be made either under mmap_write_lock or when the object
> > @@ -1170,7 +1175,13 @@ static inline struct vm_area_struct *vma_next(struct vma_iterator *vmi)
> >   */
> >  static inline void vma_assert_attached(struct vm_area_struct *vma)
> >  {
> > -	WARN_ON_ONCE(!refcount_read(&vma->vm_refcnt));
> > +	WARN_ON_ONCE(!vma_is_attached(vma));
> > +}
> > +
> > +static inline void vma_assert_can_modify(struct vm_area_struct *vma)
> > +{
> > +	if (vma_is_attached(vma))
> > +		vma_assert_write_locked(vma);
> >  }
>
> These hunks in dup.h look lost. Should perhaps be on the previous patch
> (adding the helpers).

Yeah, it's because the VMA code starts actually using them in a way that
otherwise breaks the tests at this point, but you're right, functionally it'd be
nicer to add them at the point they're introduced.

Will fix that up on respin!

>
> Anyway, Obviously Correct(tm).
>
> Reviewed-by: Pedro Falcato <pfalcato@suse.de>

Thanks!

>
> --
> Pedro

Cheers, Lorenzo

^ permalink raw reply

* Re: [PATCH 22/30] mm/vma: move __install_special_mapping() to vma.c
From: Lorenzo Stoakes @ 2026-07-07 10:31 UTC (permalink / raw)
  To: Pedro Falcato
  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, Rik van Riel, Harry Yoo,
	Jann Horn
In-Reply-To: <akZJjNic8u0pDxgD@pedro-suse.lan>

On Thu, Jul 02, 2026 at 12:22:56PM +0100, Pedro Falcato wrote:
> On Mon, Jun 29, 2026 at 01:23:33PM +0100, Lorenzo Stoakes wrote:
> > This function is operating on VMAs and rightly belongs in vma.c, where it
> > can be subject to VMA userland testing and allows us to isolate it from the
> > rest of mm.
> >
> > The _install_special_mapping() function will remain in mmap.c as a wrapper,
> > since this is used by architecture-specific code.
> >
> > Doing so allows us to isolate more functions in vma.c for the same reasons.
> >
> > This forms part of work to allow for tracking MAP_PRIVATE file-backed
> > mappings by their anonymous virtual page offset, as doing so allows us to
> > isolate and keep code that interacts with this together.
> >
> > No functional change intended.
> >
> > Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
> > ---
> >  mm/mmap.c | 38 --------------------------------------
> >  mm/vma.c  | 38 ++++++++++++++++++++++++++++++++++++++
> >  mm/vma.h  |  5 +++++
> >  3 files changed, 43 insertions(+), 38 deletions(-)
> >
> > diff --git a/mm/mmap.c b/mm/mmap.c
> > index 2d09a57e3620..46174e706bbe 100644
> > --- a/mm/mmap.c
> > +++ b/mm/mmap.c
> > @@ -1447,44 +1447,6 @@ static vm_fault_t special_mapping_fault(struct vm_fault *vmf)
> >  	return VM_FAULT_SIGBUS;
> >  }
> >
> > -static struct vm_area_struct *__install_special_mapping(
> > -	struct mm_struct *mm,
> > -	unsigned long addr, unsigned long len,
> > -	vm_flags_t vm_flags, void *priv,
> > -	const struct vm_operations_struct *ops)
> > -{
> > -	int ret;
> > -	struct vm_area_struct *vma;
> > -
> > -	vma = vm_area_alloc(mm);
> > -	if (unlikely(vma == NULL))
> > -		return ERR_PTR(-ENOMEM);
> > -
> > -	vma_set_range(vma, addr, addr + len, 0);
> > -	vm_flags |= mm->def_flags | VM_DONTEXPAND;
> > -	if (pgtable_supports_soft_dirty())
> > -		vm_flags |= VM_SOFTDIRTY;
> > -	vm_flags_init(vma, vm_flags & ~VM_LOCKED_MASK);
> > -	vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
> > -
> > -	vma->vm_ops = ops;
> > -	vma->vm_private_data = priv;
> > -
> > -	ret = insert_vm_struct(mm, vma);
> > -	if (ret)
> > -		goto out;
> > -
> > -	vm_stat_account(mm, vma->vm_flags, len >> PAGE_SHIFT);
> > -
> > -	perf_event_mmap(vma);
> > -
> > -	return vma;
> > -
> > -out:
> > -	vm_area_free(vma);
> > -	return ERR_PTR(ret);
> > -}
> > -
> >  bool vma_is_special_mapping(const struct vm_area_struct *vma,
> >  	const struct vm_special_mapping *sm)
> >  {
> > diff --git a/mm/vma.c b/mm/vma.c
> > index cb7222e20c93..f4de706a2728 100644
> > --- a/mm/vma.c
> > +++ b/mm/vma.c
> > @@ -3399,3 +3399,41 @@ __weak unsigned long vma_mmu_pagesize(struct vm_area_struct *vma)
> >  {
> >  	return vma_kernel_pagesize(vma);
> >  }
> > +
> > +struct vm_area_struct *__install_special_mapping(
> > +	struct mm_struct *mm,
> > +	unsigned long addr, unsigned long len,
> > +	vm_flags_t vm_flags, void *priv,
> > +	const struct vm_operations_struct *ops)
> > +{
> > +	int ret;
> > +	struct vm_area_struct *vma;
> > +
> > +	vma = vm_area_alloc(mm);
> > +	if (unlikely(vma == NULL))
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	vma_set_range(vma, addr, addr + len, 0);
> > +	vm_flags |= mm->def_flags | VM_DONTEXPAND;
> > +	if (pgtable_supports_soft_dirty())
> > +		vm_flags |= VM_SOFTDIRTY;
> > +	vm_flags_init(vma, vm_flags & ~VM_LOCKED_MASK);
> > +	vma->vm_page_prot = vm_get_page_prot(vma->vm_flags);
> > +
> > +	vma->vm_ops = ops;
> > +	vma->vm_private_data = priv;
> > +
> > +	ret = insert_vm_struct(mm, vma);
> > +	if (ret)
> > +		goto out;
> > +
> > +	vm_stat_account(mm, vma->vm_flags, len >> PAGE_SHIFT);
> > +
> > +	perf_event_mmap(vma);
> > +
> > +	return vma;
> > +
> > +out:
> > +	vm_area_free(vma);
> > +	return ERR_PTR(ret);
> > +}
> > diff --git a/mm/vma.h b/mm/vma.h
> > index 47fe35e5307e..14f026bf3be4 100644
> > --- a/mm/vma.h
> > +++ b/mm/vma.h
> > @@ -775,4 +775,9 @@ static inline bool map_deny_write_exec(const vma_flags_t *old,
> >  }
> >  #endif
> >
> > +struct vm_area_struct *__install_special_mapping(struct mm_struct *mm,
> > +		unsigned long addr, unsigned long len,
> > +		vm_flags_t vm_flags, void *priv,
> > +		const struct vm_operations_struct *ops);
> > +
> >  #endif	/* __MM_VMA_H */
>
> I'm really annoyed that _install_special_mapping has a leading underscore.
> That's it.

Yeah it's horrible :)

>
> Reviewed-by: Pedro Falcato <pfalcato@suse.de>

Thanks!

>
> --
> Pedro

Cheers, Lorenzo

^ permalink raw reply

* Re: [PATCH 25/30] mm/vma: update vmg_adjust_set_range() to offset pgoff instead
From: Lorenzo Stoakes @ 2026-07-07 10:35 UTC (permalink / raw)
  To: Pedro Falcato
  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, Rik van Riel, Harry Yoo,
	Jann Horn
In-Reply-To: <akZLhkjsJ_3sGdox@pedro-suse.lan>

On Thu, Jul 02, 2026 at 12:29:54PM +0100, Pedro Falcato wrote:
> On Mon, Jun 29, 2026 at 01:23:36PM +0100, Lorenzo Stoakes wrote:
> > We are calculating the pgoff as an offset, since we have vma_add_pgoff()
> > and vma_sub_pgoff() available, just offset this value directly and use
> > __vma_set_range() for vma->vm_[start, end] values.
> >
> > We take care to update the range before offsetting the page offset, so the
> > adjusted VMA's vm_start and vm_pgoff are mutually consistent at the point
> > the page offset helpers operate - this matters once vma_set_pgoff() comes
> > to assert invariants which relate the two.
> >
> > Doing so lays the foundation for future work which allows for use of
> > virtual page offsets for MAP_PRIVATE-file backed mappings.
> >
> > No functional change intended.
> >
> > Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
> > ---
> >  mm/vma.c | 15 ++++-----------
> >  1 file changed, 4 insertions(+), 11 deletions(-)
> >
> > diff --git a/mm/vma.c b/mm/vma.c
> > index e3355eab11f2..0579fc8c9bd5 100644
> > --- a/mm/vma.c
> > +++ b/mm/vma.c
> > @@ -714,9 +714,6 @@ void validate_mm(struct mm_struct *mm)
> >   */
> >  static void vmg_adjust_set_range(struct vma_merge_struct *vmg)
> >  {
> > -	struct vm_area_struct *adjust;
> > -	pgoff_t pgoff;
> > -
> >  	if (vmg->__adjust_middle_start) {
> >  		/*
> >  		 * vmg->start    vmg->end
> > @@ -735,8 +732,8 @@ static void vmg_adjust_set_range(struct vma_merge_struct *vmg)
> >  		struct vm_area_struct *middle = vmg->middle;
> >  		const unsigned long delta = vmg->end - middle->vm_start;
> >
> > -		pgoff = vma_start_pgoff(middle) + (delta >> PAGE_SHIFT);
> > -		adjust = middle;
> > +		__vma_set_range(middle, vmg->end, middle->vm_end);
> > +		vma_add_pgoff(middle, delta >> PAGE_SHIFT);
> >  	} else if (vmg->__adjust_next_start) {
> >  		/*
> >  		 *                Originally:
> > @@ -764,13 +761,9 @@ static void vmg_adjust_set_range(struct vma_merge_struct *vmg)
> >  		struct vm_area_struct *next = vmg->next;
> >  		const unsigned long delta = next->vm_start - vmg->end;
> >
> > -		pgoff = vma_start_pgoff(next) - (delta >> PAGE_SHIFT);
> > -		adjust = next;
> > -	} else {
> > -		return;
> > +		__vma_set_range(next, vmg->end, next->vm_end);
> > +		vma_sub_pgoff(next, delta >> PAGE_SHIFT);
> >  	}
> > -
> > -	vma_set_range(adjust, vmg->end, adjust->vm_end, pgoff);
> >  }
>
> Maybe this should be squashed with That Other Patch that touches this.

Ah this separation makes more sense from the point of view of the virt pgoff
stuff in the RFC (see [0]).

And would rather keep as vaguely bitesized as possible :>)

>
> Anyway,
>
> Reviewed-by: Pedro Falcato <pfalcato@suse.de>

Thanks!

>
> --
> Pedro

Cheers, Lorenzo

[0]:https://lore.kernel.org/linux-mm/cover.1782745153.git.ljs@kernel.org/

^ permalink raw reply

* Re: [PATCH 27/30] mm/vma: correct incorrect vma.h inclusion
From: Lorenzo Stoakes @ 2026-07-07 10:41 UTC (permalink / raw)
  To: Pedro Falcato
  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, Rik van Riel, Harry Yoo,
	Jann Horn
In-Reply-To: <akZNiN5Y9fPk8bZH@pedro-suse.lan>

On Thu, Jul 02, 2026 at 12:40:30PM +0100, Pedro Falcato wrote:
> On Mon, Jun 29, 2026 at 01:23:38PM +0100, Lorenzo Stoakes wrote:
> > The only files which should be including vma.h are the implementation files
> > for the core VMA logic - vma.c, vma_init.c, and vma_exec.c.
> >
> > This is in order to allow for userland testing of core VMA logic. In this
> > cases, vma_internal.h and vma.h are included, providing both the
> > dependencies upon which the core VMA logic requires and its declarations.
> >
> > Userland testable VMA logic is achieved by having separate vma_internal.h
> > implementations for userland and kernel.
> >
> > Callers other than the core VMA implementation should include internal.h
> > instead. This header does not need to include vma_internal.h as it only
> > contains the vma.h declarations, for which the includes already present
> > suffice.
> >
> > Update code to reflect this, update comments to reflect the fact there are
> > 3 VMA implementation files and document things more clearly.
> >
> > While we're here, slightly improve the language of the comment describing
> > vma_exec.c.
>
> Two random thoughts:
> 1) perhaps vma.h -> vma_private.h

Not a bad idea thanks!

> 2) https://lore.kernel.org/all/CAHk-=wghMm2c+AYEcwYY7drSVXB27DYqc-ZXpFiq=XFs-w59wA@mail.gmail.com/
>    mm/vma/whatever.c :) would PROBABLY solve the issue of people snooping vma.h

I think a vma/ subdir would probably confuse things further, I think renaming to
vma_private.h neatly solves it actually, along with a comment maybe in the
header itself?

Then again mm/vma/{vma.c,init.c, exec.c, private.h} isn't too crazy
either. Though vma.h is the actual 'shared' bit, and vma_internal.h is the
private bit that the userland changes. But could switch things around vma.h ->
mm/vma/internal.h that mm/internal.h imports, and mm/vma_internal.h becomes
mm/vma/private.h.

I think that could work but definitely a follow-up!

>
> >
> > No functional change intended.
> >
> > Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
>
> Reviewed-by: Pedro Falcato <pfalcato@suse.de>

Thanks!

Cheers, Lorenzo

^ permalink raw reply

* Re: [PATCH 29/30] tools/testing/vma: default VMA flag bits to 64-bit
From: Lorenzo Stoakes @ 2026-07-07 10:47 UTC (permalink / raw)
  To: Pedro Falcato
  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, Rik van Riel, Harry Yoo,
	Jann Horn
In-Reply-To: <akZO3xI4Lt1iSbms@pedro-suse.lan>

On Thu, Jul 02, 2026 at 12:44:21PM +0100, Pedro Falcato wrote:
> On Mon, Jun 29, 2026 at 01:23:40PM +0100, Lorenzo Stoakes wrote:
> > With all of the sanitisers turned on, setting the VMA flag bits depth to
> > 128 by default results in overly long build times.
> >
> > Reduce this to 64 - we can always manipulate these later for testing of
> > larger bitmaps as needed.
> >
>
> Hmm, what's the problem with the sanitizers? Shouldn't this just result in
> slightly different codegen?

I'm not sure but it results in vastly longer build times. It was a fun idea but
it partly defeats the point of the VMA userland tests.

Rather than spend too long investigating I'd rather we move to a sane default.

>
> > Signed-off-by: Lorenzo Stoakes <ljs@kernel.org>
> > ---
> >  tools/testing/vma/Makefile | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> >
> > diff --git a/tools/testing/vma/Makefile b/tools/testing/vma/Makefile
> > index e72b45dedda5..ef6cc558afe1 100644
> > --- a/tools/testing/vma/Makefile
> > +++ b/tools/testing/vma/Makefile
> > @@ -10,7 +10,7 @@ OFILES = $(SHARED_OFILES) main.o shared.o maple-shim.o
> >  TARGETS = vma
> >
> >  # These can be varied to test different sizes.
> > -CFLAGS += -DNUM_VMA_FLAG_BITS=128 -DNUM_MM_FLAG_BITS=128
> > +CFLAGS += -DNUM_VMA_FLAG_BITS=64 -DNUM_MM_FLAG_BITS=64
> >
> >  main.o: main.c shared.c shared.h vma_internal.h tests/merge.c tests/mmap.c tests/vma.c ../../../mm/vma.c ../../../mm/vma_init.c ../../../mm/vma_exec.c ../../../mm/vma.h include/custom.h include/dup.h include/stubs.h
> >
> > --
> > 2.54.0
> >
>
> --
> Pedro

Thanks, Lorenzo

^ permalink raw reply

* Re: [PATCH v3 04/11] arm64/mm: Add set_memory_device() and set_memory_normal()
From: Will Deacon @ 2026-07-07 11:27 UTC (permalink / raw)
  To: Thierry Reding
  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: <akuvyu1Pq0ZVMZV0@orome>

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?

Will

^ permalink raw reply

* [PATCH] riscv: ftrace: reject out-of-range non-direct targets
From: Rui Qi @ 2026-07-07 12:12 UTC (permalink / raw)
  To: rostedt, mhiramat
  Cc: mark.rutland, pjw, palmer, aou, alex, linux-kernel,
	linux-trace-kernel, linux-riscv, Rui Qi

RISC-V initializes the AUIPC half of each ftrace callsite to reach
ftrace_caller and later only patches the JALR instruction. The old
ftrace_make_call() code redirected any requested target outside the
JALR immediate range back to FTRACE_ADDR.

That fallback is only valid for direct-call targets, where
ftrace_caller can still dispatch through op->direct_call. For an
ops-specific trampoline, the generic ftrace core requested a call to
ops->trampoline. Redirecting the site to FTRACE_ADDR instead enters
ftrace_caller and invokes op->func, bypassing that trampoline.

ftrace_modify_call() had the same issue more directly: it ignored
old_addr and addr and always validated and updated the site as
FTRACE_ADDR.

Add a helper to resolve call targets consistently. Keep targets that
fit in the existing AUIPC/JALR window, redirect only out-of-range
direct-call targets through FTRACE_ADDR, and reject other out-of-range
targets. Use the resolved old and new targets in ftrace_modify_call()
so the architecture implementation follows the generic contract.

Signed-off-by: Rui Qi <qirui.001@bytedance.com>
---
 arch/riscv/kernel/ftrace.c | 79 +++++++++++++++++++++++++++++++-------
 1 file changed, 65 insertions(+), 14 deletions(-)

diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c
index b430edfb83f4..26604bbc4bb5 100644
--- a/arch/riscv/kernel/ftrace.c
+++ b/arch/riscv/kernel/ftrace.c
@@ -46,16 +46,19 @@ void arch_ftrace_update_code(int command)
 	flush_icache_all();
 }
 
-static int __ftrace_modify_call(unsigned long source, unsigned long target, bool validate)
+static int __ftrace_modify_call(unsigned long source, unsigned long old,
+				unsigned long target, bool validate)
 {
-	unsigned int call[2], offset;
+	unsigned int call[2], old_call[2], offset;
 	unsigned int replaced[2];
 
 	offset = target - source;
 	call[1] = to_jalr_t0(offset);
 
 	if (validate) {
-		call[0] = to_auipc_t0(offset);
+		offset = old - source;
+		old_call[0] = to_auipc_t0(offset);
+		old_call[1] = to_jalr_t0(offset);
 		/*
 		 * Read the text we want to modify;
 		 * return must be -EFAULT on read error
@@ -63,9 +66,10 @@ static int __ftrace_modify_call(unsigned long source, unsigned long target, bool
 		if (copy_from_kernel_nofault(replaced, (void *)source, 2 * MCOUNT_INSN_SIZE))
 			return -EFAULT;
 
-		if (replaced[0] != call[0]) {
-			pr_err("%p: expected (%08x) but got (%08x)\n",
-			       (void *)source, call[0], replaced[0]);
+		if (replaced[0] != old_call[0] || replaced[1] != old_call[1]) {
+			pr_err("%p: expected (%08x %08x) but got (%08x %08x)\n",
+			       (void *)source, old_call[0], old_call[1],
+			       replaced[0], replaced[1]);
 			return -EINVAL;
 		}
 	}
@@ -77,6 +81,46 @@ static int __ftrace_modify_call(unsigned long source, unsigned long target, bool
 	return 0;
 }
 
+static bool ftrace_call_target_in_range(unsigned long addr)
+{
+	unsigned long ftrace_addr = FTRACE_ADDR;
+	unsigned long distance;
+
+	distance = addr > ftrace_addr ? addr - ftrace_addr : ftrace_addr - addr;
+
+	return distance <= JALR_RANGE;
+}
+
+static int ftrace_resolve_call_addr(struct dyn_ftrace *rec, unsigned long addr,
+				    unsigned long *target)
+{
+	unsigned long direct;
+
+	/*
+	 * The AUIPC instruction is initialized for ftrace_caller and this
+	 * implementation only patches the JALR instruction afterwards. Targets
+	 * that fit in the existing AUIPC/JALR window can be called as-is.
+	 */
+	if (ftrace_call_target_in_range(addr)) {
+		*target = addr;
+		return 0;
+	}
+
+	/*
+	 * Out-of-range direct-call targets can still be reached through the
+	 * ftrace_caller path, which dispatches via op->direct_call. Do not use
+	 * this fallback for ops-specific trampolines, because ftrace_caller
+	 * invokes op->func and would not preserve the requested trampoline.
+	 */
+	direct = ftrace_find_rec_direct(rec->ip);
+	if (direct && addr == direct) {
+		*target = FTRACE_ADDR;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
 static const struct ftrace_ops *riscv64_rec_get_ops(struct dyn_ftrace *rec)
 {
@@ -116,19 +160,18 @@ static int ftrace_rec_update_ops(struct dyn_ftrace *rec) { return 0; }
 
 int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
 {
-	unsigned long distance, orig_addr, pc = rec->ip - MCOUNT_AUIPC_SIZE;
+	unsigned long pc = rec->ip - MCOUNT_AUIPC_SIZE;
 	int ret;
 
-	ret = ftrace_rec_update_ops(rec);
+	ret = ftrace_resolve_call_addr(rec, addr, &addr);
 	if (ret)
 		return ret;
 
-	orig_addr = (unsigned long)&ftrace_caller;
-	distance = addr > orig_addr ? addr - orig_addr : orig_addr - addr;
-	if (distance > JALR_RANGE)
-		addr = FTRACE_ADDR;
+	ret = ftrace_rec_update_ops(rec);
+	if (ret)
+		return ret;
 
-	return __ftrace_modify_call(pc, addr, false);
+	return __ftrace_modify_call(pc, 0, addr, false);
 }
 
 int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, unsigned long addr)
@@ -215,11 +258,19 @@ int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
 	unsigned long caller = rec->ip - MCOUNT_AUIPC_SIZE;
 	int ret;
 
+	ret = ftrace_resolve_call_addr(rec, old_addr, &old_addr);
+	if (ret)
+		return ret;
+
+	ret = ftrace_resolve_call_addr(rec, addr, &addr);
+	if (ret)
+		return ret;
+
 	ret = ftrace_rec_update_ops(rec);
 	if (ret)
 		return ret;
 
-	return __ftrace_modify_call(caller, FTRACE_ADDR, true);
+	return __ftrace_modify_call(caller, old_addr, addr, true);
 }
 #endif
 
-- 
2.20.1

^ permalink raw reply related

* Re: [PATCH v3 04/11] arm64/mm: Add set_memory_device() and set_memory_normal()
From: Robin Murphy @ 2026-07-07 12:15 UTC (permalink / raw)
  To: Thierry Reding, 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, 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: <akuvyu1Pq0ZVMZV0@orome>

On 06/07/2026 2:49 pm, 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.

OK, so this is dynamic TrustZone, which is essentially identical to CCA 
delegation as far as we're concerned from the Non-Secure side. IIRC 
there was some ongoing talk about explicitly keeping track of the state 
of physical memory ranges in terms of being delegated to CoCo VMs or 
not, so eventually plumbing a "delegated to TEE/other" state through all 
the same mechanisms seems a pretty achievable goal.

For now, though, firstly I'll note we have seen this sort of thing before:

https://lore.kernel.org/dri-devel/20240515112308.10171-1-yong.wu@mediatek.com/

although that didn't seem to need explicit unmapping (likely it involved 
a TrustZone controller that just made NS accesses RAZ/WI instead of 
external-aborting).

If you want to be nice and start trying to build the general abstraction 
for this, then as a first step I'd suggest following the shape of the 
current CCA machinery - build a "delegate to TEE" operation around the 
existing set_memory_valid() paradigm[1] with can_set_direct_map() 
safeguards, and have something like a have_dynamic_tz() that echoes 
is_realm_world() in terms of being set at boot when one of these regions 
is detected by the early reserved-memory parsing, then considered in 
force_pte_mapping() (such that it only matters if BBML3 doesn't already 
have us covered).

Thanks,
Robin.


[1] Personally I'd be inclined to stay away from set_memory_*crypted() 
until that mess gets sorted out properly, but the argument could also be 
made the other way that the "delegated" state is currently mixed up in 
"encrypted", so technically it wouldn't be entirely inaccurate to use, 
it would just mean that we're intentionally adding more to that cleanup 
effort. For now it seems nicer to me to keep a distinct "made invalid 
(due to delegation)" state that can eventually converge into a proper 
"delegated" state once that exists, rather than get mixed up in the 
current 
guest-shared/guest-private/host-shared/host-private/host-delegated mess 
most of which is not relevant for non-CoCo uses.

> 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?
> 
> Thierry


^ permalink raw reply

* [PATCH v2 0/4] mm: honour compact_unevictable_allowed in mlock and CMA paths
From: Wandun Chen @ 2026-07-07 12:59 UTC (permalink / raw)
  To: vbabka, david, rostedt, mhiramat, Alexander.Krabler, hughd, fvdl,
	bigeasy, linux-mm, linux-kernel, linux-trace-kernel,
	linux-rt-devel
  Cc: akpm, surenb, mhocko, jackmanb, hannes, ziy, ljs, riel, liam,
	harry, jannh, lance.yang, mathieu.desnoyers, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
	pfalcato

From: Wandun Chen <chenwandun@lixiang.com>

vm.compact_unevictable_allowed=0 (the default on RT) is meant to keep
compaction from touching unevictable folios. Several paths still migrate
folios that are about to become unevictable, or in CMA regions,
installing migration entries that a later access must wait on, then
causing latency spikes on RT kernels.

This series fixes those paths and adds a tracepoint for diagnosis. It is
a rework of the RFC [1] per review feedback, mainly from Vlastimil.

RFC --> v2:
1. On top of the isolate-path filtering, also filter by VM_LOCKED
   during the migration unmap step.

2. Make mlock/mlockall wait for in-flight migration entries, ensuring
   the folio is on the unevictable LRU before mlock[all] returns.

3. Dropped letting CMA migration take unevictable folios; instead
   migrate CMA folios out during mlock[all], avoiding migration at
   cma_alloc time.

4. Moved the tracepoint to the migration unmap path.

[1] https://lore.kernel.org/lkml/20260604023812.3700316-1-chenwandun1@gmail.com/

Wandun Chen (4):
  mm/migrate: do not migrate folios mapped into VM_LOCKED VMAs under
    compaction
  mm/mlock: wait for migration to finish when mlocking a folio
  mm/migrate: add tracepoint for folios unmapped during migration
  mm/mlock: migrate folios out of CMA when mlocking a range

 include/linux/compaction.h     |   6 ++
 include/linux/rmap.h           |   3 +
 include/trace/events/migrate.h |  29 +++++++
 mm/compaction.c                |   8 +-
 mm/migrate.c                   |  23 +++++-
 mm/mlock.c                     | 142 ++++++++++++++++++++++++++++++++-
 mm/rmap.c                      |  16 +++-
 7 files changed, 216 insertions(+), 11 deletions(-)

-- 
2.43.0


^ permalink raw reply

* [PATCH v2 1/4] mm/migrate: do not migrate folios mapped into VM_LOCKED VMAs under compaction
From: Wandun Chen @ 2026-07-07 12:59 UTC (permalink / raw)
  To: vbabka, david, rostedt, mhiramat, Alexander.Krabler, hughd, fvdl,
	bigeasy, linux-mm, linux-kernel, linux-trace-kernel,
	linux-rt-devel
  Cc: akpm, surenb, mhocko, jackmanb, hannes, ziy, ljs, riel, liam,
	harry, jannh, lance.yang, mathieu.desnoyers, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
	pfalcato
In-Reply-To: <20260707125925.3725177-1-chenwandun1@gmail.com>

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,
filter out mlocked pages, return early to avoid unnecessary operations.

Fixes: 90d07210ab55 ("mm: mlock: use folios and a folio batch internally")
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);
 
 #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
+					 * 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)))
 			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;
+}
 /*
  * 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;
 
 	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()) {
+			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);
-		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())
+			ttu |= TTU_RESPECT_MLOCK;
+
+		try_to_migrate(src, ttu);
 		old_folio_state |= FOLIO_WAS_MAPPED;
 	}
 
@@ -1905,7 +1919,8 @@ static int migrate_pages_batch(struct list_head *from,
 			}
 
 			rc = migrate_folio_unmap(get_new_folio, put_new_folio,
-					private, folio, &dst, mode, ret_folios);
+					private, folio, &dst, mode, ret_folios,
+					reason);
 			/*
 			 * The rules are:
 			 *	0: folio will be put on unmap_folios list,
diff --git a/mm/rmap.c b/mm/rmap.c
index 0fb7a1b82cf3..3cb7f6337d38 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -2420,6 +2420,9 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
 	unsigned long pfn;
 	unsigned long hsz = 0;
 
+	if ((flags & TTU_RESPECT_MLOCK) && (vma->vm_flags & VM_LOCKED))
+		return false;
+
 	/*
 	 * When racing against e.g. zap_pte_range() on another cpu,
 	 * in between its ptep_get_and_clear_full() and folio_remove_rmap_*(),
@@ -2741,11 +2744,14 @@ void try_to_migrate(struct folio *folio, enum ttu_flags flags)
 	};
 
 	/*
-	 * Migration always ignores mlock and only supports TTU_RMAP_LOCKED and
-	 * TTU_SPLIT_HUGE_PMD, TTU_SYNC, and TTU_BATCH_FLUSH flags.
+	 * Migration normally ignores mlock, but TTU_RESPECT_MLOCK asks it to
+	 * leave folios mapped into VM_LOCKED vmas alone.  Only TTU_RMAP_LOCKED,
+	 * TTU_SPLIT_HUGE_PMD, TTU_SYNC, TTU_BATCH_FLUSH and TTU_RESPECT_MLOCK
+	 * are supported.
 	 */
 	if (WARN_ON_ONCE(flags & ~(TTU_RMAP_LOCKED | TTU_SPLIT_HUGE_PMD |
-					TTU_SYNC | TTU_BATCH_FLUSH)))
+					TTU_SYNC | TTU_BATCH_FLUSH |
+					TTU_RESPECT_MLOCK)))
 		return;
 
 	if (folio_is_zone_device(folio) &&
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 2/4] mm/mlock: wait for migration to finish when mlocking a folio
From: Wandun Chen @ 2026-07-07 12:59 UTC (permalink / raw)
  To: vbabka, david, rostedt, mhiramat, Alexander.Krabler, hughd, fvdl,
	bigeasy, linux-mm, linux-kernel, linux-trace-kernel,
	linux-rt-devel
  Cc: akpm, surenb, mhocko, jackmanb, hannes, ziy, ljs, riel, liam,
	harry, jannh, lance.yang, mathieu.desnoyers, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
	pfalcato
In-Reply-To: <20260707125925.3725177-1-chenwandun1@gmail.com>

From: Wandun Chen <chenwandun@lixiang.com>

In RT kernels, sysctl_compact_unevictable_allowed is false by default,
when the mlock/mlockall system call try to lock all the present page,
the mlock_pte_range function skips non-present entries. If these
non-present entries are migration entries, and the migration is not
guaranteed to have completed before the mlock/mlockall, it may result
in a page fault on subsequent access, which then waits for the
migration to finish, causing spike latency in RT kernels.

Fix it by waiting for the migration to complete during the mlock/mlockall
syscall when sysctl_compact_unevictable_allowed is false.

Fixes: 90d07210ab55 ("mm: mlock: use folios and a folio batch internally")
Suggested-by: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
Link: https://lore.kernel.org/lkml/c8793c0f-7156-4cb7-9e6e-7909397e2fff@kernel.org/#t
---
 mm/mlock.c | 23 +++++++++++++++++++++--
 1 file changed, 21 insertions(+), 2 deletions(-)

diff --git a/mm/mlock.c b/mm/mlock.c
index 97e49038d8d3..ac65de40b22b 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -25,6 +25,7 @@
 #include <linux/memcontrol.h>
 #include <linux/mm_inline.h>
 #include <linux/secretmem.h>
+#include <linux/compaction.h>
 
 #include "internal.h"
 
@@ -361,8 +362,17 @@ static int mlock_pte_range(pmd_t *pmd, unsigned long addr,
 
 	ptl = pmd_trans_huge_lock(pmd, vma);
 	if (ptl) {
-		if (!pmd_present(*pmd))
+		if (!pmd_present(*pmd)) {
+			if (unlikely((vma->vm_flags & VM_LOCKED) &&
+			    !compaction_allow_unevictable() &&
+			    softleaf_is_migration(softleaf_from_pmd(*pmd)))) {
+				spin_unlock(ptl);
+				pmd_migration_entry_wait(vma->vm_mm, pmd);
+				walk->action = ACTION_AGAIN;
+				return 0;
+			}
 			goto out;
+		}
 		if (is_huge_zero_pmd(*pmd))
 			goto out;
 		folio = pmd_folio(*pmd);
@@ -383,8 +393,17 @@ static int mlock_pte_range(pmd_t *pmd, unsigned long addr,
 
 	for (pte = start_pte; addr != end; pte++, addr += PAGE_SIZE) {
 		ptent = ptep_get(pte);
-		if (!pte_present(ptent))
+		if (!pte_present(ptent)) {
+			if (unlikely((vma->vm_flags & VM_LOCKED) &&
+			    !compaction_allow_unevictable() &&
+			    softleaf_is_migration(softleaf_from_pte(ptent)))) {
+				pte_unmap_unlock(start_pte, ptl);
+				migration_entry_wait(vma->vm_mm, pmd, addr);
+				walk->action = ACTION_AGAIN;
+				return 0;
+			}
 			continue;
+		}
 		folio = vm_normal_folio(vma, addr, ptent);
 		if (!folio || folio_is_zone_device(folio))
 			continue;
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 3/4] mm/migrate: add tracepoint for folios unmapped during migration
From: Wandun Chen @ 2026-07-07 12:59 UTC (permalink / raw)
  To: vbabka, david, rostedt, mhiramat, Alexander.Krabler, hughd, fvdl,
	bigeasy, linux-mm, linux-kernel, linux-trace-kernel,
	linux-rt-devel
  Cc: akpm, surenb, mhocko, jackmanb, hannes, ziy, ljs, riel, liam,
	harry, jannh, lance.yang, mathieu.desnoyers, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
	pfalcato
In-Reply-To: <20260707125925.3725177-1-chenwandun1@gmail.com>

From: Wandun Chen <chenwandun@lixiang.com>

Add mm_migrate_unmap_folio tracepoint, fired in try_to_migrate_one()
after a folio's mapping has been replaced by a migration entry.
It records the pfn, address, folio flags and vm_flags, making mlocked
folios under migration easy to observe.

Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
---
 include/trace/events/migrate.h | 29 +++++++++++++++++++++++++++++
 mm/rmap.c                      |  4 ++++
 2 files changed, 33 insertions(+)

diff --git a/include/trace/events/migrate.h b/include/trace/events/migrate.h
index 15ee2ef201b5..1264593ecaee 100644
--- a/include/trace/events/migrate.h
+++ b/include/trace/events/migrate.h
@@ -6,6 +6,7 @@
 #define _TRACE_MIGRATE_H
 
 #include <linux/tracepoint.h>
+#include <trace/events/mmflags.h>
 
 #define MIGRATE_MODE						\
 	EM( MIGRATE_ASYNC,	"MIGRATE_ASYNC")		\
@@ -137,6 +138,34 @@ DEFINE_EVENT(migration_pte, set_migration_pte,
 	TP_ARGS(addr, pte, order)
 );
 
+TRACE_EVENT(mm_migrate_unmap_folio,
+
+	TP_PROTO(unsigned long pfn, unsigned long addr,
+		 unsigned long page_flags, unsigned long vm_flags),
+
+	TP_ARGS(pfn, addr, page_flags, vm_flags),
+
+	TP_STRUCT__entry(
+		__field(unsigned long, pfn)
+		__field(unsigned long, addr)
+		__field(unsigned long, page_flags)
+		__field(unsigned long, vm_flags)
+	),
+
+	TP_fast_assign(
+		__entry->pfn		= pfn;
+		__entry->addr		= addr;
+		__entry->page_flags	= page_flags;
+		__entry->vm_flags	= vm_flags;
+	),
+
+	TP_printk("pfn=0x%lx addr=0x%lx page_flags=%s vm_flags=%s",
+		__entry->pfn,
+		__entry->addr,
+		show_page_flags(__entry->page_flags & PAGEFLAGS_MASK),
+		show_vma_flags(__entry->vm_flags))
+);
+
 DEFINE_EVENT(migration_pte, remove_migration_pte,
 	TP_PROTO(unsigned long addr, unsigned long pte, int order),
 	TP_ARGS(addr, pte, order)
diff --git a/mm/rmap.c b/mm/rmap.c
index 3cb7f6337d38..b110548bebae 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -2716,6 +2716,10 @@ static bool try_to_migrate_one(struct folio *folio, struct vm_area_struct *vma,
 			hugetlb_remove_rmap(folio);
 		else
 			folio_remove_rmap_pte(folio, subpage, vma);
+
+		trace_mm_migrate_unmap_folio(folio_pfn(folio), address,
+					     folio->flags.f, vma->vm_flags);
+
 		if (vma->vm_flags & VM_LOCKED)
 			mlock_drain_local();
 		folio_put(folio);
-- 
2.43.0


^ permalink raw reply related

* [PATCH v2 4/4] mm/mlock: migrate folios out of CMA when mlocking a range
From: Wandun Chen @ 2026-07-07 12:59 UTC (permalink / raw)
  To: vbabka, david, rostedt, mhiramat, Alexander.Krabler, hughd, fvdl,
	bigeasy, linux-mm, linux-kernel, linux-trace-kernel,
	linux-rt-devel
  Cc: akpm, surenb, mhocko, jackmanb, hannes, ziy, ljs, riel, liam,
	harry, jannh, lance.yang, mathieu.desnoyers, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
	pfalcato
In-Reply-To: <20260707125925.3725177-1-chenwandun1@gmail.com>

From: Wandun Chen <chenwandun@lixiang.com>

The region covered by mlock[all] may contain CMA pages. cma_alloc installs
migration entries in the page table, if a memory access occurs at this
point, it must wait for the migration to complete, which may cause
latency spikes on the RT kernels.

Try to move the migration cost into the mlock[all] caller, which is
typically a setup path. So reduce the chance of latency spikes on RT
kernels by migrating the currently mapped CMA pages out of CMA region.

Suggested-by: Frank van der Linden <fvdl@google.com>
Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
Link: https://lore.kernel.org/all/CAPTztWZpnX1j8-7yeppVUsxE=O9hbVeqricDjZt8_pnN7a-kBQ@mail.gmail.com/#t
---
 mm/mlock.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 118 insertions(+), 1 deletion(-)

diff --git a/mm/mlock.c b/mm/mlock.c
index ac65de40b22b..f56c685533f5 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -25,6 +25,7 @@
 #include <linux/memcontrol.h>
 #include <linux/mm_inline.h>
 #include <linux/secretmem.h>
+#include <linux/migrate.h>
 #include <linux/compaction.h>
 
 #include "internal.h"
@@ -428,6 +429,119 @@ static int mlock_pte_range(pmd_t *pmd, unsigned long addr,
 	return 0;
 }
 
+#ifdef CONFIG_CMA
+static int mlock_collect_migratable_pte_range(pmd_t *pmd, unsigned long addr,
+			unsigned long end, struct mm_walk *walk)
+{
+	struct vm_area_struct *vma = walk->vma;
+	struct list_head *folio_list = walk->private;
+	spinlock_t *ptl;
+	pte_t *start_pte, *pte;
+	pte_t ptent;
+	struct folio *folio;
+	unsigned int step = 1;
+
+	if (!(vma->vm_flags & VM_LOCKED))
+		return 0;
+
+	ptl = pmd_trans_huge_lock(pmd, vma);
+	if (ptl) {
+		if (!pmd_present(*pmd)) {
+			if (unlikely(softleaf_is_migration(softleaf_from_pmd(*pmd)))) {
+				spin_unlock(ptl);
+				pmd_migration_entry_wait(vma->vm_mm, pmd);
+				walk->action = ACTION_AGAIN;
+				return 0;
+			}
+			goto out;
+		}
+		if (is_huge_zero_pmd(*pmd))
+			goto out;
+		folio = pmd_folio(*pmd);
+		if (folio_is_zone_device(folio))
+			goto out;
+		if (is_migrate_cma_page(&folio->page))
+			isolate_folio_to_list(folio, folio_list);
+		goto out;
+	}
+
+	start_pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
+	if (!start_pte) {
+		walk->action = ACTION_AGAIN;
+		return 0;
+	}
+
+	for (pte = start_pte; addr != end; pte += step, addr += step * PAGE_SIZE) {
+		step = 1;
+		ptent = ptep_get(pte);
+		if (!pte_present(ptent)) {
+			if (unlikely(softleaf_is_migration(softleaf_from_pte(ptent)))) {
+				pte_unmap_unlock(start_pte, ptl);
+				migration_entry_wait(vma->vm_mm, pmd, addr);
+				walk->action = ACTION_AGAIN;
+				return 0;
+			}
+			continue;
+		}
+		folio = vm_normal_folio(vma, addr, ptent);
+		if (!folio || folio_is_zone_device(folio))
+			continue;
+		step = folio_mlock_step(folio, pte, addr, end);
+		if (is_migrate_cma_page(&folio->page))
+			continue;
+		isolate_folio_to_list(folio, folio_list);
+	}
+	pte_unmap(start_pte);
+out:
+	spin_unlock(ptl);
+	cond_resched();
+	return 0;
+}
+
+static const struct mm_walk_ops mlock_collect_migratable_ops = {
+	.pmd_entry	= mlock_collect_migratable_pte_range,
+	.walk_lock	= PGWALK_RDLOCK,
+};
+
+static void mlock_migrate_cma_range(unsigned long start, unsigned long len)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long end = start + len;
+	LIST_HEAD(folio_list);
+	struct migration_target_control mtc = {
+		.nid = NUMA_NO_NODE,
+		.gfp_mask = GFP_HIGHUSER | __GFP_NOWARN,
+		.reason = MR_SYSCALL,
+	};
+
+	if (compaction_allow_unevictable())
+		return;
+
+	lru_cache_disable();
+
+	if (mmap_read_lock_killable(mm))
+		goto out;
+
+	walk_page_range(mm, start, end, &mlock_collect_migratable_ops,
+			&folio_list);
+	mmap_read_unlock(mm);
+
+	if (list_empty(&folio_list))
+		goto out;
+
+	if (migrate_pages(&folio_list, alloc_migration_target, NULL,
+			  (unsigned long)&mtc, MIGRATE_SYNC, MR_SYSCALL, NULL))
+		putback_movable_pages(&folio_list);
+out:
+	lru_cache_enable();
+}
+#else
+static inline void mlock_migrate_cma_range(unsigned long start,
+					   unsigned long len)
+{
+}
+#endif /* CONFIG_CMA */
+
 /*
  * mlock_vma_pages_range() - mlock any pages already in the range,
  *                           or munlock all pages in the range.
@@ -678,6 +792,7 @@ static __must_check int do_mlock(unsigned long start, size_t len, vm_flags_t fla
 	error = __mm_populate(start, len, 0);
 	if (error)
 		return __mlock_posix_error_return(error);
+	mlock_migrate_cma_range(start, len);
 	return 0;
 }
 
@@ -790,8 +905,10 @@ SYSCALL_DEFINE1(mlockall, int, flags)
 	    capable(CAP_IPC_LOCK))
 		ret = apply_mlockall_flags(flags);
 	mmap_write_unlock(current->mm);
-	if (!ret && (flags & MCL_CURRENT))
+	if (!ret && (flags & MCL_CURRENT)) {
 		mm_populate(0, TASK_SIZE);
+		mlock_migrate_cma_range(0, TASK_SIZE);
+	}
 
 	return ret;
 }
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH v3 04/11] arm64/mm: Add set_memory_device() and set_memory_normal()
From: Robin Murphy @ 2026-07-07 13:17 UTC (permalink / raw)
  To: Will Deacon, Thierry Reding
  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, 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: <akzikTrmhMsvkNVY@willie-the-truck>

On 07/07/2026 12:27 pm, 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?

Given the precedent of memblock_mark_nomap(), as long as the reusable 
reserved-memory regions also get split into distinct memblocks, then it 
seems like in principle we ought to be able to give them a new 
MEMBLOCK_PTEMAP (or whatever) flag which could then be picked up in 
map_mem() without needing to override force_pte_mapping() globally?

Cheers,
Robin.

^ permalink raw reply

* Re: [PATCH 2/2] tracing/synthetic: Free type string on error path
From: Yu Peng @ 2026-07-07 13:22 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: Masami Hiramatsu, Mathieu Desnoyers, linux-trace-kernel,
	linux-kernel
In-Reply-To: <20260706131534.70e602ef@gandalf.local.home>

On 7/7/2026 1:15 AM, Steven Rostedt wrote:

> Can you do this instead?
> 
> diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c
> index cdd5b9332835..7ff0f00edbdd 100644
> --- a/kernel/trace/trace_events_synth.c
> +++ b/kernel/trace/trace_events_synth.c
> @@ -828,7 +828,7 @@ static struct synth_field *parse_synth_field(int argc, char **argv,
>   	} else if (size == 0) {
>   		if (synth_field_is_string(field->type) ||
>   		    synth_field_is_stack(field->type)) {
> -			char *type;
> +			char *type __free(kfree) = NULL;
>   
>   			len = sizeof("__data_loc ") + strlen(field->type) + 1;
>   			type = kzalloc(len, GFP_KERNEL);
> @@ -844,7 +844,7 @@ static struct synth_field *parse_synth_field(int argc, char **argv,
>   			s.buffer[s.len] = '\0';
>   
>   			kfree(field->type);
> -			field->type = type;
> +			field->type = no_free_ptr(type);
>   
>   			field->is_dynamic = true;
>   			size = sizeof(u64);
> 
> -- Steve

Yes, that looks better. I'll fold it into v2.

Thanks,
Yu Peng

^ permalink raw reply

* [PATCH v2] tracing/synthetic: Free type string on error path
From: Yu Peng @ 2026-07-07 13:24 UTC (permalink / raw)
  To: rostedt
  Cc: mhiramat, mathieu.desnoyers, linux-trace-kernel, linux-kernel,
	Yu Peng

parse_synth_field() builds a "__data_loc ..." type string before
assigning it to field->type. If the seq_buf check fails, the temporary
string is not owned by field and is leaked. Free it before leaving.

Suggested-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Yu Peng <pengyu@kylinos.cn>
---
Changes in v2:
- Use __free(kfree) and no_free_ptr() as suggested by Steven.

 kernel/trace/trace_events_synth.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/trace_events_synth.c b/kernel/trace/trace_events_synth.c
index e6871230bde96..ad2e70258291b 100644
--- a/kernel/trace/trace_events_synth.c
+++ b/kernel/trace/trace_events_synth.c
@@ -828,7 +828,7 @@ static struct synth_field *parse_synth_field(int argc, char **argv,
 	} else if (size == 0) {
 		if (synth_field_is_string(field->type) ||
 		    synth_field_is_stack(field->type)) {
-			char *type;
+			char *type __free(kfree) = NULL;
 
 			len = sizeof("__data_loc ") + strlen(field->type) + 1;
 			type = kzalloc(len, GFP_KERNEL);
@@ -844,7 +844,7 @@ static struct synth_field *parse_synth_field(int argc, char **argv,
 			s.buffer[s.len] = '\0';
 
 			kfree(field->type);
-			field->type = type;
+			field->type = no_free_ptr(type);
 
 			field->is_dynamic = true;
 			size = sizeof(u64);
-- 
2.43.0

^ permalink raw reply related

* Re: [PATCH v2 4/4] mm/mlock: migrate folios out of CMA when mlocking a range
From: Wandun @ 2026-07-07 13:36 UTC (permalink / raw)
  To: vbabka, david, rostedt, mhiramat, Alexander.Krabler, hughd, fvdl,
	bigeasy, linux-mm, linux-kernel, linux-trace-kernel,
	linux-rt-devel
  Cc: akpm, surenb, mhocko, jackmanb, hannes, ziy, ljs, riel, liam,
	harry, jannh, lance.yang, mathieu.desnoyers, matthew.brost,
	joshua.hahnjy, rakie.kim, byungchul, gourry, ying.huang, apopple,
	pfalcato
In-Reply-To: <20260707125925.3725177-5-chenwandun1@gmail.com>



On 7/7/26 20:59, Wandun Chen wrote:
> From: Wandun Chen <chenwandun@lixiang.com>
> 
> The region covered by mlock[all] may contain CMA pages. cma_alloc installs
> migration entries in the page table, if a memory access occurs at this
> point, it must wait for the migration to complete, which may cause
> latency spikes on the RT kernels.
> 
> Try to move the migration cost into the mlock[all] caller, which is
> typically a setup path. So reduce the chance of latency spikes on RT
> kernels by migrating the currently mapped CMA pages out of CMA region.
> 
> Suggested-by: Frank van der Linden <fvdl@google.com>
> Signed-off-by: Wandun Chen <chenwandun@lixiang.com>
> Link: https://lore.kernel.org/all/CAPTztWZpnX1j8-7yeppVUsxE=O9hbVeqricDjZt8_pnN7a-kBQ@mail.gmail.com/#t
> ---
>  mm/mlock.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 118 insertions(+), 1 deletion(-)
> 
> diff --git a/mm/mlock.c b/mm/mlock.c
> index ac65de40b22b..f56c685533f5 100644
> --- a/mm/mlock.c
> +++ b/mm/mlock.c
> @@ -25,6 +25,7 @@
>  #include <linux/memcontrol.h>
>  #include <linux/mm_inline.h>
>  #include <linux/secretmem.h>
> +#include <linux/migrate.h>
>  #include <linux/compaction.h>
>  
>  #include "internal.h"
> @@ -428,6 +429,119 @@ static int mlock_pte_range(pmd_t *pmd, unsigned long addr,
>  	return 0;
>  }
>  
> +#ifdef CONFIG_CMA
> +static int mlock_collect_migratable_pte_range(pmd_t *pmd, unsigned long addr,
> +			unsigned long end, struct mm_walk *walk)
> +{
> +	struct vm_area_struct *vma = walk->vma;
> +	struct list_head *folio_list = walk->private;
> +	spinlock_t *ptl;
> +	pte_t *start_pte, *pte;
> +	pte_t ptent;
> +	struct folio *folio;
> +	unsigned int step = 1;
> +
> +	if (!(vma->vm_flags & VM_LOCKED))
> +		return 0;
> +
> +	ptl = pmd_trans_huge_lock(pmd, vma);
> +	if (ptl) {
> +		if (!pmd_present(*pmd)) {
> +			if (unlikely(softleaf_is_migration(softleaf_from_pmd(*pmd)))) {
> +				spin_unlock(ptl);
> +				pmd_migration_entry_wait(vma->vm_mm, pmd);
> +				walk->action = ACTION_AGAIN;
> +				return 0;
> +			}
> +			goto out;
> +		}
> +		if (is_huge_zero_pmd(*pmd))
> +			goto out;
> +		folio = pmd_folio(*pmd);
> +		if (folio_is_zone_device(folio))
> +			goto out;
> +		if (is_migrate_cma_page(&folio->page))
> +			isolate_folio_to_list(folio, folio_list);
> +		goto out;
> +	}
> +
> +	start_pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
> +	if (!start_pte) {
> +		walk->action = ACTION_AGAIN;
> +		return 0;
> +	}
> +
> +	for (pte = start_pte; addr != end; pte += step, addr += step * PAGE_SIZE) {
> +		step = 1;
> +		ptent = ptep_get(pte);
> +		if (!pte_present(ptent)) {
> +			if (unlikely(softleaf_is_migration(softleaf_from_pte(ptent)))) {
> +				pte_unmap_unlock(start_pte, ptl);
> +				migration_entry_wait(vma->vm_mm, pmd, addr);
> +				walk->action = ACTION_AGAIN;
> +				return 0;
> +			}
> +			continue;
> +		}
> +		folio = vm_normal_folio(vma, addr, ptent);
> +		if (!folio || folio_is_zone_device(folio))
> +			continue;
> +		step = folio_mlock_step(folio, pte, addr, end);
> +		if (is_migrate_cma_page(&folio->page))
Here should be, sorry about this.
	if (!is_migrate_cma_page(&folio->page))
		continue;

Best regards
Wandun
> +			continue;
> +		isolate_folio_to_list(folio, folio_list);
> +	}
> +	pte_unmap(start_pte);
> +out:
> +	spin_unlock(ptl);
> +	cond_resched();
> +	return 0;
> +}
> +
> +static const struct mm_walk_ops mlock_collect_migratable_ops = {
> +	.pmd_entry	= mlock_collect_migratable_pte_range,
> +	.walk_lock	= PGWALK_RDLOCK,
> +};
> +
> +static void mlock_migrate_cma_range(unsigned long start, unsigned long len)
> +{
> +	struct mm_struct *mm = current->mm;
> +	unsigned long end = start + len;
> +	LIST_HEAD(folio_list);
> +	struct migration_target_control mtc = {
> +		.nid = NUMA_NO_NODE,
> +		.gfp_mask = GFP_HIGHUSER | __GFP_NOWARN,
> +		.reason = MR_SYSCALL,
> +	};
> +
> +	if (compaction_allow_unevictable())
> +		return;
> +
> +	lru_cache_disable();
> +
> +	if (mmap_read_lock_killable(mm))
> +		goto out;
> +
> +	walk_page_range(mm, start, end, &mlock_collect_migratable_ops,
> +			&folio_list);
> +	mmap_read_unlock(mm);
> +
> +	if (list_empty(&folio_list))
> +		goto out;
> +
> +	if (migrate_pages(&folio_list, alloc_migration_target, NULL,
> +			  (unsigned long)&mtc, MIGRATE_SYNC, MR_SYSCALL, NULL))
> +		putback_movable_pages(&folio_list);
> +out:
> +	lru_cache_enable();
> +}
> +#else
> +static inline void mlock_migrate_cma_range(unsigned long start,
> +					   unsigned long len)
> +{
> +}
> +#endif /* CONFIG_CMA */
> +
>  /*
>   * mlock_vma_pages_range() - mlock any pages already in the range,
>   *                           or munlock all pages in the range.
> @@ -678,6 +792,7 @@ static __must_check int do_mlock(unsigned long start, size_t len, vm_flags_t fla
>  	error = __mm_populate(start, len, 0);
>  	if (error)
>  		return __mlock_posix_error_return(error);
> +	mlock_migrate_cma_range(start, len);
>  	return 0;
>  }
>  
> @@ -790,8 +905,10 @@ SYSCALL_DEFINE1(mlockall, int, flags)
>  	    capable(CAP_IPC_LOCK))
>  		ret = apply_mlockall_flags(flags);
>  	mmap_write_unlock(current->mm);
> -	if (!ret && (flags & MCL_CURRENT))
> +	if (!ret && (flags & MCL_CURRENT)) {
>  		mm_populate(0, TASK_SIZE);
> +		mlock_migrate_cma_range(0, TASK_SIZE);
> +	}
>  
>  	return ret;
>  }


^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox