Linux Documentation
 help / color / mirror / Atom feed
* [PATCH v9 06/10] x86/hw_breakpoint: Add arch_reinstall_hw_breakpoint
From: Masami Hiramatsu (Google) @ 2026-07-17 14:20 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra, Ingo Molnar, x86
  Cc: Jinchao Wang, Mathieu Desnoyers, Masami Hiramatsu,
	Thomas Gleixner, Borislav Petkov, Dave Hansen, H . Peter Anvin,
	Alexander Shishkin, Ian Rogers, linux-kernel, linux-trace-kernel,
	linux-doc, linux-perf-users
In-Reply-To: <178429796992.157981.3393977217853767915.stgit@devnote2>

From: Jinchao Wang <wangjinchao600@gmail.com>

The new arch_reinstall_hw_breakpoint() function can be used in an
atomic context, unlike the more expensive free and re-allocation path.
This allows callers to efficiently re-establish an existing breakpoint.

Signed-off-by: Jinchao Wang <wangjinchao600@gmail.com>
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 Changes in v9:
  - Update commit message.
  - Temporarily disable the active slot in setup_hwbp() before updating
    the address register to avoid spurious debug exceptions.
---
 arch/x86/include/asm/hw_breakpoint.h |    2 ++
 arch/x86/kernel/hw_breakpoint.c      |   34 ++++++++++++++++++++++++++++------
 2 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/hw_breakpoint.h b/arch/x86/include/asm/hw_breakpoint.h
index aa6adac6c3a2..c22cc4e87fc5 100644
--- a/arch/x86/include/asm/hw_breakpoint.h
+++ b/arch/x86/include/asm/hw_breakpoint.h
@@ -21,6 +21,7 @@ struct arch_hw_breakpoint {
 
 enum bp_slot_action {
 	BP_SLOT_ACTION_INSTALL,
+	BP_SLOT_ACTION_REINSTALL,
 	BP_SLOT_ACTION_UNINSTALL,
 };
 
@@ -65,6 +66,7 @@ extern int hw_breakpoint_exceptions_notify(struct notifier_block *unused,
 
 
 int arch_install_hw_breakpoint(struct perf_event *bp);
+int arch_reinstall_hw_breakpoint(struct perf_event *bp);
 void arch_uninstall_hw_breakpoint(struct perf_event *bp);
 void hw_breakpoint_pmu_read(struct perf_event *bp);
 void hw_breakpoint_pmu_unthrottle(struct perf_event *bp);
diff --git a/arch/x86/kernel/hw_breakpoint.c b/arch/x86/kernel/hw_breakpoint.c
index c323c2aab2af..0df3ff556f47 100644
--- a/arch/x86/kernel/hw_breakpoint.c
+++ b/arch/x86/kernel/hw_breakpoint.c
@@ -100,6 +100,10 @@ static int manage_bp_slot(struct perf_event *bp, enum bp_slot_action action)
 		old_bp = NULL;
 		new_bp = bp;
 		break;
+	case BP_SLOT_ACTION_REINSTALL:
+		old_bp = bp;
+		new_bp = bp;
+		break;
 	case BP_SLOT_ACTION_UNINSTALL:
 		old_bp = bp;
 		new_bp = NULL;
@@ -129,23 +133,36 @@ static int manage_bp_slot(struct perf_event *bp, enum bp_slot_action action)
 static void setup_hwbp(struct arch_hw_breakpoint *info, int slot, bool enable)
 {
 	unsigned long dr7;
-
-	set_debugreg(info->address, slot);
-	__this_cpu_write(cpu_debugreg[slot], info->address);
+	bool enabled;
 
 	dr7 = this_cpu_read(cpu_dr7);
+	enabled = dr7 & ((DR_LOCAL_ENABLE | DR_GLOBAL_ENABLE) << (slot * DR_ENABLE_SIZE));
 	dr7 &= ~(__encode_dr7(slot, 0xc, 0x3) |
 		 (DR_LOCAL_ENABLE << (slot * DR_ENABLE_SIZE)));
-	if (enable)
-		dr7 |= encode_dr7(slot, info->len, info->type);
+
+	/*
+	 * If the slot is currently enabled, disable it first before updating
+	 * the address register to prevent spurious debug exceptions.
+	 */
+	if (enable && enabled) {
+		barrier();
+		set_debugreg(dr7, 7);
+		barrier();
+		this_cpu_write(cpu_dr7, dr7);
+	}
+
+	set_debugreg(info->address, slot);
+	__this_cpu_write(cpu_debugreg[slot], info->address);
 
 	/*
 	 * Enabling:
 	 *   Ensure we first write cpu_dr7 before we set the DR7 register.
 	 *   This ensures an NMI never see cpu_dr7 0 when DR7 is not.
 	 */
-	if (enable)
+	if (enable) {
+		dr7 |= encode_dr7(slot, info->len, info->type);
 		this_cpu_write(cpu_dr7, dr7);
+	}
 
 	barrier();
 
@@ -189,6 +206,11 @@ int arch_install_hw_breakpoint(struct perf_event *bp)
 	return arch_manage_bp(bp, BP_SLOT_ACTION_INSTALL);
 }
 
+int arch_reinstall_hw_breakpoint(struct perf_event *bp)
+{
+	return arch_manage_bp(bp, BP_SLOT_ACTION_REINSTALL);
+}
+
 void arch_uninstall_hw_breakpoint(struct perf_event *bp)
 {
 	arch_manage_bp(bp, BP_SLOT_ACTION_UNINSTALL);


^ permalink raw reply related

* [PATCH v9 07/10] HWBP: Add modify_wide_hw_breakpoint_local() API
From: Masami Hiramatsu (Google) @ 2026-07-17 14:20 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra, Ingo Molnar, x86
  Cc: Jinchao Wang, Mathieu Desnoyers, Masami Hiramatsu,
	Thomas Gleixner, Borislav Petkov, Dave Hansen, H . Peter Anvin,
	Alexander Shishkin, Ian Rogers, linux-kernel, linux-trace-kernel,
	linux-doc, linux-perf-users
In-Reply-To: <178429796992.157981.3393977217853767915.stgit@devnote2>

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Add modify_wide_hw_breakpoint_local() arch-wide interface which allows
hwbp users to update watch address on-line. This is available if the
arch supports CONFIG_HAVE_REINSTALL_HW_BREAKPOINT.
Note that this allows to change the type only for compatible types,
because it does not release and reserve the hwbp slot based on type.
For instance, you can not change HW_BREAKPOINT_W to HW_BREAKPOINT_X.

Assisted-by: Antigravity:gemini-3.5-flash
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 Changes in v9:
  - Add lockdep_assert_irqs_disabled() to enforce and document the
    interrupt-disabled calling context requirement.
  - Implement state rollback logic in modify_wide_hw_breakpoint_local()
    to prevent inconsistent state on architecture update failure.
 Changes in v8:
  - Parse new attributes into a temporary struct arch_hw_breakpoint
    copy to prevent in-place mutation and corruption on parse error paths.
  - Synchronize logical perf_event attributes by updating
   bp->attr.bp_type and bp->attr.bp_len in modify_wide_hw_breakpoint_local().
 Changes in v7:
  - Update bp->attr.bp_attr so that we can correctly check the
    address on it.
  - Use -EOPNOTSUPP instead of -ENOSYS.
 Changes in v4:
  - Update kerneldoc comment about modify_wide_hw_breakpoint_local
    according to Randy's comment.
 Changes in v2:
  - Check type compatibility by checking slot. (Thanks Jinchao!)
---
 arch/Kconfig                  |   10 +++++++
 arch/x86/Kconfig              |    1 +
 include/linux/hw_breakpoint.h |    6 ++++
 kernel/events/hw_breakpoint.c |   61 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 78 insertions(+)

diff --git a/arch/Kconfig b/arch/Kconfig
index 959aee9568ff..4a87e843bb4c 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -467,6 +467,16 @@ config HAVE_POST_BREAKPOINT_HOOK
 	  Select this option if your arch implements breakpoints overflow
 	  handler hooks after the target memory is modified.
 
+config HAVE_REINSTALL_HW_BREAKPOINT
+	bool
+	depends on HAVE_HW_BREAKPOINT
+	help
+	  Depending on the arch implementation of hardware breakpoints,
+	  some of them are able to update the breakpoint configuration
+	  without release and reserve the hardware breakpoint register.
+	  What configuration is able to update depends on hardware and
+	  software implementation.
+
 config HAVE_USER_RETURN_NOTIFIER
 	bool
 
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 6b7e14ef8cfb..588218da8f41 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -247,6 +247,7 @@ config X86
 	select HAVE_GCC_PLUGINS
 	select HAVE_HW_BREAKPOINT
 	select HAVE_POST_BREAKPOINT_HOOK
+	select HAVE_REINSTALL_HW_BREAKPOINT
 	select HAVE_IOREMAP_PROT
 	select HAVE_IRQ_EXIT_ON_IRQ_STACK	if X86_64
 	select HAVE_IRQ_TIME_ACCOUNTING
diff --git a/include/linux/hw_breakpoint.h b/include/linux/hw_breakpoint.h
index db199d653dd1..6754ffbee9ed 100644
--- a/include/linux/hw_breakpoint.h
+++ b/include/linux/hw_breakpoint.h
@@ -81,6 +81,9 @@ register_wide_hw_breakpoint(struct perf_event_attr *attr,
 			    perf_overflow_handler_t triggered,
 			    void *context);
 
+extern int modify_wide_hw_breakpoint_local(struct perf_event *bp,
+					   struct perf_event_attr *attr);
+
 extern int register_perf_hw_breakpoint(struct perf_event *bp);
 extern void unregister_hw_breakpoint(struct perf_event *bp);
 extern void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events);
@@ -124,6 +127,9 @@ register_wide_hw_breakpoint(struct perf_event_attr *attr,
 			    perf_overflow_handler_t triggered,
 			    void *context)		{ return NULL; }
 static inline int
+modify_wide_hw_breakpoint_local(struct perf_event *bp,
+				struct perf_event_attr *attr) { return -EOPNOTSUPP; }
+static inline int
 register_perf_hw_breakpoint(struct perf_event *bp)	{ return -ENOSYS; }
 static inline void unregister_hw_breakpoint(struct perf_event *bp)	{ }
 static inline void
diff --git a/kernel/events/hw_breakpoint.c b/kernel/events/hw_breakpoint.c
index 789add0c185a..63570a5079bf 100644
--- a/kernel/events/hw_breakpoint.c
+++ b/kernel/events/hw_breakpoint.c
@@ -888,6 +888,67 @@ void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events)
 }
 EXPORT_SYMBOL_GPL(unregister_wide_hw_breakpoint);
 
