Tracepoints around __schedule() do not identify the boundaries of one
preempt_schedule_irq() invocation. The calling task may switch out and
resume on another CPU before the invocation returns.

Add events at entry to and return from preempt_schedule_irq(). Record the
calling task as the owner in both events so consumers can follow the
invocation across switches and migration. Sample the preempt count and
interrupt state before dispatching the callbacks.

The events bracket preempt_schedule_irq() only. They do not cover
architecture-specific interrupt-return work or establish that the helper
was reached from a physical interrupt.

Assisted-by: LLM
---
 include/trace/events/sched.h | 51 ++++++++++++++++++++++++++++++++++++
 kernel/sched/core.c          |  6 +++++
 2 files changed, 57 insertions(+)

diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 535860581f159..d0f510c35b02b 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -52,6 +52,57 @@ TRACE_EVENT(sched_kthread_stop_ret,
        TP_printk("ret=%d", __entry->ret)
 );
 
+DECLARE_EVENT_CLASS(sched_irq_preempt,
+
+       TP_PROTO(struct task_struct *owner, unsigned long pc, bool irq_off),
+
+       TP_ARGS(owner, pc, irq_off),
+
+       TP_STRUCT__entry(
+               __array(char, owner_comm, TASK_COMM_LEN)
+               __field(pid_t, owner_pid)
+               __field(unsigned long, pc)
+               __field(bool, irq_off)
+       ),
+
+       TP_fast_assign(
+               memcpy(__entry->owner_comm, owner->comm, TASK_COMM_LEN);
+               __entry->owner_pid = owner->pid;
+               __entry->pc = pc;
+               __entry->irq_off = irq_off;
+       ),
+
+       TP_printk("owner=%s/%d pc=0x%lx irq_off=%d",
+                 __entry->owner_comm, __entry->owner_pid,
+                 __entry->pc, __entry->irq_off)
+);
+
+/**
+ * sched_irq_preempt_entry - begin preempt_schedule_irq() processing
+ * @owner: task whose interrupted execution will resume after scheduling
+ * @pc: preempt count sampled at the call site, before tracing bookkeeping
+ * @irq_off: interrupt state sampled at the same call site
+ *
+ * Emitted after entry assertions and context-tracking setup, with zero
+ * preempt count and local interrupts disabled. Exception-return paths can
+ * also use this scheduler entrypoint.
+ */
+DEFINE_EVENT(sched_irq_preempt, sched_irq_preempt_entry,
+            TP_PROTO(struct task_struct *owner, unsigned long pc, bool 
irq_off),
+            TP_ARGS(owner, pc, irq_off));
+
+/**
+ * sched_irq_preempt_exit - original preempt_schedule_irq() invocation resumes
+ * @owner: task saved by the matching entry, possibly on a different CPU
+ * @pc: preempt count sampled at the call site, before tracing bookkeeping
+ * @irq_off: interrupt state sampled at the same call site
+ *
+ * Emitted with local interrupts disabled before restoring context tracking.
+ */
+DEFINE_EVENT(sched_irq_preempt, sched_irq_preempt_exit,
+            TP_PROTO(struct task_struct *owner, unsigned long pc, bool 
irq_off),
+            TP_ARGS(owner, pc, irq_off));
+
 /**
  * sched_kthread_work_queue_work - called when a work gets queued
  * @worker:    pointer to the kthread_worker
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 1754d9f95f2cf..b971a373ea3a1 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -7593,12 +7593,16 @@ EXPORT_SYMBOL(dynamic_preempt_schedule_notrace);
  */
 asmlinkage __visible void __sched preempt_schedule_irq(void)
 {
+       struct task_struct *owner = current;
        enum ctx_state prev_state;
 
        /* Catch callers which need to be fixed */
        BUG_ON(preempt_count() || !irqs_disabled());
 
        prev_state = exception_enter();
+       /* Sample before tracing bookkeeping can change the observed context. */
+       if (trace_sched_irq_preempt_entry_enabled())
+               trace_sched_irq_preempt_entry(owner, preempt_count(), 
irqs_disabled());
 
        do {
                preempt_disable();
@@ -7608,6 +7612,8 @@ asmlinkage __visible void __sched 
preempt_schedule_irq(void)
                sched_preempt_enable_no_resched();
        } while (need_resched());
 
+       if (trace_sched_irq_preempt_exit_enabled())
+               trace_sched_irq_preempt_exit(owner, preempt_count(), 
irqs_disabled());
        exception_exit(prev_state);
 }
 
-- 
2.39.5 (Apple Git-154)


Reply via email to