+/**
+ * modify_wide_hw_breakpoint_local - update breakpoint config for local CPU
+ * @bp: the hwbp perf event for this CPU
+ * @attr: the new attribute for @bp
+ *
+ * This does not release and reserve the slot of a HWBP; it just reuses the
+ * current slot on local CPU. So the users must update the other CPUs by
+ * themselves.
+ * Also, since this does not release/reserve the slot, this can not change the
+ * type to incompatible type of the HWBP.
+ * Return err if attr is invalid or the CPU fails to update debug register
+ * for new @attr.
+ */
+#ifdef CONFIG_HAVE_REINSTALL_HW_BREAKPOINT
+int modify_wide_hw_breakpoint_local(struct perf_event *bp,
+				    struct perf_event_attr *attr)
+{
+	struct arch_hw_breakpoint info, old_info;
+	unsigned long old_addr;
+	unsigned int old_type, old_len;
+	int ret;
+
+	lockdep_assert_irqs_disabled();
+
+	if (find_slot_idx(bp->attr.bp_type) != find_slot_idx(attr->bp_type))
+		return -EINVAL;
+
+	ret = hw_breakpoint_arch_parse(bp, attr, &info);
+	if (ret)
+		return ret;
+
+	old_info = *counter_arch_bp(bp);
+	old_addr = bp->attr.bp_addr;
+	old_type = bp->attr.bp_type;
+	old_len = bp->attr.bp_len;
+
+	*counter_arch_bp(bp) = info;
+	bp->attr.bp_addr = attr->bp_addr;
+	bp->attr.bp_type = attr->bp_type;
+	bp->attr.bp_len = attr->bp_len;
+
+	ret = arch_reinstall_hw_breakpoint(bp);
+	if (ret) {
+		/* Rollback to the original state */
+		*counter_arch_bp(bp) = old_info;
+		bp->attr.bp_addr = old_addr;
+		bp->attr.bp_type = old_type;
+		bp->attr.bp_len = old_len;
+	}
+
+	return ret;
+}
+#else
+int modify_wide_hw_breakpoint_local(struct perf_event *bp,
+				    struct perf_event_attr *attr)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+EXPORT_SYMBOL_GPL(modify_wide_hw_breakpoint_local);
+
 /**
  * hw_breakpoint_is_used - check if breakpoints are currently used
  *


^ permalink raw reply related

* [PATCH v9 08/10] tracing: wprobe: Add wprobe event trigger
From: Masami Hiramatsu (Google) @ 2026-07-17 14:21 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra, Ingo Molnar, x86
  Cc: Jinchao Wang, Mathieu Desnoyers, Masami Hiramatsu,
	Thomas Gleixner, Borislav Petkov, Dave Hansen, H . Peter Anvin,
	Alexander Shishkin, Ian Rogers, linux-kernel, linux-trace-kernel,
	linux-doc, linux-perf-users
In-Reply-To: <178429796992.157981.3393977217853767915.stgit@devnote2>

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Add wprobe event trigger to set and clear the watch event dynamically.
This allows us to set an watchpoint on a given local variables and
a slab object instead of static objects.

The trigger syntax is below:

  - set_wprobe:WPROBE:FIELD[+OFFSET] [if FILTER]
  - clear_wprobe:WPROBE[:FIELD[+OFFSET]] [if FILTER]

set_wprobe sets the address pointed by FIELD[+offset] to the WPROBE
event. The FIELD is the field name of trigger event.
clear_wprobe clears the watch address of WPROBE event. If the FIELD
option is specified, it clears only if the current watch address is
same as the given FIELD[+OFFSET] value.

The set_wprobe trigger does not change the type and length, these
must be set when creating a new wprobe.

Also, the WPROBE event must be disabled when setting the new trigger
and it will be busy afterwards. Recommended usage is to add a new
wprobe at NULL address and keep disabled.

Assisted-by: Antigravity:gemini-3.5-flash
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 Changes in v9:
  - Make event_trigger_free() non-static to solve build dependency.
  - Sync irq_work and work inside __unregister_trace_wprobe() before
    clearing tw->bp_event to prevent concurrent NULL pointer dereference.
  - Introduce private_free destructor in struct event_trigger_data to
    safely release wprobe_trigger_data after tracepoint readers exit.
  - Fix filter memory leak in wprobe_trigger_cmd_parse() on the error
    handling path of trace_event_try_get_ref() failure.
  - Avoid overwriting tw->addr on clear_wprobe trigger registration to
    prevent active watchpoint corruption and hardware breakpoint leak.
 Changes in v8:
  - Redesign wprobe_trigger() to be safe in NMI/hardirq contexts by
    deferring register updates to a workqueue via irq_work.
  - Skip trigger execution and increment an atomic missed count
    (tw->missed) if the tracepoint runs in NMI context to prevent
    recursive spinlock deadlocks. (this is currently hidden counter)
  - Prohibit attaching wprobe triggers to kprobe_events by checking
    TRACE_EVENT_FL_KPROBE in wprobe_trigger_cmd_parse().
  - Use call_rcu() in trigger deactivation path and add
    synchronize_rcu() in parse failure path to ensure safe RCU
    lifetime cleanup.
  - Acquire the target tracepoint's module reference via
   trace_event_try_get_ref() to prevent module refcount underflows.
  - Fix event_trigger_data memory leak by properly freeing the
    initial refcount in wprobe_trigger_cmd_parse() on success.
  - Call on_each_cpu() with wait=true in wprobe_work_func() to
    prevent use-after-free during trigger unregistration.
  - Synchronize concurrent wprobe triggers on the same event by
    using a shared raw spinlock (tw->lock).
  - Drop the support of kprobe events (that should be done later).
 Changes in v7:
  - Use kzalloc_obj().
  - Update sample code in document.
 Changes in v6:
  - Update according to the latest change of trigger ops.
 Changes in v5:
  - Following the suggestions, the documentation was revised to suit rst.
 Changes in v3:
  - Add FIELD option support for clear_wprobe and update document.
  - Fix to unregister/free event_trigger_data on file correctly.
  - Fix syntax comments.
 Changes in v2:
  - Getting local cpu perf_event from trace_wprobe directly.
  - Remove trace_wprobe_local_perf() because it is conditionally unused.
  - Make CONFIG_WPROBE_TRIGGERS a hidden config.
---
 Documentation/trace/wprobetrace.rst |   93 +++++++
 include/linux/trace_events.h        |    1 
 kernel/trace/Kconfig                |   10 +
 kernel/trace/trace.h                |    2 
 kernel/trace/trace_events_trigger.c |   12 +
 kernel/trace/trace_wprobe.c         |  438 +++++++++++++++++++++++++++++++++++
 6 files changed, 553 insertions(+), 3 deletions(-)

diff --git a/Documentation/trace/wprobetrace.rst b/Documentation/trace/wprobetrace.rst
index eb4f10607530..a4c0f0e676fd 100644
--- a/Documentation/trace/wprobetrace.rst
+++ b/Documentation/trace/wprobetrace.rst
@@ -68,3 +68,96 @@ Here is an example to add a wprobe event on a variable `jiffies`.
            <idle>-0       [000] d.Z1.  717.026373: my_jiffies: (tick_do_update_jiffies64+0xbe/0x130)
 
 You can see the code which writes to `jiffies` is `tick_do_update_jiffies64()`.
+
+Combination with trigger action
+-------------------------------
+The event trigger action can extend the utilization of this wprobe.
+
+- set_wprobe:WPEVENT:FIELD[+|-ADJUST]
+- clear_wprobe:WPEVENT[:FIELD[+|-]ADJUST]
+
+Set these triggers to the target event, then the WPROBE event will be
+setup to trace the memory access at FIELD[+|-ADJUST] address.
+When clear_wprobe is hit, if FIELD is NOT specified, the WPEVENT is
+forcibly cleared. If FIELD[[+|-]ADJUST] is set, it clears WPEVENT only
+if its watching address is the same as the FIELD[[+|-]ADJUST] value.
+
+Notes:
+The set_wprobe trigger does not change the type and length, these
+must be set when creating a new wprobe.
+
+The WPROBE event must be disabled when setting the new trigger
+and it will be busy afterwards. Recommended usage is to add a new
+wprobe at NULL address and keep disabled.
+
+Wprobe triggers are not supported on kprobe_events, because kprobes
+themselves can use software breakpoints which conflicts with wprobe
+operation.
+
+
+For example, trace the first 8 bytes of the dentry data structure passed
+to do_truncate() until it is deleted by dentry_kill().
+(Note: all tracefs setup uses '>>' so that it does not kick do_truncate())
+::
+
+  # echo 'w:watch rw@0:8 address=$addr value=+0($addr)' >> dynamic_events
+  # echo 'f:truncate do_truncate dentry=$arg2' >> dynamic_events
+  # echo 'set_wprobe:watch:dentry' >> events/fprobes/truncate/trigger
+  # echo 'f:dentry_kill dentry_kill dentry=$arg1' >> dynamic_events
+  # echo 'clear_wprobe:watch:dentry' >> events/fprobes/dentry_kill/trigger
+  # echo 1 >> events/fprobes/truncate/enable
+  # echo 1 >> events/fprobes/dentry_kill/enable
+
+  # echo aaa > /tmp/hoge
+  # echo bbb > /tmp/hoge
+  # echo ccc > /tmp/hoge
+  # rm /tmp/hoge
+
+Then, the trace data will show::
+
+ # tracer: nop
+ #
+ # entries-in-buffer/entries-written: 32/32   #P:8
+ #
+ #                                _-----=> irqs-off/BH-disabled
+ #                               / _----=> need-resched
+ #                              | / _---=> hardirq/softirq
+ #                              || / _--=> preempt-depth
+ #                              ||| / _-=> migrate-disable
+ #                              |||| /     delay
+ #           TASK-PID     CPU#  |||||  TIMESTAMP  FUNCTION
+ #              | |         |   |||||     |         |
+               sh-107     [004] ...1.     9.990418: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff888004ad6618
+               sh-107     [004] ...1.     9.990914: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff888004b3de78
+               sh-107     [004] ...1.     9.993175: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff8880049ddd40
+               sh-107     [004] .....     9.995198: truncate: (do_truncate+0x4/0x120) dentry=0xffff8880048083a8
+               sh-107     [004] ...1.     9.995389: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff8880049db998
+               sh-107     [004] ..Zff     9.997503: watch: (lookup_fast+0xaa/0x150) address=0xffff8880048083a8 value=0x8200080
+               sh-107     [004] ..Zff     9.997509: watch: (path_openat+0x211/0xda0) address=0xffff8880048083a8 value=0x8200080
+               sh-107     [004] ..Zff     9.997514: watch: (path_openat+0xa56/0xda0) address=0xffff8880048083a8 value=0x8200080
+               sh-107     [004] ..Zff     9.997518: watch: (path_openat+0xae2/0xda0) address=0xffff8880048083a8 value=0x8200080
+               sh-107     [004] .....     9.997521: truncate: (do_truncate+0x4/0x120) dentry=0xffff8880048083a8
+               sh-107     [004] ...1.     9.997582: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff888004808270
+               sh-107     [004] ...1.     9.999365: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff8880049db728
+               sh-107     [004] ...1.     9.999388: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff888004b1c000
+               rm-113     [005] ..Zff    10.000965: watch: (lookup_fast+0xaa/0x150) address=0xffff8880048083a8 value=0x8200080
+               rm-113     [005] ..Zff    10.000971: watch: (path_lookupat+0x97/0x1e0) address=0xffff8880048083a8 value=0x8200080
+               rm-113     [005] ..Zff    10.000984: watch: (lookup_fast+0xaa/0x150) address=0xffff8880048083a8 value=0x8200080
+               rm-113     [005] ..Zff    10.000988: watch: (path_lookupat+0x97/0x1e0) address=0xffff8880048083a8 value=0x8200080
+               rm-113     [005] ..Zff    10.001010: watch: (lookup_one_qstr_excl+0x28/0x140) address=0xffff8880048083a8 value=0x8200080
+               rm-113     [005] ..Zff    10.001014: watch: (lookup_one_qstr_excl+0xd1/0x140) address=0xffff8880048083a8 value=0x8200080
+               rm-113     [005] ..Zff    10.001018: watch: (may_delete_dentry+0x1c/0x200) address=0xffff8880048083a8 value=0x8200080
+               rm-113     [005] ..Zff    10.001021: watch: (may_delete_dentry+0x195/0x200) address=0xffff8880048083a8 value=0x8200080
+               rm-113     [005] ..Zff    10.001031: watch: (vfs_unlink+0x5e/0x260) address=0xffff8880048083a8 value=0x8200080
+               rm-113     [005] d.Z..    10.001067: watch: (d_make_discardable+0x1b/0x40) address=0xffff8880048083a8 value=0x8200080
+               rm-113     [005] d.Z..    10.001071: watch: (d_make_discardable+0x29/0x40) address=0xffff8880048083a8 value=0x200080
+               rm-113     [005] ...1.    10.001072: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff8880048083a8
+               rm-113     [005] ...1.    10.001218: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff8880048083a8
+               sh-107     [004] ...1.    10.001416: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff8880049db110
+               sh-107     [004] ...1.    10.001444: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff8880049db248
+               sh-107     [004] ...1.    10.001500: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff888004ad6618
+               sh-107     [004] ...1.    10.002067: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff888004b41e78
+               sh-107     [004] ...1.    10.904920: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff888004b41e78
+               sh-107     [004] ...1.    10.905129: dentry_kill: (dentry_kill+0x0/0x2c0) dentry=0xffff888004ad6618
+
+You can see the watch event is correctly configured on the dentry.
diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index d1e5ab71d928..e6f3bbcbb9af 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -729,6 +729,7 @@ enum event_trigger_type {
 	ETT_EVENT_HIST		= (1 << 4),
 	ETT_HIST_ENABLE		= (1 << 5),
 	ETT_EVENT_EPROBE	= (1 << 6),
+	ETT_EVENT_WPROBE	= (1 << 7),
 };
 
 extern int filter_match_preds(struct event_filter *filter, void *rec);
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index d9b6fa5c35d9..af570fa2a882 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -876,6 +876,16 @@ config WPROBE_EVENTS
 	  Those events can be inserted wherever hardware breakpoints can be
 	  set, and record accessed memory address and values.
 
+config WPROBE_TRIGGERS
+	depends on WPROBE_EVENTS
+	depends on HAVE_REINSTALL_HW_BREAKPOINT
+	bool
+	default y
+	help
+	  This adds an event trigger which will set the wprobe on a specific
+	  field of an event. This allows user to trace the memory access of
+	  an address pointed by the event field.
+
 config BPF_EVENTS
 	depends on BPF_SYSCALL
 	depends on (KPROBE_EVENTS || UPROBE_EVENTS) && PERF_EVENTS
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 2f07c5c4ffc8..e5964a69057c 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -1939,6 +1939,7 @@ struct event_trigger_data {
 	struct event_filter __rcu	*filter;
 	char				*filter_str;
 	void				*private_data;
+	void				(*private_free)(void *private_data);
 	bool				paused;
 	bool				paused_tmp;
 	struct list_head		list;
@@ -1982,6 +1983,7 @@ trigger_data_alloc(struct event_command *cmd_ops, char *cmd, char *param,
 		   void *private_data);
 extern void trigger_data_free(struct event_trigger_data *data);
 extern int event_trigger_init(struct event_trigger_data *data);
+extern void event_trigger_free(struct event_trigger_data *data);
 extern int trace_event_trigger_enable_disable(struct trace_event_file *file,
 					      int trigger_enable);
 extern void update_cond_flag(struct trace_event_file *file);
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c
index 655db2e82513..1e3b667a2edd 100644
--- a/kernel/trace/trace_events_trigger.c
+++ b/kernel/trace/trace_events_trigger.c
@@ -51,8 +51,11 @@ static void trigger_data_free_queued_locked(void)
 
 	tracepoint_synchronize_unregister();
 
-	llist_for_each_entry_safe(data, tmp, llnodes, llist)
+	llist_for_each_entry_safe(data, tmp, llnodes, llist) {
+		if (data->private_free)
+			data->private_free(data->private_data);
 		kfree(data);
+	}
 }
 
 /* Bulk garbage collection of event_trigger_data elements */
@@ -74,8 +77,11 @@ static int trigger_kthread_fn(void *ignore)
 		/* make sure current triggers exit before free */
 		tracepoint_synchronize_unregister();
 
-		llist_for_each_entry_safe(data, tmp, llnodes, llist)
+		llist_for_each_entry_safe(data, tmp, llnodes, llist) {
+			if (data->private_free)
+				data->private_free(data->private_data);
 			kfree(data);
+		}
 	}
 
 	return 0;
@@ -582,7 +588,7 @@ int event_trigger_init(struct event_trigger_data *data)
  * Usually used directly as the @free method in event trigger
  * implementations.
  */
-static void
+void
 event_trigger_free(struct event_trigger_data *data)
 {
 	if (WARN_ON_ONCE(data->ref <= 0))
diff --git a/kernel/trace/trace_wprobe.c b/kernel/trace/trace_wprobe.c
index 08a2829b9eaa..df099a6eb69e 100644
--- a/kernel/trace/trace_wprobe.c
+++ b/kernel/trace/trace_wprobe.c
@@ -6,7 +6,9 @@
  */
 #define pr_fmt(fmt)	"trace_wprobe: " fmt
 
+#include <linux/atomic.h>
 #include <linux/compiler.h>
+#include <linux/errno.h>
 #include <linux/hw_breakpoint.h>
 #include <linux/kallsyms.h>
 #include <linux/list.h>
@@ -15,11 +17,16 @@
 #include <linux/perf_event.h>
 #include <linux/rculist.h>
 #include <linux/security.h>
+#include <linux/spinlock.h>
 #include <linux/tracepoint.h>
 #include <linux/uaccess.h>
+#include <linux/workqueue.h>
+#include <linux/irq_work.h>
+#include <linux/preempt.h>
 
 #include <asm/ptrace.h>
 
+#include "trace.h"
 #include "trace_dynevent.h"
 #include "trace_probe.h"
 #include "trace_probe_kernel.h"
@@ -50,6 +57,10 @@ struct trace_wprobe {
 	int			len;
 	int			type;
 	const char		*symbol;
+	raw_spinlock_t		lock;
+	struct irq_work		irq_work;
+	struct work_struct	work;
+	atomic_t		missed;
 	struct trace_probe	tp;
 };
 
@@ -199,14 +210,49 @@ static int __register_trace_wprobe(struct trace_wprobe *tw)
 static void __unregister_trace_wprobe(struct trace_wprobe *tw)
 {
 	if (tw->bp_event) {
+		irq_work_sync(&tw->irq_work);
+		cancel_work_sync(&tw->work);
 		unregister_wide_hw_breakpoint(tw->bp_event);
 		tw->bp_event = NULL;
 	}
 }
 
+static int trace_wprobe_update_local(struct trace_wprobe *tw, unsigned long addr)
+{
+	struct perf_event *bp = *this_cpu_ptr(tw->bp_event);
+	struct perf_event_attr attr = bp->attr;
+
+	attr.bp_addr = addr;
+	return modify_wide_hw_breakpoint_local(bp, &attr);
+}
+
+static void wprobe_smp_update_func(void *info)
+{
+	struct trace_wprobe *tw = info;
+	unsigned long addr = READ_ONCE(tw->addr);
+
+	trace_wprobe_update_local(tw, addr);
+}
+
+static void wprobe_work_func(struct work_struct *work)
+{
+	struct trace_wprobe *tw = container_of(work, struct trace_wprobe, work);
+
+	on_each_cpu(wprobe_smp_update_func, tw, true);
+}
+
+static void wprobe_irq_work_func(struct irq_work *irq_work)
+{
+	struct trace_wprobe *tw = container_of(irq_work, struct trace_wprobe, irq_work);
+
+	schedule_work(&tw->work);
+}
+
 static void free_trace_wprobe(struct trace_wprobe *tw)
 {
 	if (tw) {
+		irq_work_sync(&tw->irq_work);
+		cancel_work_sync(&tw->work);
 		trace_probe_cleanup(&tw->tp);
 		kfree(tw->symbol);
 		kfree(tw);
@@ -238,6 +284,10 @@ static struct trace_wprobe *alloc_trace_wprobe(const char *group,
 	tw->addr = addr;
 	tw->len = len;
 	tw->type = type;
+	raw_spin_lock_init(&tw->lock);
+	init_irq_work(&tw->irq_work, wprobe_irq_work_func);
+	INIT_WORK(&tw->work, wprobe_work_func);
+	atomic_set(&tw->missed, 0);
 
 	ret = trace_probe_init(&tw->tp, event, group, false, nargs);
 	if (ret < 0)
@@ -745,3 +795,391 @@ static __init int init_wprobe_trace(void)
 }
 fs_initcall(init_wprobe_trace);
 
+#ifdef CONFIG_WPROBE_TRIGGERS
+
+static int wprobe_trigger_global_enabled;
+
+#define SET_WPROBE_STR		"set_wprobe"
+#define CLEAR_WPROBE_STR	"clear_wprobe"
+#define WPROBE_DEFAULT_CLEAR_ADDRESS ((unsigned long)&wprobe_trigger_global_enabled)
+
+struct wprobe_trigger_data {
+	struct rcu_head rcu;
+	struct trace_event_file *file;
+	struct trace_wprobe *tw;
+	unsigned int		offset;
+	long			adjust;
+	const char		*field;
+	bool			clear;
+};
+
+static void wprobe_trigger(struct event_trigger_data *data,
+			   struct trace_buffer *buffer,  void *rec,
+			   struct ring_buffer_event *event)
+{
+	struct wprobe_trigger_data *wprobe_data = data->private_data;
+	struct trace_wprobe *tw = wprobe_data->tw;
+	unsigned long addr, flags;
+	bool changed = false;
+
+	addr = *(unsigned long *)(rec + wprobe_data->offset);
+	addr += wprobe_data->adjust;
+
+	if (in_nmi()) {
+		atomic_inc(&tw->missed);
+		return;
+	}
+
+	raw_spin_lock_irqsave(&tw->lock, flags);
+
+	if (!wprobe_data->clear) {
+		if (tw->addr == WPROBE_DEFAULT_CLEAR_ADDRESS) {
+			tw->addr = addr;
+			changed = true;
+			clear_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &wprobe_data->file->flags);
+		}
+	} else {
+		if (tw->addr != WPROBE_DEFAULT_CLEAR_ADDRESS) {
+			if (!wprobe_data->field || tw->addr == addr) {
+				tw->addr = WPROBE_DEFAULT_CLEAR_ADDRESS;
+				changed = true;
+				set_bit(EVENT_FILE_FL_SOFT_DISABLED_BIT, &wprobe_data->file->flags);
+			}
+		}
+	}
+
+	if (changed)
+		irq_work_queue(&tw->irq_work);
+
+	raw_spin_unlock_irqrestore(&tw->lock, flags);
+}
+
+static void free_wprobe_trigger_data(struct wprobe_trigger_data *wprobe_data)
+{
+	if (wprobe_data) {
+		kfree(wprobe_data->field);
+		kfree(wprobe_data);
+	}
+}
+DEFINE_FREE(free_wprobe_trigger_data, struct wprobe_trigger_data *, free_wprobe_trigger_data(_T));
+
+static void free_private_wprobe_trigger_data(void *data)
+{
+	free_wprobe_trigger_data(data);
+}
+
+static int wprobe_trigger_print(struct seq_file *m,
+			       struct event_trigger_data *data)
+{
+	struct wprobe_trigger_data *wprobe_data = data->private_data;
+
+	if (wprobe_data->clear) {
+		seq_printf(m, "%s:%s", CLEAR_WPROBE_STR,
+			   trace_event_name(wprobe_data->file->event_call));
+		if (wprobe_data->field) {
+			seq_printf(m, ":%s%+ld",
+				   wprobe_data->field, wprobe_data->adjust);
+		}
+	} else
+		seq_printf(m, "%s:%s:%s%+ld", SET_WPROBE_STR,
+			   trace_event_name(wprobe_data->file->event_call),
+			   wprobe_data->field, wprobe_data->adjust);
+
+	if (data->filter_str)
+		seq_printf(m, " if %s\n", data->filter_str);
+	else
+		seq_putc(m, '\n');
+
+	return 0;
+}
+
+static struct wprobe_trigger_data *
+wprobe_trigger_alloc(struct trace_wprobe *tw, struct trace_event_file *file,
+		     bool clear)
+{
+	struct wprobe_trigger_data *wprobe_data;
+
+	wprobe_data = kzalloc_obj(*wprobe_data);
+	if (!wprobe_data)
+		return NULL;
+
+	wprobe_data->tw = tw;
+	wprobe_data->clear = clear;
+	wprobe_data->file = file;
+
+	return wprobe_data;
+}
+
+static void wprobe_trigger_free(struct event_trigger_data *data)
+{
+	struct wprobe_trigger_data *wprobe_data = data->private_data;
+
+	if (WARN_ON_ONCE(data->ref <= 0))
+		return;
+
+	data->ref--;
+	if (!data->ref) {
+		/* Remove the SOFT_MODE flag */
+		trace_event_enable_disable(wprobe_data->file, 0, 1);
+		trace_event_put_ref(wprobe_data->file->event_call);
+		trigger_data_free(data);
+	}
+}
+
+static int wprobe_trigger_cmd_parse(struct event_command *cmd_ops,
+				    struct trace_event_file *file,
+				    char *glob, char *cmd,
+				    char *param_and_filter)
+{
+	/*
+	 * set_wprobe:EVENT:FIELD[+OFFS]
+	 * clear_wprobe:EVENT[:FIELD[+OFFS]]
+	 */
+	struct wprobe_trigger_data *wprobe_data __free(free_wprobe_trigger_data) = NULL;
+	struct event_trigger_data *trigger_data __free(kfree) = NULL;
+	struct ftrace_event_field *field = NULL;
+	struct trace_event_file *wprobe_file;
+	struct trace_array *tr = file->tr;
+	struct trace_event_call *event;
+	char *event_str, *field_str;
+	bool remove, clear = false;
+	struct trace_wprobe *tw;
+	char *param, *filter;
+	int ret;
+
+	remove = event_trigger_check_remove(glob);
+
+	if (!strcmp(cmd, CLEAR_WPROBE_STR))
+		clear = true;
+
+	if (event_trigger_empty_param(param_and_filter))
+		return -EINVAL;
+
+	ret = event_trigger_separate_filter(param_and_filter, &param, &filter, true);
+	if (ret)
+		return ret;
+
+	if (file->event_call->flags & TRACE_EVENT_FL_KPROBE)
+		return -EOPNOTSUPP;
+
+	event_str = strsep(&param, ":");
+
+	/* Find target wprobe */
+	tw = find_trace_wprobe(event_str, WPROBE_EVENT_SYSTEM);
+	if (!tw)
+		return -ENOENT;
+	/* The target wprobe must not be used (unless clear) */
+	if (!remove && !clear && trace_probe_is_enabled(&tw->tp))
+		return -EBUSY;
+
+	wprobe_file = find_event_file(tr, WPROBE_EVENT_SYSTEM, event_str);
+	if (!wprobe_file)
+		return -EINVAL;
+
+	wprobe_data = wprobe_trigger_alloc(tw, wprobe_file, clear);
+	if (!wprobe_data)
+		return -ENOMEM;
+
+	/* Find target field, which must be equivarent to "void *" */
+	field_str = strsep(&param, ":");
+	/* trigger removing or clear_wprobe does not need field. */
+	if (!remove && !clear && !field_str)
+		return -EINVAL;
+
+	if (field_str) {
+		char *offs;
+
+		offs = strpbrk(field_str, "+-");
+		if (offs) {
+			long val;
+
+			if (kstrtol(offs, 0, &val) < 0)
+				return -EINVAL;
+			wprobe_data->adjust = val;
+			*offs = '\0';
+		}
+
+		event = file->event_call;
+		field = trace_find_event_field(event, field_str);
+		if (!field)
+			return -ENOENT;
+
+		if (field->size != sizeof(void *))
+			return -ENOEXEC;
+		wprobe_data->offset = field->offset;
+		wprobe_data->field = kstrdup(field_str, GFP_KERNEL);
+		if (!wprobe_data->field)
+			return -ENOMEM;
+	}
+
+	trigger_data = trigger_data_alloc(cmd_ops, cmd, param, wprobe_data);
+	if (!trigger_data)
+		return -ENOMEM;
+
+	trigger_data->private_free = free_private_wprobe_trigger_data;
+
+	/* Up the trigger_data count to make sure nothing frees it on failure */
+	event_trigger_init(trigger_data);
+
+	if (remove) {
+		event_trigger_unregister(cmd_ops, file, glob+1, trigger_data);
+		return 0;
+	}
+
+	ret = event_trigger_parse_num(param, trigger_data);
+	if (ret)
+		return ret;
+
+	ret = event_trigger_set_filter(cmd_ops, file, filter, trigger_data);
+	if (ret < 0)
+		return ret;
+
+	/* Soft-enable (register) wprobe event on WPROBE_DEFAULT_CLEAR_ADDRESS */
+	if (!trace_event_try_get_ref(wprobe_file->event_call)) {
+		event_trigger_reset_filter(cmd_ops, trigger_data);
+		return -ENODEV;
+	}
+
+	if (!clear)
+		WRITE_ONCE(tw->addr, WPROBE_DEFAULT_CLEAR_ADDRESS);
+	ret = trace_event_enable_disable(wprobe_file, 1, 1);
+	if (ret < 0) {
+		trace_event_put_ref(wprobe_file->event_call);
+		event_trigger_reset_filter(cmd_ops, trigger_data);
+		return ret;
+	}
+	ret = event_trigger_register(cmd_ops, file, glob, trigger_data);
+	if (ret) {
+		event_trigger_reset_filter(cmd_ops, trigger_data);
+		trace_event_enable_disable(wprobe_file, 0, 1);
+		trace_event_put_ref(wprobe_file->event_call);
+		synchronize_rcu();
+		return ret;
+	}
+	/* Make it NULL to avoid freeing trigger_data and wprobe_data by __free() */
+	wprobe_data = NULL;
+	event_trigger_free(trigger_data);
+	trigger_data = NULL;
+
+	return 0;
+}
+
+/* Return event_trigger_data if there is a trigger which points the same wprobe */
+static struct event_trigger_data *
+wprobe_trigger_find_same(struct event_trigger_data *test,
+			 struct trace_event_file *file)
+{
+	struct wprobe_trigger_data *test_wprobe_data = test->private_data;
+	struct wprobe_trigger_data *wprobe_data;
+	struct event_trigger_data *iter;
+
+	list_for_each_entry(iter, &file->triggers, list) {
+		wprobe_data = iter->private_data;
+		if (!wprobe_data ||
+		    iter->cmd_ops->trigger_type !=
+		    test->cmd_ops->trigger_type)
+			continue;
+		if (wprobe_data->tw == test_wprobe_data->tw)
+			return iter;
+	}
+	return NULL;
+}
+
+static int wprobe_register_trigger(char *glob,
+				   struct event_trigger_data *data,
+				   struct trace_event_file *file)
+{
+	int ret = 0;
+
+	lockdep_assert_held(&event_mutex);
+
+	/* The same wprobe is not accept on the same file (event) */
+	if (wprobe_trigger_find_same(data, file))
+		return -EEXIST;
+
+	if (data->cmd_ops->init) {
+		ret = data->cmd_ops->init(data);
+		if (ret < 0)
+			return ret;
+	}
+
+	list_add_rcu(&data->list, &file->triggers);
+
+	update_cond_flag(file);
+	ret = trace_event_trigger_enable_disable(file, 1);
+	if (ret < 0) {
+		list_del_rcu(&data->list);
+		update_cond_flag(file);
+	}
+	return ret;
+}
+
+static void wprobe_unregister_trigger(char *glob,
+				      struct event_trigger_data *test,
+				      struct trace_event_file *file)
+{
+	struct event_trigger_data *data;
+
+	lockdep_assert_held(&event_mutex);
+
+	data = wprobe_trigger_find_same(test, file);
+	if (!data)
+		return;
+
+	list_del_rcu(&data->list);
+	trace_event_trigger_enable_disable(file, 0);
+	update_cond_flag(file);
+	if (data->cmd_ops->free)
+		data->cmd_ops->free(data);
+}
+
+static struct event_command trigger_wprobe_set_cmd = {
+	.name			= SET_WPROBE_STR,
+	.trigger_type		= ETT_EVENT_WPROBE,
+	/* This triggers after when the event is recorded. */
+	.flags			= EVENT_CMD_FL_NEEDS_REC,
+	.parse			= wprobe_trigger_cmd_parse,
+	.reg			= wprobe_register_trigger,
+	.unreg			= wprobe_unregister_trigger,
+	.set_filter		= set_trigger_filter,
+	.trigger		= wprobe_trigger,
+	.count_func		= event_trigger_count,
+	.print			= wprobe_trigger_print,
+	.init			= event_trigger_init,
+	.free			= wprobe_trigger_free,
+};
+
+static struct event_command trigger_wprobe_clear_cmd = {
+	.name			= CLEAR_WPROBE_STR,
+	.trigger_type		= ETT_EVENT_WPROBE,
+	/* This triggers after when the event is recorded. */
+	.flags			= EVENT_CMD_FL_NEEDS_REC,
+	.parse			= wprobe_trigger_cmd_parse,
+	.reg			= wprobe_register_trigger,
+	.unreg			= wprobe_unregister_trigger,
+	.set_filter		= set_trigger_filter,
+	.trigger		= wprobe_trigger,
+	.count_func		= event_trigger_count,
+	.print			= wprobe_trigger_print,
+	.init			= event_trigger_init,
+	.free			= wprobe_trigger_free,
+};
+
+static __init int init_trigger_wprobe_cmds(void)
+{
+	int ret;
+
+	ret = register_event_command(&trigger_wprobe_set_cmd);
+	if (WARN_ON(ret < 0))
+		return ret;
+	ret = register_event_command(&trigger_wprobe_clear_cmd);
+	if (WARN_ON(ret < 0))
+		unregister_event_command(&trigger_wprobe_set_cmd);
+
+	if (!ret)
+		wprobe_trigger_global_enabled = 1;
+
+	return ret;
+}
+fs_initcall(init_trigger_wprobe_cmds);
+#endif /* CONFIG_WPROBE_TRIGGERS */


^ permalink raw reply related

* [PATCH v9 09/10] selftests: ftrace: Add wprobe trigger testcase
From: Masami Hiramatsu (Google) @ 2026-07-17 14:21 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra, Ingo Molnar, x86
  Cc: Jinchao Wang, Mathieu Desnoyers, Masami Hiramatsu,
	Thomas Gleixner, Borislav Petkov, Dave Hansen, H . Peter Anvin,
	Alexander Shishkin, Ian Rogers, linux-kernel, linux-trace-kernel,
	linux-doc, linux-perf-users
In-Reply-To: <178429796992.157981.3393977217853767915.stgit@devnote2>

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Add a testcase for checking wprobe trigger. This sets set_wprobe and
clear_wprobe triggers on fprobe events to watch dentry access.
So this depends on both wprobe and fprobe.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 Changes in v9:
  - Drop dentry cache after removing tempfile for on-disk
    filesystem.
 Changes in v8:
  - Use TMPDIR for making a test file.
  - Ensure the fprobe and target functions exists, if not, exit
    with UNRESOLVED (== skip).
 Changes in v7:
  - Add a newline at the end of file.(style fix)
  - Use dentry_kill instead of __dentry_kill.
 Changes in v5:
  - Enable CONFIG_WPROBE_TRIGGERS in the config for ftrace test.
 Changes in v3:
  - Newly added.
---
 tools/testing/selftests/ftrace/config              |    1 
 .../ftrace/test.d/trigger/trigger-wprobe.tc        |   70 ++++++++++++++++++++
 2 files changed, 71 insertions(+)
 create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/trigger-wprobe.tc

diff --git a/tools/testing/selftests/ftrace/config b/tools/testing/selftests/ftrace/config
index d2f503722020..ecdee77f360f 100644
--- a/tools/testing/selftests/ftrace/config
+++ b/tools/testing/selftests/ftrace/config
@@ -28,3 +28,4 @@ CONFIG_TRACER_SNAPSHOT=y
 CONFIG_UPROBES=y
 CONFIG_UPROBE_EVENTS=y
 CONFIG_WPROBE_EVENTS=y
+CONFIG_WPROBE_TRIGGERS=y
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-wprobe.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-wprobe.tc
new file mode 100644
index 000000000000..0634259e2c65
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-wprobe.tc
@@ -0,0 +1,70 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: event trigger - test wprobe trigger
+# requires: dynamic_events "w[:[<group>/][<event>]] [r|w|rw]@<addr>[:<len>]":README events/sched/sched_process_fork/trigger
+
+echo 0 > tracing_on
+rm -f $TMPDIR/hoge
+
+:;: "Add a wprobe event used by trigger" ;:
+echo 'w:watch rw@0:8 address=$addr value=+0($addr)' > dynamic_events
+
+# we will skip this test if fprobe is not supported.
+if ! grep -Fq "f[:[<group>/][<event>]] <func-name>[%return] [<args>]" README; then
+    echo "UNRESOLVED: fprobe is not supported"
+    exit_unresolved
+fi
+
+# we will skip this test if the target function does not exist.
+if ! grep -wq "do_truncate" /proc/kallsyms; then
+    echo "UNRESOLVED: do_truncate not found"
+    exit_unresolved
+fi
+if ! grep -wq "dentry_kill" /proc/kallsyms; then
+    echo "UNRESOLVED: dentry_kill not found"
+    exit_unresolved
+fi
+
+:;: "Add events for triggering wprobe" ;:
+echo 'f:truncate do_truncate dentry=$arg2' >> dynamic_events
+echo 'f:dentry_kill dentry_kill dentry=$arg1' >> dynamic_events
+
+:;: "Add wprobe triggers" ;:
+echo 'set_wprobe:watch:dentry' >> events/fprobes/truncate/trigger
+echo 'clear_wprobe:watch:dentry' >> events/fprobes/dentry_kill/trigger
+cat events/fprobes/truncate/trigger | grep ^set_wprobe
+cat events/fprobes/dentry_kill/trigger | grep ^clear_wprobe
+
+:;: "Ensure wprobe is still disabled" ;:
+cat events/wprobes/watch/enable | grep 0
+
+:;: "Enable events for triggers" ;:
+echo 1 >> events/fprobes/truncate/enable
+echo 1 >> events/fprobes/dentry_kill/enable
+
+:;: "Start test workload" ;:
+echo 1 >> tracing_on
+
+echo aaa > $TMPDIR/hoge
+echo bbb > $TMPDIR/hoge
+echo ccc > $TMPDIR/hoge
+rm $TMPDIR/hoge
+
+:;: "Drop dentry caches (for dentry_kill)" ;:
+# Use append (>>) to avoid calling do_truncate again.
+sync && echo 2 >> /proc/sys/vm/drop_caches
+
+:;: "Check trace results" ;:
+cat trace | grep watch
+
+
+:;: "Ensure wprobe becomes disabled again" ;:
+cat events/wprobes/watch/enable | grep 0
+
+:;: "Remove wprobe triggers" ;:
+echo '!set_wprobe:watch:dentry' >> events/fprobes/truncate/trigger
+echo '!clear_wprobe:watch' >> events/fprobes/dentry_kill/trigger
+! grep ^set_wprobe events/fprobes/truncate/trigger
+! grep ^clear_wprobe events/fprobes/dentry_kill/trigger
+
+exit 0


^ permalink raw reply related

* [PATCH v9 10/10] tracing/wprobe: Support BTF typecast in fetchargs
From: Masami Hiramatsu (Google) @ 2026-07-17 14:21 UTC (permalink / raw)
  To: Steven Rostedt, Peter Zijlstra, Ingo Molnar, x86
  Cc: Jinchao Wang, Mathieu Desnoyers, Masami Hiramatsu,
	Thomas Gleixner, Borislav Petkov, Dave Hansen, H . Peter Anvin,
	Alexander Shishkin, Ian Rogers, linux-kernel, linux-trace-kernel,
	linux-doc, linux-perf-users
In-Reply-To: <178429796992.157981.3393977217853767915.stgit@devnote2>

From: Masami Hiramatsu (Google) <mhiramat@kernel.org>

Allow BTF typecast syntax (STRUCT)FETCHARG->MEMBER in wprobe event
fetchargs. Previously, handle_typecast() rejected any probe context
that was not a function entry/return or tracepoint event probe.

Wprobe events use  (the accessed address) and  (the value
at that address). By enabling BTF typecast, users can now cast these
to a concrete struct type and access its fields directly. For example:

  echo 'w:watch rw@0:8 dflag=(struct dentry)$addr->d_flags' >> dynamic_events

With a set_wprobe trigger pointing the watchpoint at a dentry address,
the resulting trace shows d_flags being accessed at that location.

Note that  and  are restricted to kernel-space memory,
which is consistent with the existing TPARG_FL_KERNEL flag used when
parsing wprobe fetchargs.

Assisted-by: Antigravity:gemini-3.5-flash
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
 Changes in v9:
  - Newly added.
---
 kernel/trace/trace_probe.c                         |    3 +
 kernel/trace/trace_probe.h                         |    5 +
 .../test.d/trigger/trigger-wprobe-btf-typecast.tc  |   80 ++++++++++++++++++++
 3 files changed, 87 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/trigger-wprobe-btf-typecast.tc

diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 5d5e9b477b86..8332ff1bb4ff 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -967,7 +967,8 @@ static int handle_typecast(char *arg, struct traceprobe_parse_context *ctx)
 
 	if (!(tparg_is_event_probe(ctx->flags) ||
 	      tparg_is_function_entry(ctx->flags) ||
-	      tparg_is_function_return(ctx->flags))) {
+	      tparg_is_function_return(ctx->flags) ||
+	      tparg_is_wprobe(ctx->flags))) {
 		trace_probe_log_err(ctx->offset, NOSUP_BTFARG);
 		return -EOPNOTSUPP;
 	}
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 7380502a85af..0a83b3fb6128 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -439,6 +439,11 @@ static inline bool tparg_is_event_probe(unsigned int flags)
 	return !!(flags & TPARG_FL_TEVENT);
 }
 
+static inline bool tparg_is_wprobe(unsigned int flags)
+{
+	return !!(flags & TPARG_FL_WPROBE);
+}
+
 /* Each typecast consumes nested level. So the max number of typecast is 8. */
 #define TRACEPROBE_MAX_NESTED_LEVEL 8
 
diff --git a/tools/testing/selftests/ftrace/test.d/trigger/trigger-wprobe-btf-typecast.tc b/tools/testing/selftests/ftrace/test.d/trigger/trigger-wprobe-btf-typecast.tc
new file mode 100644
index 000000000000..8962c91d8428
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/trigger/trigger-wprobe-btf-typecast.tc
@@ -0,0 +1,80 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: event trigger - test wprobe trigger with BTF typecast fetchargs
+# requires: dynamic_events "w[:[<group>/][<event>]] [r|w|rw]@<addr>[:<len>]":README events/sched/sched_process_fork/trigger "[(structname[,field])]<argname>[->field[->field|.field...]]":README
+
+echo 0 >> tracing_on
+
+rm -f $TMPDIR/hoge
+
+# we will skip this test if fprobe is not supported.
+if ! grep -Fq "f[:[<group>/][<event>]] <func-name>[%return] [<args>]" README; then
+    echo "UNRESOLVED: fprobe is not supported"
+    exit_unresolved
+fi
+
+# we will skip this test if the target function does not exist.
+if ! grep -wq "do_truncate" /proc/kallsyms; then
+    echo "UNRESOLVED: do_truncate not found"
+    exit_unresolved
+fi
+if ! grep -wq "dentry_kill" /proc/kallsyms; then
+    echo "UNRESOLVED: dentry_kill not found"
+    exit_unresolved
+fi
+
+:;: "Add a wprobe event with BTF typecast fetchargs" ;:
+# $addr is the address being accessed (= dentry pointer when watching dentry)
+# (dentry)$addr->d_flags reads d_flags from the dentry struct via BTF typecast
+# Note: BTF typecast uses (STRUCT) without the 'struct' keyword, matching
+# the fetcharg syntax used in fprobe/tprobe events.
+echo 'w:watch rw@0:8 address=$addr dflag=(dentry)$addr->d_flags' >> dynamic_events
+
+:;: "Check the wprobe event is registered with dflag field" ;:
+grep -q "dflag" dynamic_events
+
+:;: "Add events for triggering wprobe" ;:
+echo 'f:truncate do_truncate dentry=$arg2' >> dynamic_events
+echo 'f:dentry_kill dentry_kill dentry=$arg1' >> dynamic_events
+
+:;: "Add wprobe triggers" ;:
+echo 'set_wprobe:watch:dentry' >> events/fprobes/truncate/trigger
+echo 'clear_wprobe:watch:dentry' >> events/fprobes/dentry_kill/trigger
+cat events/fprobes/truncate/trigger | grep ^set_wprobe
+cat events/fprobes/dentry_kill/trigger | grep ^clear_wprobe
+
+:;: "Ensure wprobe is still disabled" ;:
+cat events/wprobes/watch/enable | grep 0
+
+:;: "Enable events for triggers" ;:
+echo 1 >> events/fprobes/truncate/enable
+echo 1 >> events/fprobes/dentry_kill/enable
+
+:;: "Start test workload" ;:
+echo 1 >> tracing_on
+
+echo aaa > $TMPDIR/hoge
+sleep 1
+echo bbb > $TMPDIR/hoge
+sleep 1
+echo ccc > $TMPDIR/hoge
+sleep 1
+rm $TMPDIR/hoge
+
+:;: "Drop dentry caches (for dentry_kill)" ;:
+sync && echo 2 >> /proc/sys/vm/drop_caches
+
+:;: "Check trace results include BTF typecast field dflag" ;:
+cat trace > /tmp/test-trace-typecast.log
+cat trace | grep "watch.*dflag="
+
+:;: "Ensure wprobe becomes disabled again" ;:
+cat events/wprobes/watch/enable | grep 0
+
+:;: "Remove wprobe triggers" ;:
+echo '!set_wprobe:watch:dentry' >> events/fprobes/truncate/trigger
+echo '!clear_wprobe:watch' >> events/fprobes/dentry_kill/trigger
+! grep ^set_wprobe events/fprobes/truncate/trigger
+! grep ^clear_wprobe events/fprobes/dentry_kill/trigger
+
+exit 0


^ permalink raw reply related

* Re: [RFC PATCH v1 8/8] misc/arm-cla: Add userspace interface
From: Ryan Roberts @ 2026-07-17 14:35 UTC (permalink / raw)
  To: Arnd Bergmann, Greg Kroah-Hartman, Catalin Marinas, Will Deacon,
	Mark Rutland, Jean-Philippe Brucker, Oded Gabbay, Jonathan Corbet
  Cc: linux-kernel, linux-arm-kernel, dri-devel, linux-doc
In-Reply-To: <404d2c6d-4a18-40c2-9da9-fb030c39536f@app.fastmail.com>

On 17/07/2026 13:54, Arnd Bergmann wrote:
> On Fri, Jul 17, 2026, at 12:47, Ryan Roberts wrote:
>> Expose CLA devices through a character device so userspace can enumerate
>> the available hardware and map accelerator register frames.
>>
>> Define version 1 of the CLA UAPI with a GET_PARAM ioctl. Report device
>> topology, CPU affinity, domain membership, mmap offsets, architecture
>> version and attached accelerator masks, together with the IIDR, DEVARCH
>> and REVIDR of each accelerator.
>>
>> CLA registers can only be read from the CPU local to the device, while
>> enumeration may occur on any CPU. Validate the supported CLA
>> architecture version during device setup and cache the CLA and
>> accelerator identification registers for later ioctl queries.
> 
> This interface looks very raw at the moment, I expect this will have
> one or more larger redesigns.

Are you referring to the overall UABI or specifically to the ioctl interface
here? I could imagine the ioctl interface evolving before we get this merged
(although it is based on similar patterns used by some DRM and accel drivers -
it's intended to be easily extensible while existing params remain stable).

The aspect where the CLA MMIO is directly mapped into user space is an aspect we
are keen to keep though since it has significant performance implications if we
need to redirect through the kernel.

> 
> Most importantly, a single character device to expose an arbitrary
> number of underlying hardware features is an inherently flawed security
> model. If any specific accelerator is ever found to have a
> major vulnerability, that would mean administrators will have to
> disable all of them by default.

Note that we are exposing MMIO per CLA, not per accelerator. So preventing
access to a single CLA would prevent access to all accelerators attached to it.
There is a per-accelerator availability masking control that the kernel can use
to disable access to selected accelerators though, which might help with the
vulnerability example.

The rationale for choosing a single device file was driven by performance: At
domain reassignment time, we need to unmap and invalidate the TLB entries for
all the devices in the domain from the out-going process's address space. By
having all the devices in a single file and all devices within the same domain
adjacent, they can all be mapped to a single VMA, meaning the driver can use a
single call to the existing zap_special_vma_range(), which will result in a
single TLBI-by-range instruction, which is faster than a TLBI-by-va for every
device.

If you think it is important for security to have each CLA exposed by an
independent device file, I'll take another look.

> 
>> Support shared read-write mmap of one or more CLA register pages. Create
>> a context for every domain covered by the mapping and resolve faults
>> only while that context owns the domain. Queue unassigned contexts with
>> the domain scheduler, drop mmap_lock while waiting for assignment and
>> retry the fault after the context is woken.
> 
> I still need some time to better understand what this means.

I can probably do a better job of explaining this: The kernel keeps a cla_ctx
object which represents a single {file description, mm_struct} context that
wants to use the cla_domain (collection of 1 or more cla_dev). Initially the VMA
is not populated so when user space tries to access, it will fault to the
driver. If the cla_domain is assigned to a different cla_ctx, the faulting
thread is put to sleep until the driver determines that it's the turn of that
cla_ctx to be assigned the domain. At that point the waiting thread(s) are woken
and map the devices from the domain to the VMA and return to user space. The
out-going cla_ctx had it's mappings removed during the reassignment process so
any user space access will now fault and sleep waiting for assignment.

> Does a CPU have multiple concurrently running contexts? 

The HW only has a single HW context, hence the timesliced assignment approach
described above (assuming there is more than 1 concurrent user).

> Is a
> user process able to starve the allocation of other processes
> by just requesting a lot of them?

In the current code, a process can theoretically create the same number of
cla_ctx as the number of file descriptors it can open(). It would then need to
mmap and access to get into the queue to be assigned the domain. I see it as
similar to threads; if process A creates 10 threads and process B creates 1
thread, then in the long run (ignoring cgroups et al) you'd expect A to get
10/11th of the CPU time (IIUC?).

Do you think this consitutes a DoS?

> 
>> +static long cla_ioctl_get_param(unsigned long arg)
>> +{
>> +	struct arm_cla_param __user *uparam = (void __user *)arg;
>> +	struct arm_cla_param param;
>> +	int accel_id;
>> +	int dev_id;
>> +	int ret;
>> +
>> +	if (copy_from_user(&param, uparam, sizeof(param)))
>> +		return -EFAULT;
>> +
>> +	ret = cla_ioctl_validate_param(&param);
>> +	if (ret)
>> +		return ret;
>> +
>> +	dev_id = dev_nospec(ARM_CLA_PARAM_INDEX_DEV(param.index));
>> +	accel_id = accel_nospec(ARM_CLA_PARAM_INDEX_ACCEL(param.index));
> 
> Why is the dev_id/accel_id not a property of the device node itself?

As per above, I can go look again at having a device node per CLA device (i.e.
one for each CPU that has a CLA). But it doesn't make sense to have a device
node per accelerator (a CLA can have up to 8 connected accelerators); there is
only a single HW interface.

> 
>> +	switch (param.param) {
>> +	case ARM_CLA_PARAM_UABI_VERSION:
>> +		param.value = ARM_CLA_UABI_VERSION;
>> +		break;
> 
> UABI definitions are not versioned, you have to stay compatible
> indefinitely. If you need something else, add a new command.

Yes agreed; my mistake - this is used for the internal development versions
where the interface has been changing and I forgot to remove it for the RFC.

> 
>> +	wait_event_interruptible(ctx->waitq,
>> +				 READ_ONCE(domain->assigned_ctx) == ctx ||
>> +				 cla_ctx_is_dying(ctx) ||
>> +				 READ_ONCE(domain->broken));
> 
> If you call wait_event_interruptible(), you have to check the return
> code and deal with it being interrupted.

I believe this is already correct - I'm reeturning VM_FAULT_RETRY
unconditionally at this point, which is also the correct return code if we get
interrupted. This unwinds to arm64's do_page_fault() which then notices and
handles the fault:

	/* Quick path to respond to signals */
	if (fault_signal_pending(fault, regs)) {
		if (!user_mode(regs))
			goto no_context;
		return 0;
	}

I believe GUP and other handle_mm_fault() callers have similar logic.

I'll add a comment to make that clear.

> 
>> +static const struct file_operations cla_fops = {
>> +	.owner = THIS_MODULE,
>> +	.mmap = cla_file_mmap,
>> +	.unlocked_ioctl = cla_file_ioctl,
>> +#ifdef CONFIG_COMPAT
>> +	.compat_ioctl = cla_file_ioctl,
>> +#endif
> 
> No need for the #ifdef here. Technically setting .compat_ioctl=compat_ptr_ioctl
> is the correct way here, though that may change in the future now that
> s390 compat mode is gone.

ACK, I'll fix this.

Thanks,
Ryan


> 
>       Arnd


^ permalink raw reply

* Re: [PATCH v2 1/2] Docs/admin-guide/cgroup-v2: document io.latency rotational vs non-rotational behavior
From: Michal Koutný @ 2026-07-17 14:48 UTC (permalink / raw)
  To: Tao Cui
  Cc: Tejun Heo, Johannes Weiner, Jonathan Corbet, Josef Bacik,
	Jens Axboe, cgroups, linux-doc, linux-block, linux-kernel, cuitao
In-Reply-To: <20260717060225.2019764-2-cui.tao@linux.dev>

[-- Attachment #1: Type: text/plain, Size: 990 bytes --]

Hi.

On Fri, Jul 17, 2026 at 02:02:24PM +0800, Tao Cui <cui.tao@linux.dev> wrote:
> -		The sampling window size in milliseconds.  This is the minimum
> -		duration of time between evaluation events.  Windows only elapse
> -		with IO activity.  Idle periods extend the most recent window.
> +		(Rotational devices only.)  The sampling window size in
> +		milliseconds.  This is the minimum duration of time between
> +		evaluation events.  Windows only elapse with IO activity.  Idle
> +		periods extend the most recent window.
> +
> +	  missed
> +		(Non-rotational devices only.)  The number of IOs in the
> +		current window whose latency exceeded the target.

		A group is considered to be missing its target once
		missed reaches certain ratio of total.

I would not bind to the exact value in the docs and put the explanation
to the "missed" stanza.

Thanks for documenting missed (pun intended) fields.

Besides that
Acked-by: Michal Koutný <mkoutny@suse.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 265 bytes --]

^ permalink raw reply

* Re: [PATCH v2 2/2] Docs/admin-guide/cgroup-v2: fix delay_nsec unit in io.latency doc
From: Michal Koutný @ 2026-07-17 14:49 UTC (permalink / raw)
  To: Tao Cui
  Cc: Tejun Heo, Johannes Weiner, Jonathan Corbet, Josef Bacik,
	Jens Axboe, cgroups, linux-doc, linux-block, linux-kernel, cuitao
In-Reply-To: <20260717060225.2019764-3-cui.tao@linux.dev>

[-- Attachment #1: Type: text/plain, Size: 516 bytes --]

On Fri, Jul 17, 2026 at 02:02:25PM +0800, Tao Cui <cui.tao@linux.dev> wrote:
> From: Tao Cui <cuitao@kylinos.cn>
> 
> The io.latency doc says the io.stat delay field counts microseconds.  The
> field is delay_nsec and is reported in nanoseconds.  Refer to it by its
> real name and correct the unit.
> 
> Signed-off-by: Tao Cui <cuitao@kylinos.cn>
> ---
>  Documentation/admin-guide/cgroup-v2.rst | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)

Acked-by: Michal Koutný <mkoutny@suse.com>

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 265 bytes --]

^ permalink raw reply

* Re: [RFC PATCH v1 8/8] misc/arm-cla: Add userspace interface
From: Arnd Bergmann @ 2026-07-17 15:31 UTC (permalink / raw)
  To: Ryan Roberts, Greg Kroah-Hartman, Catalin Marinas, Will Deacon,
	Mark Rutland, Jean-Philippe Brucker, Oded Gabbay, Jonathan Corbet
  Cc: linux-kernel, linux-arm-kernel, dri-devel, linux-doc
In-Reply-To: <5012970d-a0f0-461c-b0b6-61823e0aab2d@arm.com>

On Fri, Jul 17, 2026, at 16:35, Ryan Roberts wrote:
> On 17/07/2026 13:54, Arnd Bergmann wrote:
>> On Fri, Jul 17, 2026, at 12:47, Ryan Roberts wrote:
>>> Expose CLA devices through a character device so userspace can enumerate
>>> the available hardware and map accelerator register frames.
>>>
>>> Define version 1 of the CLA UAPI with a GET_PARAM ioctl. Report device
>>> topology, CPU affinity, domain membership, mmap offsets, architecture
>>> version and attached accelerator masks, together with the IIDR, DEVARCH
>>> and REVIDR of each accelerator.
>>>
>>> CLA registers can only be read from the CPU local to the device, while
>>> enumeration may occur on any CPU. Validate the supported CLA
>>> architecture version during device setup and cache the CLA and
>>> accelerator identification registers for later ioctl queries.
>> 
>> This interface looks very raw at the moment, I expect this will have
>> one or more larger redesigns.
>
> Are you referring to the overall UABI or specifically to the ioctl interface
> here? I could imagine the ioctl interface evolving before we get this merged
> (although it is based on similar patterns used by some DRM and accel drivers -
> it's intended to be easily extensible while existing params remain stable).
>
> The aspect where the CLA MMIO is directly mapped into user space is an aspect we
> are keen to keep though since it has significant performance implications if we
> need to redirect through the kernel.

I see no problem with having a per-accelerator VM area for MMIO
operations mapped to userspace, this is obviously part of all
designs like this one that sneak custom coprocessor instructions
in by disguising them as MMIO.

My concern is about how userspace gets to that mapping, both
the chardev itself, but also the ioctls.

>> Most importantly, a single character device to expose an arbitrary
>> number of underlying hardware features is an inherently flawed security
>> model. If any specific accelerator is ever found to have a
>> major vulnerability, that would mean administrators will have to
>> disable all of them by default.
>
> Note that we are exposing MMIO per CLA, not per accelerator. So preventing
> access to a single CLA would prevent access to all accelerators attached to it.
> There is a per-accelerator availability masking control that the kernel can use
> to disable access to selected accelerators though, which might help with the
> vulnerability example.
>
> The rationale for choosing a single device file was driven by performance: At
> domain reassignment time, we need to unmap and invalidate the TLB entries for
> all the devices in the domain from the out-going process's address space. By
> having all the devices in a single file and all devices within the same domain
> adjacent, they can all be mapped to a single VMA, meaning the driver can use a
> single call to the existing zap_special_vma_range(), which will result in a
> single TLBI-by-range instruction, which is faster than a TLBI-by-va for every
> device.
>
> If you think it is important for security to have each CLA exposed by an
> independent device file, I'll take another look.

Without concrete implementation examples, I find it hard to imagine
how granular the CLA and accelerator blocks are. What I'm interested
in is separating things into special character devices when they
refer to units that you want to manage separately in userspace.

If you have e.g. one accelerator for tensor operations and one for
handling gzip, I would very much want to see those have a separate
chardev nodes so a local administrator can give permissions to each
one separately, and have device names that are sensible to the
functionality underneath.

If you have separate accelerators for AES encryption and decryption,
or a large set of identical accelerators that can run concurrently,
those would of course get managed as a single device file.

Most importantly, I don't think a global /dev/cla device node
is a sensible interface from a management perspective as that
would give unprivileged userspace direct control to something
that is essentially arbitrary (or buggy) vendor firmware
with DMA permissions.

>>> Support shared read-write mmap of one or more CLA register pages. Create
>>> a context for every domain covered by the mapping and resolve faults
>>> only while that context owns the domain. Queue unassigned contexts with
>>> the domain scheduler, drop mmap_lock while waiting for assignment and
>>> retry the fault after the context is woken.
>> 
>> I still need some time to better understand what this means.
>
> I can probably do a better job of explaining this: The kernel keeps a cla_ctx
> object which represents a single {file description, mm_struct} context that
> wants to use the cla_domain (collection of 1 or more cla_dev). Initially the VMA
> is not populated so when user space tries to access, it will fault to the
> driver. If the cla_domain is assigned to a different cla_ctx, the faulting
> thread is put to sleep until the driver determines that it's the turn of that
> cla_ctx to be assigned the domain. At that point the waiting thread(s) are woken
> and map the devices from the domain to the VMA and return to user space. The
> out-going cla_ctx had it's mappings removed during the reassignment process so
> any user space access will now fault and sleep waiting for assignment.

Got it, thanks

>> Does a CPU have multiple concurrently running contexts? 
>
> The HW only has a single HW context, hence the timesliced assignment approach
> described above (assuming there is more than 1 concurrent user).

Sorry, I think we have a clash of terminology. I meant whether
a CPU can start multiple operations on one or more accelerator
in a single cla_domain, and have each of those operate at the
same time while the hardware is asynchronously processing them
in parallel.

It sounds like a single accelerator has one register to wait for
completion and can only have single operation in progress at any
time, but if multiple accelerators are in the same cla_ctx,
can a single thread start an operation in each one before waiting
for the first to complete?

>> Is a
>> user process able to starve the allocation of other processes
>> by just requesting a lot of them?
>
> In the current code, a process can theoretically create the same number of
> cla_ctx as the number of file descriptors it can open(). It would then need to
> mmap and access to get into the queue to be assigned the domain. I see it as
> similar to threads; if process A creates 10 threads and process B creates 1
> thread, then in the long run (ignoring cgroups et al) you'd expect A to get
> 10/11th of the CPU time (IIUC?).
>
> Do you think this consitutes a DoS?

I need to think about it more. Probably not a DoS, but if the resource
is managed like CPU timeslices, I wonder whether you'd have to also
consider things like realtime tasks or priority inversion.
 
>>> +	wait_event_interruptible(ctx->waitq,
>>> +				 READ_ONCE(domain->assigned_ctx) == ctx ||
>>> +				 cla_ctx_is_dying(ctx) ||
>>> +				 READ_ONCE(domain->broken));
>> 
>> If you call wait_event_interruptible(), you have to check the return
>> code and deal with it being interrupted.
>
> I believe this is already correct - I'm reeturning VM_FAULT_RETRY
> unconditionally at this point, which is also the correct return code if we get
> interrupted. This unwinds to arm64's do_page_fault() which then notices and
> handles the fault:
>
> 	/* Quick path to respond to signals */
> 	if (fault_signal_pending(fault, regs)) {
> 		if (!user_mode(regs))
> 			goto no_context;
> 		return 0;
> 	}

Ok, makes sense.

> I believe GUP and other handle_mm_fault() callers have similar logic.
>
> I'll add a comment to make that clear.

Thanks

   Arnd

^ permalink raw reply

* Re: [RFC PATCH v1 1/8] misc/arm-cla: Add driver skeleton and documentation
From: Ryan Roberts @ 2026-07-17 15:44 UTC (permalink / raw)
  To: Arnd Bergmann, Greg Kroah-Hartman, Catalin Marinas, Will Deacon,
	Mark Rutland, Jean-Philippe Brucker, Oded Gabbay, Jonathan Corbet
  Cc: linux-kernel, linux-arm-kernel, dri-devel, linux-doc
In-Reply-To: <1e561b1a-2c87-4a23-b4da-126b333de8ba@app.fastmail.com>

Hi Arnd,

Thanks for all your fast feedback!...


On 17/07/2026 14:49, Arnd Bergmann wrote:
> On Fri, Jul 17, 2026, at 12:47, Ryan Roberts wrote:
>> From: Jean-Philippe Brucker <jpb@kernel.org>
>>
>> Add the initial Kconfig and build-system plumbing for the Arm Core Local
>> Accelerator driver.
>>
>> Introduce the common driver header and register definitions used by
>> later CLA support. The definitions cover the CLA MMIO frame, launch
>> response and status fields, standard accelerator registers, launch
>> opcodes, error codes and memory translation context state.
>>
>> Add documentation describing the CLA programming model, its CPU-local
>> MMIO access rules, userspace assignment model, domain grouping and
>> expected boot state.
> 
> I have a few more questions here. Most of the description and
> the design decisions make perfect sense to me, but there are
> a few things I don't understand from your current document.
> 
>> +The CLA supports up to 8 attached accelerators, which are accessed by
>> +programming the CLA's MMIO registers. Operations are launched to an 
>> accelerator
>> +and are polled for completion. CLA does not raise interrupts.
>> +
>> +            CPU                     CLA              Accel
>> +             |--- write DATA[7:0] -->|                 |
>> +             |--- write LAUNCH ----->|---- launch ---->|
>> +             |<--- poll LRESP -------|                 |
>> +             |                       |                 |
>> +             |<--- poll STATUS ------|<--- complete ---|
>> +
>> +Each operation can take a 512-bit payload in the DATA registers. After handling
>> +a LAUNCH write, CLA indicates the launch status in the LRESP register. A further
>> +operation can only be launched after LRESP indicates completion of the previous
>> +launch.
> 
> This sounds a lot like st64bv or st64bv0, passing an 8-word payload and returning
> a single word per accelerator operation with shared addressing.

We're actually passing 9 words here; 8 DATA words plus the LAUNCH word. CLA
supports only 64 bit aligned and sized accesses (other accesses are RAZ/WI) so
they have to be written as 9x64bit stores. Then poll using 64bit loads.

> 
> Why are there now two interfaces to do the same thing?

Good question. This is how the HW operates.

> 
> Can a user process use st64bv to do the four steps in a
> single instruction?

No, unfortunately not.

> 
>> +Some operations continue to run asynchronously on the accelerator after launch
>> +completion. In this case progress is tracked by polling the STATUS register.
>> +When the CLA updates the STATUS register, it also raises an event which will
>> +wake an in-progress WFE (wait for event) instruction on the local CPU.
> 
> The asynchronous interface seems very confusing.
> 
> How are page faults from the SVA master resolved during an
> asynchronous operation?

The STATUS register has a fault bit; the poller notices, reads fault info from
accelerator registers and takes actions to resolve the fault (which in practice
means access from user space on CPU and fault into the kernel to handle).

> 
> Can a CPU start multiple asynchronous operations concurrently?

Yes; STATUS indicates READY while it can accept more asynchronous operations
("comamnds").

> 
> Do these continue to run if the starting process is scheduled out
> and another process also tries to use CLA?

Yes; the driver manages assignment of a CLA to a process context completely
separately from the thread scheduler's decisions about which threads run on
which CPUs and when. If another process is scheduled onto the CPU and it
attempts to access it's VA for the CLA, it will fault into the driver's handler
and be put to sleep until the driver decides to reassign the CLA.

> 
>> +Faults during address translation are reported by the accelerator in its
>> +registers and in STATUS. While polling for work completion, software fixes up
>> +the faults and notifies the accelerator with RESOLVE operations.
> 
> I would like to understand the faulting part better. Which instruction
> specifically causes the fault, is that the poll STATUS read?

I'm not sure what you mean by "Which instruction specifically causes the fault".
A fault occurs within the accelerator if it tries to access a virtual address
that is not mapped by the page table or if the permissions of the mapping are
not sufficient, etc... The fact that the accelerator has faulted is reported to
the SW that is polling the accelerator's STATUS register within user space. That
SW is expected to trigger fault handling by the usual kernel mechanisms by
accessing the VA. Then it issues a RESOLVE operation to tell the accelerator it
can continue.

> 
>> +Inter-Accelerator Communication
>> +-------------------------------
>> +
>> +On some platforms, multiple accelerators, each attached to a separate CLA within
>> +a cluster, are also directly connected to each other via a shared bus to
>> +accelerate cooperation between accelerators. The accelerators sharing a bus
>> +cannot be isolated from each other. When collaborative operations are launched
>> +on each of the participating accelerators, they synchronize over the bus,
>> +stalling until all are ready.
> 
> Could you give an example what this model might be good for?

I can't currently share that information. I expect you might be able to have a
good guess though :)

> 
> Does this mean a user may have to start one operation on each CPU
> from a thread of the same process in order to get a result efficiently
> across a shared accelerator?

Yes, correct. User space threads don't need to be precisesly synchronized
because multiple operations can be queued.

> 
> I assume this will become clearer once you can show an example userspace
> application that uses this type of accelerator.

Yes indeed. As I said, Arm plans to open source a user space driver, but there
is no commitment on dates yet.

> 
>> +Intended SW Usage Model
>> +=======================
>> +
>> +CLA is designed for its PL0 MMIO frame to be mapped into user space  and for user
>> +space to directly launch accelerator operations and poll for completion. It has
>> +been observed that for some use cases, the operation execution time is small and
>> +a trip through the kernel would consume a significant amount of the CPU budget
>> +for preparing the next operation leading to a significant reduction in bandwidth
>> +through the accelerator.
> 
> Do you have any plans for in-kernel usage of the accelerators?
> I would assume that for things like cryptographic features, these
> make sense to be exposed to the kernel itself.

As per cover letter: "the initial (and currently only) target is a compute
engine". There are not any plans for crypto accelerators (or other things like
that). So haven't been considering this as something the kernel would want to
use directly.

(Sorry I'm being vague - I'm sure you appreciate I'm limited on what I can say
around the use cases for now).

> 
>> +User space software is expected to create a thread to drive each CLA it is
>> +using, and for each thread to be pinned to the CLA's local CPU.
> 
> What happens if multiple processes have the same chardev open and
> each mmap() that, e.g. after a fork()? Does each process see its
> own virtual instance of the accelerator and interact with it through
> the same physical MMIO register range but its own process address space,
> or do you have to rely on the registers being mapped only into a
> single mm_struct to prevent a process from messing with another process
> data?

The driver maintains a cla_ctx for each {file description, mm_struct} pair. So
in this case, even though the file description is shared between the parent and
child processes, they still have distinct mm_structs so still have separate
contexts allowing the driver to virtualize access correctly.

> 
>> +Saving and restoring the internal state of the accelerator is an optional
>> +feature. Current platforms only support it when the accelerator is idle, so
>> +preempting an accelerator causes work cancellation. Software must carefully
>> +consider how to balance forward-progress guarantees with preemption 
>> latency.
> 
> I'm not sure I understand this point. Do you mean any async operation
> that was started on an accelerator may fail due to preemption, so user
> space must be able to restart it?

Yes, at it's simplest. But it gets a bit complicated if you introduce the idea
of a priority to each cla_ctx. If a high priority context needs the HW
periodically and preempts a low priority context, if we just abort the low
priority work on preemption, it may never make forward progress. We've been
considering a grace period where the kernel will wait for the accelerators to
complete their current work (up to a certain timeout) before reassigning them to
the incomming context. But none of that is part of this RFC - I think that's
discussion that can come later once we have the basic shape of everything agreed.

Thanks,
Ryan

> 
>      Arnd


^ permalink raw reply

* Re: [RFC PATCH v1 1/8] misc/arm-cla: Add driver skeleton and documentation
From: Arnd Bergmann @ 2026-07-17 16:10 UTC (permalink / raw)
  To: Ryan Roberts, Greg Kroah-Hartman, Catalin Marinas, Will Deacon,
	Mark Rutland, Jean-Philippe Brucker, Oded Gabbay, Jonathan Corbet
  Cc: linux-kernel, linux-arm-kernel, dri-devel, linux-doc
In-Reply-To: <5f82ee6b-d106-4ae1-9b2c-5a817e3e43b9@arm.com>

On Fri, Jul 17, 2026, at 17:44, Ryan Roberts wrote:
> On 17/07/2026 14:49, Arnd Bergmann wrote:
>> On Fri, Jul 17, 2026, at 12:47, Ryan Roberts wrote:
>> This sounds a lot like st64bv or st64bv0, passing an 8-word payload and returning
>> a single word per accelerator operation with shared addressing.
>
> We're actually passing 9 words here; 8 DATA words plus the LAUNCH word. CLA
> supports only 64 bit aligned and sized accesses (other accesses are RAZ/WI) so
> they have to be written as 9x64bit stores. Then poll using 64bit loads.
>
>> 
>> Why are there now two interfaces to do the same thing?
>
> Good question. This is how the HW operates.
>
>> 
>> Can a user process use st64bv to do the four steps in a
>> single instruction?
>
> No, unfortunately not.
>

Ok

>> Can a CPU start multiple asynchronous operations concurrently?
>
> Yes; STATUS indicates READY while it can accept more asynchronous operations
> ("comamnds").

How does userspace know which operations have already completed
then? (not worried about this bit, just trying to understand)

>> Do these continue to run if the starting process is scheduled out
>> and another process also tries to use CLA?
>
> Yes; the driver manages assignment of a CLA to a process context completely
> separately from the thread scheduler's decisions about which threads run on
> which CPUs and when. If another process is scheduled onto the CPU and it
> attempts to access it's VA for the CLA, it will fault into the driver's handler
> and be put to sleep until the driver decides to reassign the CLA.

This part does sound dangerous, not in the sense that I think it's
fundamentally broken, but in the complexity it adds.

I wonder if it's feasible to simplify this by always canceling
any ongoing CLA operations during switch_mm():

Is there an upper bound on how long a single operation can take,
or a guarantee that an operation at least provides a partial result
in hardware?

From your earlier descriptions, it sounds like the CPU is usually
assumed to wait for completion with WFE anyway, so from the
scheduler's perspective, the thread is active while waiting for
the accelerator to complete a job (even if from hardware side
the CPU is powered down during WFE).

If this is how it generally operates, and the accelerator jobs
are usually fast, forcing the CLA TTBR0 to be the same as the
CPU TTBR0 would avoid the entire problem of unmapping the registers
on context switch, but instead let this hook into the same place
as the corresponding iommu_mm_data switch on x86, which seems
to handle this more nicely.

> I'm not sure what you mean by "Which instruction specifically causes the fault".
> A fault occurs within the accelerator if it tries to access a virtual address
> that is not mapped by the page table or if the permissions of the mapping are
> not sufficient, etc... The fact that the accelerator has faulted is reported to
> the SW that is polling the accelerator's STATUS register within user space. That
> SW is expected to trigger fault handling by the usual kernel mechanisms by
> accessing the VA. Then it issues a RESOLVE operation to tell the accelerator it
> can continue.

Got it now. I had assumed that the page fault is delivered asynchronously
to the kernel without user space getting involved. In this case, I think
the interface is actually cleaner, though it does add a little bit
of overhead for userspace having to decipher the status. 
 
>>> +User space software is expected to create a thread to drive each CLA it is
>>> +using, and for each thread to be pinned to the CLA's local CPU.
>> 
>> What happens if multiple processes have the same chardev open and
>> each mmap() that, e.g. after a fork()? Does each process see its
>> own virtual instance of the accelerator and interact with it through
>> the same physical MMIO register range but its own process address space,
>> or do you have to rely on the registers being mapped only into a
>> single mm_struct to prevent a process from messing with another process
>> data?
>
> The driver maintains a cla_ctx for each {file description, mm_struct} pair. So
> in this case, even though the file description is shared between the parent and
> child processes, they still have distinct mm_structs so still have separate
> contexts allowing the driver to virtualize access correctly.

Ok, got it.

     Arnd

^ permalink raw reply

* Re: [RFC PATCH v1 8/8] misc/arm-cla: Add userspace interface
From: Ryan Roberts @ 2026-07-17 16:21 UTC (permalink / raw)
  To: Arnd Bergmann, Greg Kroah-Hartman, Catalin Marinas, Will Deacon,
	Mark Rutland, Jean-Philippe Brucker, Oded Gabbay, Jonathan Corbet
  Cc: linux-kernel, linux-arm-kernel, dri-devel, linux-doc
In-Reply-To: <59d0c4d5-af53-410d-9bf8-8dd2ba17f697@app.fastmail.com>

On 17/07/2026 16:31, Arnd Bergmann wrote:
> On Fri, Jul 17, 2026, at 16:35, Ryan Roberts wrote:
>> On 17/07/2026 13:54, Arnd Bergmann wrote:
>>> On Fri, Jul 17, 2026, at 12:47, Ryan Roberts wrote:
>>>> Expose CLA devices through a character device so userspace can enumerate
>>>> the available hardware and map accelerator register frames.
>>>>
>>>> Define version 1 of the CLA UAPI with a GET_PARAM ioctl. Report device
>>>> topology, CPU affinity, domain membership, mmap offsets, architecture
>>>> version and attached accelerator masks, together with the IIDR, DEVARCH
>>>> and REVIDR of each accelerator.
>>>>
>>>> CLA registers can only be read from the CPU local to the device, while
>>>> enumeration may occur on any CPU. Validate the supported CLA
>>>> architecture version during device setup and cache the CLA and
>>>> accelerator identification registers for later ioctl queries.
>>>
>>> This interface looks very raw at the moment, I expect this will have
>>> one or more larger redesigns.
>>
>> Are you referring to the overall UABI or specifically to the ioctl interface
>> here? I could imagine the ioctl interface evolving before we get this merged
>> (although it is based on similar patterns used by some DRM and accel drivers -
>> it's intended to be easily extensible while existing params remain stable).
>>
>> The aspect where the CLA MMIO is directly mapped into user space is an aspect we
>> are keen to keep though since it has significant performance implications if we
>> need to redirect through the kernel.
> 
> I see no problem with having a per-accelerator VM area for MMIO
> operations mapped to userspace, this is obviously part of all
> designs like this one that sneak custom coprocessor instructions
> in by disguising them as MMIO.
> 
> My concern is about how userspace gets to that mapping, both
> the chardev itself, but also the ioctls.

OK thanks for the clarification.

> 
>>> Most importantly, a single character device to expose an arbitrary
>>> number of underlying hardware features is an inherently flawed security
>>> model. If any specific accelerator is ever found to have a
>>> major vulnerability, that would mean administrators will have to
>>> disable all of them by default.
>>
>> Note that we are exposing MMIO per CLA, not per accelerator. So preventing
>> access to a single CLA would prevent access to all accelerators attached to it.
>> There is a per-accelerator availability masking control that the kernel can use
>> to disable access to selected accelerators though, which might help with the
>> vulnerability example.
>>
>> The rationale for choosing a single device file was driven by performance: At
>> domain reassignment time, we need to unmap and invalidate the TLB entries for
>> all the devices in the domain from the out-going process's address space. By
>> having all the devices in a single file and all devices within the same domain
>> adjacent, they can all be mapped to a single VMA, meaning the driver can use a
>> single call to the existing zap_special_vma_range(), which will result in a
>> single TLBI-by-range instruction, which is faster than a TLBI-by-va for every
>> device.
>>
>> If you think it is important for security to have each CLA exposed by an
>> independent device file, I'll take another look.
> 
> Without concrete implementation examples, I find it hard to imagine
> how granular the CLA and accelerator blocks are. What I'm interested
> in is separating things into special character devices when they
> refer to units that you want to manage separately in userspace.
> 
> If you have e.g. one accelerator for tensor operations and one for
> handling gzip, I would very much want to see those have a separate
> chardev nodes so a local administrator can give permissions to each
> one separately, and have device names that are sensible to the
> functionality underneath.

Unfortunately this doesn't map well to the HW: the MMIO is for the CLA interface
(each CPU has 1 CLA). Once you have access to that interface, you can
communicate with all of the accelerators that are connected to the CLA. We could
potentially use the availability masking control to only expose a single
accelerator for a given context (which would be chosen based on which file you
opened), but it wouldn't be possible for (e.g.) 2 different processes to access
the different accelerators concurrently - they would have to be subject to the
time slice model.

I'll think harder about what we might be able to do though.

> 
> If you have separate accelerators for AES encryption and decryption,
> or a large set of identical accelerators that can run concurrently,
> those would of course get managed as a single device file.
> 
> Most importantly, I don't think a global /dev/cla device node
> is a sensible interface from a management perspective as that
> would give unprivileged userspace direct control to something
> that is essentially arbitrary (or buggy) vendor firmware
> with DMA permissions.

OK I see your point.

While the interface supports up to 8 connected accelerators, we anticpate there
only being a single compute accelerator in practice. We decided to keep the
driver interface generic given the CLA spec, but perhaps it would be more
straightforward to limit the driver implementation to only permitting a single
accelerator?

> 
>>>> Support shared read-write mmap of one or more CLA register pages. Create
>>>> a context for every domain covered by the mapping and resolve faults
>>>> only while that context owns the domain. Queue unassigned contexts with
>>>> the domain scheduler, drop mmap_lock while waiting for assignment and
>>>> retry the fault after the context is woken.
>>>
>>> I still need some time to better understand what this means.
>>
>> I can probably do a better job of explaining this: The kernel keeps a cla_ctx
>> object which represents a single {file description, mm_struct} context that
>> wants to use the cla_domain (collection of 1 or more cla_dev). Initially the VMA
>> is not populated so when user space tries to access, it will fault to the
>> driver. If the cla_domain is assigned to a different cla_ctx, the faulting
>> thread is put to sleep until the driver determines that it's the turn of that
>> cla_ctx to be assigned the domain. At that point the waiting thread(s) are woken
>> and map the devices from the domain to the VMA and return to user space. The
>> out-going cla_ctx had it's mappings removed during the reassignment process so
>> any user space access will now fault and sleep waiting for assignment.
> 
> Got it, thanks
> 
>>> Does a CPU have multiple concurrently running contexts? 
>>
>> The HW only has a single HW context, hence the timesliced assignment approach
>> described above (assuming there is more than 1 concurrent user).
> 
> Sorry, I think we have a clash of terminology. I meant whether
> a CPU can start multiple operations on one or more accelerator
> in a single cla_domain, and have each of those operate at the
> same time while the hardware is asynchronously processing them
> in parallel.
> 
> It sounds like a single accelerator has one register to wait for
> completion and can only have single operation in progress at any
> time, but if multiple accelerators are in the same cla_ctx,
> can a single thread start an operation in each one before waiting
> for the first to complete?

CLAs can only be accessed/controlled from their local CPU. The expected model is
that you have a thread per CLA (pinned to the CPU) to submit operations only for
it's local CLA.

> 
>>> Is a
>>> user process able to starve the allocation of other processes
>>> by just requesting a lot of them?
>>
>> In the current code, a process can theoretically create the same number of
>> cla_ctx as the number of file descriptors it can open(). It would then need to
>> mmap and access to get into the queue to be assigned the domain. I see it as
>> similar to threads; if process A creates 10 threads and process B creates 1
>> thread, then in the long run (ignoring cgroups et al) you'd expect A to get
>> 10/11th of the CPU time (IIUC?).
>>
>> Do you think this consitutes a DoS?
> 
> I need to think about it more. Probably not a DoS, but if the resource
> is managed like CPU timeslices, I wonder whether you'd have to also
> consider things like realtime tasks or priority inversion.

Yes... we are considering realtime. I was trying not to dump too much into the
initial RFC though :)

Thanks,
Ryan


>  
>>>> +	wait_event_interruptible(ctx->waitq,
>>>> +				 READ_ONCE(domain->assigned_ctx) == ctx ||
>>>> +				 cla_ctx_is_dying(ctx) ||
>>>> +				 READ_ONCE(domain->broken));
>>>
>>> If you call wait_event_interruptible(), you have to check the return
>>> code and deal with it being interrupted.
>>
>> I believe this is already correct - I'm reeturning VM_FAULT_RETRY
>> unconditionally at this point, which is also the correct return code if we get
>> interrupted. This unwinds to arm64's do_page_fault() which then notices and
>> handles the fault:
>>
>> 	/* Quick path to respond to signals */
>> 	if (fault_signal_pending(fault, regs)) {
>> 		if (!user_mode(regs))
>> 			goto no_context;
>> 		return 0;
>> 	}
> 
> Ok, makes sense.
> 
>> I believe GUP and other handle_mm_fault() callers have similar logic.
>>
>> I'll add a comment to make that clear.
> 
> Thanks
> 
>    Arnd


^ permalink raw reply

* Re: [PATCH v3] scripts/kernel-doc: Suggest possible names for excess descriptions
From: Randy Dunlap @ 2026-07-17 16:28 UTC (permalink / raw)
  To: Ryszard Knop, linux-doc
  Cc: Jonathan Corbet, Shuicheng Lin, Jani Nikula, linux-kernel,
	intel-xe
In-Reply-To: <20260717125753.634550-1-ryszard.knop@intel.com>



On 7/17/26 5:57 AM, Ryszard Knop wrote:
> Recent check_sections() change added a warning if a documentation tag
> member name does not match the detected struct/union member names. Since
> the checker knows all possible names, we can suggest known names, so
> that it's more obvious how to deal with the warning.
> 
> Signed-off-by: Ryszard Knop <ryszard.knop@intel.com>

Tested-by: Randy Dunlap <rdunlap@infradead.org>
Acked-by: Randy Dunlap <rdunlap@infradead.org>

Thanks.

> ---
> Changes in v1:
> - Added the suggestion hint in the warning, with basic name substring checks
> - Link: https://lore.kernel.org/linux-doc/20260714111208.323108-1-ryszard.knop@intel.com/
> 
> Changes in v2:
> - Strip trailing whitespace from the warning when the generated hint is empty
> - Link: https://lore.kernel.org/linux-doc/20260715111726.394565-1-ryszard.knop@intel.com/
> 
> v3:
> - Use difflib to generate suggestions even if the tag member is mistyped
> - Suggest names based on the nested struct members too
> ---
>  tools/lib/python/kdoc/kdoc_parser.py | 51 ++++++++++++++++++++++++++--
>  1 file changed, 49 insertions(+), 2 deletions(-)
> 
> diff --git a/tools/lib/python/kdoc/kdoc_parser.py b/tools/lib/python/kdoc/kdoc_parser.py
> index 2dedda215c22..884f42584667 100644
> --- a/tools/lib/python/kdoc/kdoc_parser.py
> +++ b/tools/lib/python/kdoc/kdoc_parser.py
> @@ -11,6 +11,7 @@ and extract embedded documentation comments from it.
>  
>  import sys
>  import re
> +import difflib
>  from pprint import pformat
>  
>  from kdoc.c_lex import CTokenizer, tokenizer_set_log
> @@ -558,6 +559,50 @@ class KernelDoc:
>                          self.push_parameter(ln, decl_type, param, dtype,
>                                              arg, declaration_name)
>  
> +    def get_suggestions_hint(self, decl_name, possible_names):
> +        # For decl name 'flags' or 'flgas', suggests 'substruct.flags'
> +        submember_exact = []
> +        submember_substrings = []
> +        submember_suggestions = []
> +        for possible_name in possible_names:
> +            parts = possible_name.strip().split('.')
> +            if len(parts) < 2:
> +                continue
> +
> +            final_part = parts[-1]
> +            if decl_name == final_part:
> +                submember_exact.append(possible_name)
> +            elif decl_name in final_part:
> +                submember_substrings.append(possible_name)
> +            elif difflib.get_close_matches(decl_name, [final_part]):
> +                submember_suggestions.append(possible_name)
> +
> +        # For decl name 'flgas', suggests 'flags'
> +        full_suggestions = difflib.get_close_matches(decl_name, possible_names)
> +
> +        # For decl name 'member', suggests 'longer_member'
> +        full_substrings = [name for name in possible_names if decl_name in name]
> +
> +        ordered_lists = [
> +            submember_exact,
> +            submember_substrings,
> +            submember_suggestions,
> +            full_suggestions,
> +            full_substrings,
> +        ]
> +
> +        # Deduplicate but maintain order from most to least likely:
> +        unique_suggestions = {}
> +        for suggestion_list in ordered_lists:
> +            for suggestion in suggestion_list:
> +                unique_suggestions[suggestion] = None
> +
> +        suggestions = list(unique_suggestions.keys())
> +        if not suggestions:
> +            return ""
> +
> +        return f"(did you mean one of: '{"', '".join(suggestions)}')"
> +
>      def check_sections(self, ln, decl_name, decl_type):
>          """
>          Check for errors inside sections, emitting warnings if not found
> @@ -566,12 +611,13 @@ class KernelDoc:
>          for section in self.entry.sections:
>              if section not in self.entry.parameterlist and \
>                 not known_sections.search(section):
> +                hint = self.get_suggestions_hint(section, self.entry.parameterlist)
>                  if decl_type == 'function':
>                      dname = f"{decl_type} parameter"
>                  else:
>                      dname = f"{decl_type} member"
>                  self.emit_msg(ln,
> -                              f"Excess {dname} '{section}' description in '{decl_name}'")
> +                              f"Excess {dname} '{section}' description in '{decl_name}' {hint}".strip())
>  
>          #
>          # Check that documented parameter names (from doc comments, including
> @@ -591,12 +637,13 @@ class KernelDoc:
>              if param_name in self.entry.parameterlist:
>                  continue
>  
> +            hint = self.get_suggestions_hint(param_name, self.entry.parameterlist)
>              if decl_type == 'function':
>                  dname = f"{decl_type} parameter"
>              else:
>                  dname = f"{decl_type} member"
>              self.emit_msg(ln,
> -                          f"Excess {dname} '{param_name}' description in '{decl_name}'")
> +                          f"Excess {dname} '{param_name}' description in '{decl_name}' {hint}".strip())
>  
>      def check_return_section(self, ln, declaration_name, return_type):
>          """

-- 
~Randy

^ permalink raw reply

* Re: [PATCH v9 00/10] tracing: wprobe: x86: Add wprobe for watchpoint
From: Borislav Petkov @ 2026-07-17 16:28 UTC (permalink / raw)
  To: Masami Hiramatsu (Google)
  Cc: Steven Rostedt, Peter Zijlstra, Ingo Molnar, x86, Jinchao Wang,
	Mathieu Desnoyers, Thomas Gleixner, Dave Hansen, H . Peter Anvin,
	Alexander Shishkin, Ian Rogers, linux-kernel, linux-trace-kernel,
	linux-doc, linux-perf-users
In-Reply-To: <178429796992.157981.3393977217853767915.stgit@devnote2>

Hi,

On Fri, Jul 17, 2026 at 11:19:30PM +0900, Masami Hiramatsu (Google) wrote:
> Here is the 9th version of the series for adding new wprobe (watch probe)

any chance you won't blast out your patchset every day?

Thx.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

^ permalink raw reply

* Re: [PATCH 1/3] docs/zh_CN: add process/applying-patches Chinese translation
From: Weijie Yuan @ 2026-07-17 16:43 UTC (permalink / raw)
  To: Alex Shi, Yanteng Si, Dongliang Mu, Jonathan Corbet, Shuah Khan
  Cc: linux-doc, linux-kernel
In-Reply-To: <b65902acdaa37438479b3739e907a9e0ff604c55.1784289654.git.wy@wyuan.org>

On Fri, Jul 17, 2026 at 08:07:42PM +0800, Weijie Yuan wrote:
> Translate .../process/applying-patches.rst into Chinese.
> 
> Update the translation through commit fa04150b8ef7
> ("Documentation: describe how to apply incremental stable patches")

Btw, I don't know how to write the commit message here.

I translated the entire article, but it's obvious that the latest
commit of the original English version only updated a part of it. So
the commit message written in accordance with the usual practices
and rules is obviously inappropriate.

I am more than willing to make the necessary revisions as per your
instructions.

Thanks.

^ permalink raw reply

* Re: [PATCH v2 2/2] mm/zswap: Support batch writeback in shrink_memcg()
From: Yosry Ahmed @ 2026-07-17 16:45 UTC (permalink / raw)
  To: Hao Jia
  Cc: akpm, tj, hannes, shakeel.butt, mhocko, mkoutny, nphamcs,
	chengming.zhou, muchun.song, roman.gushchin, linux-mm,
	linux-kernel, linux-doc, Hao Jia
In-Reply-To: <20260717085151.22822-3-jiahao.kernel@gmail.com>

On Fri, Jul 17, 2026 at 04:51:51PM +0800, Hao Jia wrote:
> From: Hao Jia <jiahao1@lixiang.com>
> 
> Currently, shrink_memcg() writes back at most one entry per-node during
> its traversal. This makes shrink_worker() inefficient, as it must
> repeatedly re-enter shrink_memcg() to make any substantial progress.
> Under high memory pressure, this can cause the writeback speed to be
> too slow to keep up with refaults, leading to zswap store failures and
> forcing pages to skip zswap and go directly to disk, which results in
> an LRU inversion.
> 
> To address this, extend shrink_memcg() and rewrite its LRU iteration logic
> to support batch writeback. Introduce the nr_to_scan parameter to bound how
> many pages are scanned per call. This enables batch writeback in the
> shrink_worker() path, while maintaining a low scan budget in the
> zswap_store() path.
> 
> Test Setup:
> - Total memory: 32 GB.
> - zswap settings: max_pool_percent=1, accept_threshold_percent=50,
>   shrinker_enabled=N.
> 
> Test Case 1:
> Allocate 512MB of anonymous pages and fill them with random data (to avoid
> compression), then use cgroup memory.reclaim to force a large amount of
> anonymous pages into zswap. At an interval of 2ms, allocate a 4K anonymous
> page where the first 4 bytes are random numbers and the rest are zeros, and
> then trigger a reclamation of this 4K anonymous page through cgroup
> memory.reclaim. When the pool threshold is reached, shrink_memcg() will
> be triggered.
> The test data after running for 120s is as follows:
>                                 Baseline       Patched
> shrink_worker wakeups              5,363            85
> shrink_memcg calls            11,373,201       180,928
> written_back pages                40,212        40,236
> zswap_store calls                161,190       168,741
>    store succeeded (ret=1)       102,743       127,644
>    store rejected (ret=0)         58,447        41,097
>    store reject rate                ~36%          ~24%
> pool_limit_hit delta              55,826        14,062
> pswpout                           98,659        81,333
> pswpin                                 2             1
> 
> Test Case 2:
> To consistently force zswap store failures and trigger shrink_worker(),
> the following stress-ng command was run for 120 seconds within a cgroup
> limited to a memory.max of 1G:
>    bash -c 'echo $$ > /sys/fs/cgroup/zswaptest/cgroup.procs ; \
>    exec stress-ng --vm 4 --vm-bytes 4G --vm-keep --vm-method rand-set -t \
> 120s -q'
> The test data after running for 120s is as follows:
>                                 Baseline       Patched
> shrink_worker wakeups              5,640           987
> shrink_memcg calls             8,481,500     2,504,818
> written_back pages                   260       768,576
> zswap_store calls              2,742,756     2,301,414
>    store succeeded (ret=1)       934,640     1,308,686
>    store rejected (ret=0)      1,808,116       992,728
>    store reject rate                ~66%          ~43%
> pool_limit_hit delta           1,181,310       101,593
> pswpout                        1,808,376     1,761,304
> pswpin                         4,288,497     3,902,658
> 
> Under identical workloads and runtimes, batching the zswap shrinker
> exhibits a significant reduction in both shrink_worker wakeups and
> shrink_memcg calls. Furthermore, the sharp drop in both pool_limit_hit
> and zswap_store rejections demonstrates that batching the zswap shrinker
> effectively mitigates zswap_store failures caused by hitting the pool
> limit. This significantly prevents pages from bypassing zswap and falling
> back directly to disk, thereby reducing LRU inversion.
> 
> Suggested-by: Yosry Ahmed <yosry@kernel.org>
> Signed-off-by: Hao Jia <jiahao1@lixiang.com>

Acked-by: Yosry Ahmed <yosry@kernel.org>

^ permalink raw reply

* Re: [PATCH v2 2/2] mm/zswap: Support batch writeback in shrink_memcg()
From: Nhat Pham @ 2026-07-17 16:46 UTC (permalink / raw)
  To: Hao Jia
  Cc: akpm, tj, hannes, shakeel.butt, mhocko, yosry, mkoutny,
	chengming.zhou, muchun.song, roman.gushchin, linux-mm,
	linux-kernel, linux-doc, Hao Jia
In-Reply-To: <20260717085151.22822-3-jiahao.kernel@gmail.com>

On Fri, Jul 17, 2026 at 1:52 AM Hao Jia <jiahao.kernel@gmail.com> wrote:
>
> From: Hao Jia <jiahao1@lixiang.com>
>
> Currently, shrink_memcg() writes back at most one entry per-node during
> its traversal. This makes shrink_worker() inefficient, as it must
> repeatedly re-enter shrink_memcg() to make any substantial progress.
> Under high memory pressure, this can cause the writeback speed to be
> too slow to keep up with refaults, leading to zswap store failures and
> forcing pages to skip zswap and go directly to disk, which results in
> an LRU inversion.
>
> To address this, extend shrink_memcg() and rewrite its LRU iteration logic
> to support batch writeback. Introduce the nr_to_scan parameter to bound how
> many pages are scanned per call. This enables batch writeback in the
> shrink_worker() path, while maintaining a low scan budget in the
> zswap_store() path.
>
> Test Setup:
> - Total memory: 32 GB.
> - zswap settings: max_pool_percent=1, accept_threshold_percent=50,
>   shrinker_enabled=N.
>
> Test Case 1:
> Allocate 512MB of anonymous pages and fill them with random data (to avoid
> compression), then use cgroup memory.reclaim to force a large amount of
> anonymous pages into zswap. At an interval of 2ms, allocate a 4K anonymous
> page where the first 4 bytes are random numbers and the rest are zeros, and
> then trigger a reclamation of this 4K anonymous page through cgroup
> memory.reclaim. When the pool threshold is reached, shrink_memcg() will
> be triggered.
> The test data after running for 120s is as follows:
>                                 Baseline       Patched
> shrink_worker wakeups              5,363            85
> shrink_memcg calls            11,373,201       180,928
> written_back pages                40,212        40,236
> zswap_store calls                161,190       168,741
>    store succeeded (ret=1)       102,743       127,644
>    store rejected (ret=0)         58,447        41,097
>    store reject rate                ~36%          ~24%
> pool_limit_hit delta              55,826        14,062
> pswpout                           98,659        81,333
> pswpin                                 2             1
>
> Test Case 2:
> To consistently force zswap store failures and trigger shrink_worker(),
> the following stress-ng command was run for 120 seconds within a cgroup
> limited to a memory.max of 1G:
>    bash -c 'echo $$ > /sys/fs/cgroup/zswaptest/cgroup.procs ; \
>    exec stress-ng --vm 4 --vm-bytes 4G --vm-keep --vm-method rand-set -t \
> 120s -q'
> The test data after running for 120s is as follows:
>                                 Baseline       Patched
> shrink_worker wakeups              5,640           987
> shrink_memcg calls             8,481,500     2,504,818
> written_back pages                   260       768,576
> zswap_store calls              2,742,756     2,301,414
>    store succeeded (ret=1)       934,640     1,308,686
>    store rejected (ret=0)      1,808,116       992,728
>    store reject rate                ~66%          ~43%
> pool_limit_hit delta           1,181,310       101,593
> pswpout                        1,808,376     1,761,304
> pswpin                         4,288,497     3,902,658
>

Acked-by: Nhat Pham <nphamcs@gmail.com>

^ permalink raw reply

* Re: [PATCH 2/2] mm/zswap: Support batch writeback in shrink_memcg()
From: Nhat Pham @ 2026-07-17 16:50 UTC (permalink / raw)
  To: Yosry Ahmed
  Cc: Hao Jia, akpm, tj, hannes, shakeel.butt, mhocko, mkoutny,
	chengming.zhou, muchun.song, roman.gushchin, linux-mm,
	linux-kernel, linux-doc, Hao Jia
In-Reply-To: <CAO9r8zMLGMpsQ+HbLA5SFSMEc_ctuZoScJMkybnXMp+_0MW-yQ@mail.gmail.com>

On Thu, Jul 16, 2026 at 1:35 PM Yosry Ahmed <yosry@kernel.org> wrote:
>
>
> It is a bit alarming that the store rejection rate is still 43% with
> batching, but we can worry about this later :)

Yeah I think it's unavoidable at the time the global shrinker is
awaken, unfortunately :( We need to kick off shrinking way ahead of
time if we want to avoid this, especially since the rate of zswap out
is going to be faster than the rate of writeback (CPU vs IO).

Sort of why we implement the proactive reclaimers :)

^ permalink raw reply

* Re: [PATCH 2/2] mm/zswap: Support batch writeback in shrink_memcg()
From: Yosry Ahmed @ 2026-07-17 16:55 UTC (permalink / raw)
  To: Nhat Pham
  Cc: Hao Jia, akpm, tj, hannes, shakeel.butt, mhocko, mkoutny,
	chengming.zhou, muchun.song, roman.gushchin, linux-mm,
	linux-kernel, linux-doc, Hao Jia
In-Reply-To: <CAKEwX=Patm4+gxtxwDYBFXFh+jfaOUSvtKtVZFvp=oQwNmdu1Q@mail.gmail.com>

On Fri, Jul 17, 2026 at 9:50 AM Nhat Pham <nphamcs@gmail.com> wrote:
>
> On Thu, Jul 16, 2026 at 1:35 PM Yosry Ahmed <yosry@kernel.org> wrote:
> >
> >
> > It is a bit alarming that the store rejection rate is still 43% with
> > batching, but we can worry about this later :)
>
> Yeah I think it's unavoidable at the time the global shrinker is
> awaken, unfortunately :( We need to kick off shrinking way ahead of
> time if we want to avoid this, especially since the rate of zswap out
> is going to be faster than the rate of writeback (CPU vs IO).
>
> Sort of why we implement the proactive reclaimers :)

Arguably, reclaim should wait for zswap writeback and retry, similar
to how allocators wakeup kswapd and retry, instead of just skipping
zswap. I was actually thinking about doing this at least for the memcg
limit case, eliminate the sync shrink_memcg(1) call in zswap_store()
and instead wakeup an async flusher and sleep.

A problem for another day I guess :)

^ permalink raw reply

* [PATCH v2] docs: pt_BR: process: Translate programming-language
From: Abel Philippe @ 2026-07-17 16:59 UTC (permalink / raw)
  To: danielmaraboo; +Cc: linux-doc, corbet, Abel Philippe

Translate the programming language documentation into Brazilian Portuguese.

Signed-off-by: Abel Philippe <le590616@gmail.com>
---
 pt_BR/index.rst                        |  2 +-
 pt_BR/process/programming-language.rst | 58 ++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 1 deletion(-)
 create mode 100644 pt_BR/process/programming-language.rst

diff --git a/pt_BR/index.rst b/pt_BR/index.rst
index 5b8b60cf930f..0b9748e8b986 100644
--- a/pt_BR/index.rst
+++ b/pt_BR/index.rst
@@ -83,4 +83,4 @@ kernel e sobre como ver seu trabalho integrado.
    Conformidade de DTS para SoC <process/maintainer-soc-clean-dts>
    Processo do subsistema KVM x86 <process/maintainer-kvm-x86>
    Adicionando uma Nova Chamada de Sistema <process/adding-syscalls>
-
+   Linguagem de progamação <process/programming-language>
diff --git a/pt_BR/process/programming-language.rst b/pt_BR/process/programming-language.rst
new file mode 100644
index 000000000000..1fc0a6be7f65
--- /dev/null
+++ b/pt_BR/process/programming-language.rst
@@ -0,0 +1,58 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Linguagem de programação 
+========================
+
+O kernel Linux é escrito na linguagem de programação C [c-language]_.
+Mais precisamente, ele é normalmente compilado com ``gcc`` [gcc]_
+sob ``-std=gnu11`` [gcc-c-dialect-options]_, o dialeto GNU da ISO C11.
+O compilador ``clang`` [clang]_ também é suportado; consulte a documentação em
+:ref:`Building Linux with Clang/LLVM <kbuild_llvm>`.
+
+Esse dialeto contém diversas extensões da linguagem [gnu-extensions]_,
+e muitas delas são utilizadas rotineiramente no kernel.
+
+Atributos
+---------
+
+Uma das extensões mais comuns utilizadas em todo o kernel são os atributos
+[gcc-attribute-syntax]_. Os atributos permitem introduzir
+semânticas definidas pela implementação em entidades da linguagem (como variáveis,
+funções ou tipos) sem a necessidade de realizar mudanças sintáticas
+significativas na linguagem (por exemplo, adicionando uma nova palavra-chave) [n2049]_.
+
+Em alguns casos, os atributos são opcionais (isto é, um compilador que não os
+suporte ainda deve produzir código correto, mesmo que ele seja mais lento ou
+não execute tantas verificações e diagnósticos durante a compilação).
+
+O kernel define pseudopalavras-chave (por exemplo, ``__pure``) em vez de usar
+diretamente a sintaxe de atributos do GNU (por exemplo, ``__attribute__((__pure__))``)
+para detectar quais deles podem ser utilizados e/ou para encurtar o código.
+
+Por favor, consulte ``include/linux/compiler_attributes.h`` para mais informações.
+
+Rust
+----
+
+O kernel tem suporte para a linguagem de programação Rust.
+[rust-language]_ sob ``CONFIG_RUST``. É compilado com o ``rustc`` [rustc]_ ``rustc`` [rustc]_
+sob ``--edition=2021`` [rust-editions]_. As edições são uma maneira de introduzir
+pequenas alterações na linguagem que não são retrocompatíveis.
+
+Além disso, alguns recursos instáveis ​​[rust-unstable-features]_ são utilizados no
+kernel. Recursos instáveis ​​podem sofrer alterações no futuro; portanto, é um
+objetivo importante chegar a um ponto em que apenas recursos estáveis ​​sejam utilizados.
+
+Consulte ``Documentation/rust/index.rst`` para obter mais informações.
+
+.. [c-language] http://www.open-std.org/jtc1/sc22/wg14/www/standards
+.. [gcc] https://gcc.gnu.org
+.. [clang] https://clang.llvm.org
+.. [gcc-c-dialect-options] https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html
+.. [gnu-extensions] https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html
+.. [gcc-attribute-syntax] https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html
+.. [n2049] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2049.pdf
+.. [rust-language] https://www.rust-lang.org
+.. [rustc] https://doc.rust-lang.org/rustc/
+.. [rust-editions] https://doc.rust-lang.org/edition-guide/editions/
+.. [rust-unstable-features] https://github.com/Rust-for-Linux/linux/issues/2
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH v2 1/2] Docs/admin-guide/cgroup-v2: document io.latency rotational vs non-rotational behavior
From: Tejun Heo @ 2026-07-17 17:23 UTC (permalink / raw)
  To: Michal Koutný, Tao Cui
  Cc: Johannes Weiner, Jonathan Corbet, Josef Bacik, Jens Axboe,
	cgroups, linux-doc, linux-block, linux-kernel, cuitao
In-Reply-To: <alpADmJBLHpHAS_G@localhost.localdomain>

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 227 bytes --]

Hello,

On Fri, Jul 17, 2026 at 04:48:40PM +0200, Michal Koutný wrote:
> I would not bind to the exact value in the docs and put the explanation
> to the "missed" stanza.

I'll wait for an updated version.

Thanks.

-- 
tejun

^ permalink raw reply

* Re: [PATCH v2 2/2] Docs/admin-guide/cgroup-v2: fix delay_nsec unit in io.latency doc
From: Tejun Heo @ 2026-07-17 17:23 UTC (permalink / raw)
  To: Tao Cui
  Cc: Johannes Weiner, Michal Koutný, Jonathan Corbet, Josef Bacik,
	Jens Axboe, cgroups, linux-doc, linux-block, linux-kernel, cuitao
In-Reply-To: <20260717060225.2019764-3-cui.tao@linux.dev>

Hello,

Applied 2/2 to cgroup/for-7.3 with Michal's ack added.

Thanks.

-- 
tejun

^ permalink raw reply

* Re: [RFC PATCH v2 00/13] mm/kwatch: dynamic hardware watchpoints for hunting memory corruption
From: Borislav Petkov @ 2026-07-17 18:10 UTC (permalink / raw)
  To: Dave Hansen
  Cc: Jinchao Wang, Andrew Morton, Peter Zijlstra, Thomas Gleixner,
	Steven Rostedt, Masami Hiramatsu, Ingo Molnar, Dave Hansen,
	H . Peter Anvin, x86, Arnaldo Carvalho de Melo, Namhyung Kim,
	Mark Rutland, Mathieu Desnoyers, David Hildenbrand,
	Jonathan Corbet, Matthew Wilcox, Alan Stern, Randy Dunlap,
	Alexander Potapenko, Marco Elver, Mike Rapoport, linux-kernel,
	linux-mm, linux-trace-kernel, linux-perf-users, linux-doc
In-Reply-To: <91f3486b-3b85-4b43-b099-0a5325643352@intel.com>

On Fri, Jul 17, 2026 at 06:41:49AM -0700, Dave Hansen wrote:
> On 7/17/26 05:50, Jinchao Wang wrote:
> >  24 files changed, 2115 insertions(+), 63 deletions(-)
> Reading this, I wonder how many kernel debugging features we need. I
> don't even think we have a centralized list of them. They all just live
> in their own silos.
> 
> This one really seems like a super specialized tool. It has to be
> enabled at compile time and specifically aimed at a specific function.
> 
> Maybe this should live off on the side for a while. If folks end up
> actually needing it, they can point their friendly LLM over to its tree.

Right, and in my mbox right under this mail thread there's a

https://lore.kernel.org/all/178429796992.157981.3393977217853767915.stgit@devnote2/

which Masami has been blasting almost every day this week which contains two
of the patches from this set here...

Looks to me like folks need to sit down and agree on strategy first.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

^ permalink raw reply

* Re: [PATCH v2] docs: pt_BR: process: Translate programming-language
From: Daniel Pereira @ 2026-07-17 18:54 UTC (permalink / raw)
  To: Abel Philippe; +Cc: linux-doc, corbet
In-Reply-To: <20260717165908.1040053-1-le590616@gmail.com>

Em sex., 17 de jul. de 2026 às 13:59, Abel Philippe
<le590616@gmail.com> escreveu:
>
> Translate the programming language documentation into Brazilian Portuguese.
>
> Signed-off-by: Abel Philippe <le590616@gmail.com>
> ---
>  pt_BR/index.rst                        |  2 +-
>  pt_BR/process/programming-language.rst | 58 ++++++++++++++++++++++++++
>  2 files changed, 59 insertions(+), 1 deletion(-)
>  create mode 100644 pt_BR/process/programming-language.rst
>
> diff --git a/pt_BR/index.rst b/pt_BR/index.rst
> index 5b8b60cf930f..0b9748e8b986 100644
> --- a/pt_BR/index.rst
> +++ b/pt_BR/index.rst
> @@ -83,4 +83,4 @@ kernel e sobre como ver seu trabalho integrado.
>     Conformidade de DTS para SoC <process/maintainer-soc-clean-dts>
>     Processo do subsistema KVM x86 <process/maintainer-kvm-x86>
>     Adicionando uma Nova Chamada de Sistema <process/adding-syscalls>
> -
> +   Linguagem de progamação <process/programming-language>

Hi Abel,

I noticed a small typo in pt_BR/index.rst: it should be 'programação'
instead of 'progamação'.
Additionally, could you please include a description of the changes
from version 1 to version 2? Providing a changelog makes it much
easier to track what was modified.


Best regards,

Daniel

^ permalink raw reply

* Re: [PATCH v7 01/12] PCI: liveupdate: Set up FLB handler for the PCI core
From: Pasha Tatashin @ 2026-07-17 19:28 UTC (permalink / raw)
  To: David Matlack
  Cc: kexec, linux-doc, linux-kernel, linux-mm, linux-pci,
	Adithya Jayachandran, Alexander Graf, Alex Williamson,
	Bjorn Helgaas, Chris Li, David Rientjes, Jacob Pan,
	Jason Gunthorpe, Jonathan Corbet, Josh Hilke, Leon Romanovsky,
	Lukas Wunner, Mike Rapoport, Parav Pandit, Pasha Tatashin,
	Pranjal Shrivastava, Pratyush Yadav, Saeed Mahameed,
	Samiullah Khawaja, Shuah Khan, Vipin Sharma, William Tu, Yi Liu
In-Reply-To: <20260710212616.1351130-2-dmatlack@google.com>

On Fri, 10 Jul 2026 21:26:04 +0000, David Matlack <dmatlack@google.com> wrote:
> diff --git a/drivers/pci/liveupdate.c b/drivers/pci/liveupdate.c
> new file mode 100644
> index 000000000000..899758883dd5
> --- /dev/null
> +++ b/drivers/pci/liveupdate.c
> @@ -0,0 +1,155 @@
> [ ... skip 50 lines ... ]
> +#include <linux/slab.h>
> +
> +/**
> + * struct pci_flb_outgoing - Outgoing PCI FLB object
> + * @ser: Pointer to the preserved struct pci_ser.
> + * @block_set: The KHO block set holding the outgoing devices.

AFAIK, these should be aligned after column:
@ser:       Pointer to ...
@block_set: The KHO block ...

> [ ... skip 26 lines ... ]
> +	ser->devices = 0;
> +
> +	outgoing->ser = ser;
> +	kho_block_set_init(&outgoing->block_set, sizeof(struct pci_dev_ser));
> +
> +	args->obj = outgoing;

Nit:
You could re-write the above:

args->obj = no_free_ptr(outgoing);

And declare outgoing like this:
struct pci_flb_outgoing *outgoing __free(kfree) = kzalloc_obj(*outgoing);

Also, remove kfree(outgoing) call.

>
> diff --git a/include/linux/kho/abi/pci.h b/include/linux/kho/abi/pci.h
> new file mode 100644
> index 000000000000..de549016807a
> --- /dev/null
> +++ b/include/linux/kho/abi/pci.h
> @@ -0,0 +1,58 @@
> [ ... skip 30 lines ... ]
> + * @domain: The device's PCI domain number (segment).
> + * @bdf: The device's PCI bus, device, and function number.
> + * @refcount: Reference count used by the PCI core to keep track of whether it
> + *            is done using a device's struct pci_dev_ser. The value of the
> + *            refcount is equal to 1 when the struct pci_dev_ser is in use, and
> + *            0 otherwise.

I believe descriptions must be aligned.

> + */
> +struct pci_dev_ser {
> +	u32 domain;
> +	u16 bdf;
> +	u16 refcount;
> +} __packed;
> +
> +/**
> + * struct pci_ser - PCI Subsystem Live Update State
> + *
> + * This struct tracks state about all devices that are being preserved across
> + * a Live Update for the next kernel.
> + *
> + * @nr_devices: The number of devices that were preserved.
> + * @devices: Physical address of the first KHO block containing pci_dev_ser.

I believe descriptions must be aligned.

Nit: Please order the included headers alphabetically.

Nit: Please order the included headers alphabetically.

-- 
Pasha Tatashin <pasha.tatashin@soleen.com>

^ 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