From: Mohamed Ayman <mohamedaymanworkspace@gmail.com>
To: Suzuki K Poulose <suzuki.poulose@arm.com>,
Mike Leach <mike.leach@arm.com>,
James Clark <james.clark@linaro.org>, Leo Yan <leo.yan@arm.com>,
Alexander Shishkin <alexander.shishkin@linux.intel.com>,
Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
Clark Williams <clrkwllms@kernel.org>,
Steven Rostedt <rostedt@goodmis.org>,
coresight@lists.linaro.org (moderated list:ARM/CORESIGHT
FRAMEWORK AND DRIVERS),
linux-arm-kernel@lists.infradead.org (moderated
list:ARM/CORESIGHT FRAMEWORK AND DRIVERS),
linux-kernel@vger.kernel.org (open list),
linux-rt-devel@lists.linux.dev (open list:Real-time Linux
(PREEMPT_RT):Keyword:PREEMPT_RT)
Cc: Mohamed Ayman <mohamedaymanworkspace@gmail.com>,
coresight@lists.linaro.org (moderated list:ARM/CORESIGHT
FRAMEWORK AND DRIVERS),
linux-arm-kernel@lists.infradead.org (moderated
list:ARM/CORESIGHT FRAMEWORK AND DRIVERS),
linux-kernel@vger.kernel.org (open list),
linux-rt-devel@lists.linux.dev (open list:Real-time Linux
(PREEMPT_RT):Keyword:PREEMPT_RT)
Subject: [PATCH v2] coresight: Fix scheduling while atomic in coresight_put_percpu_source_ref()
Date: Tue, 14 Jul 2026 02:00:27 +0300 [thread overview]
Message-ID: <20260713230028.8046-1-mohamedaymanworkspace@gmail.com> (raw)
In-Reply-To: <20260712210446.14290-1-mohamedaymanworkspace@gmail.com>
Dropping the last reference to a coresight_device triggers a kernel panic
on PREEMPT_RT builds due to a "scheduling while atomic" violation.
During CPU idle transitions, coresight_cpu_pm_notify() runs with
interrupts disabled. It eventually calls put_device(), which can
synchronously trigger the device's release callback and drop the parent
device's reference. On PREEMPT_RT, free_percpu() takes a sleeping lock
(rt-mutex), and the parent's release callback might also sleep. Sleeping
in this atomic PM context crashes the system.
A previous patch tried deferring just the coresight_device_release() body,
but this still left the synchronous put_device() call dangerously exposed
to sleeping parent release functions.
Fix this by entirely deferring the put_device() call to process context.
We add a pending counter (put_pending) and a work_struct to the coresight
device. When releasing a reference, we increment the counter and queue
the work. A worker thread then safely drains the counter and calls
put_device(). The counter prevents leaking references if multiple puts
are queued before the worker even has a chance to run.
To prevent a use-after-free race condition during module unload, the work
is queued on a dedicated coresight_wq which is safely drained and
destroyed in coresight_exit().
Finally, remove the unnecessary raw_spinlock_irqsave in the put path,
as dropping a reference doesn't require protecting the per-CPU table.
Signed-off-by: Mohamed Ayman <mohamedaymanworkspace@gmail.com>
---
drivers/hwtracing/coresight/coresight-core.c | 37 ++++++++++++++------
include/linux/coresight.h | 3 ++
2 files changed, 30 insertions(+), 10 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 6d65c43d5..e931e6bdc 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -63,6 +63,8 @@ static LIST_HEAD(coresight_dev_idx_list);
static const struct cti_assoc_op *cti_assoc_ops;
+static struct workqueue_struct *coresight_wq;
+
static struct coresight_node *
coresight_path_first_node(struct coresight_path *path)
{
@@ -132,6 +134,16 @@ static void coresight_clear_percpu_source(struct coresight_device *csdev)
per_cpu(csdev_source, csdev->cpu) = NULL;
}
+static void coresight_put_device_work(struct work_struct *work)
+{
+ struct coresight_device *csdev =
+ container_of(work, struct coresight_device, put_work);
+ int n = atomic_xchg(&csdev->put_pending, 0);
+
+ while (n--)
+ put_device(&csdev->dev);
+}
+
struct coresight_device *coresight_get_percpu_source_ref(int cpu)
{
struct coresight_device *csdev;
@@ -163,16 +175,9 @@ void coresight_put_percpu_source_ref(struct coresight_device *csdev)
if (!csdev || !coresight_is_percpu_source(csdev))
return;
- guard(raw_spinlock_irqsave)(&coresight_dev_lock);
+ atomic_inc(&csdev->put_pending);
- /*
- * TODO: coresight_device_release() is invoked to release resources when
- * the device's refcount reaches zero. It then calls free_percpu(),
- * which acquires pcpu_lock — a sleepable lock when PREEMPT_RT is
- * enabled. Since the raw spinlock coresight_dev_lock is held, this can
- * lead to a potential "scheduling while atomic" issue.
- */
- put_device(&csdev->dev);
+ queue_work(coresight_wq, &csdev->put_work);
}
struct coresight_device *coresight_get_source(struct coresight_path *path)
@@ -1563,6 +1568,9 @@ coresight_init_device(struct coresight_desc *desc)
csdev->dev.release = coresight_device_release;
csdev->dev.bus = &coresight_bustype;
+ INIT_WORK(&csdev->put_work, coresight_put_device_work);
+ atomic_set(&csdev->put_pending, 0);
+
return csdev;
}
@@ -2090,9 +2098,13 @@ static int __init coresight_init(void)
{
int ret;
+ coresight_wq = alloc_workqueue("coresight_wq", 0, 0);
+ if (!coresight_wq)
+ return -ENOMEM;
+
ret = bus_register(&coresight_bustype);
if (ret)
- return ret;
+ goto exit_wq;
ret = etm_perf_init();
if (ret)
@@ -2121,6 +2133,8 @@ static int __init coresight_init(void)
etm_perf_exit();
exit_bus_unregister:
bus_unregister(&coresight_bustype);
+exit_wq:
+ destroy_workqueue(coresight_wq);
return ret;
}
@@ -2133,6 +2147,9 @@ static void __exit coresight_exit(void)
etm_perf_exit();
bus_unregister(&coresight_bustype);
coresight_release_device_list();
+
+ if (coresight_wq)
+ destroy_workqueue(coresight_wq);
}
module_init(coresight_init);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index ddf18c970..589a6c20d 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -13,6 +13,7 @@
#include <linux/perf_event.h>
#include <linux/sched.h>
#include <linux/platform_device.h>
+#include <linux/workqueue.h>
/* Peripheral id registers (0xFD0-0xFEC) */
#define CORESIGHT_PERIPHIDR4 0xfd0
@@ -293,6 +294,8 @@ struct coresight_device {
struct csdev_access access;
struct device dev;
struct coresight_path *path;
+ struct work_struct put_work;
+ atomic_t put_pending;
atomic_t mode;
int refcnt;
int cpu;
--
2.34.1
next prev parent reply other threads:[~2026-07-13 23:00 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-12 21:04 [PATCH] coresight: Fix scheduling while atomic in coresight_device_release() Mohamed Ayman
2026-07-12 21:17 ` sashiko-bot
2026-07-13 3:07 ` Jie Gan
2026-07-13 23:00 ` Mohamed Ayman [this message]
2026-07-13 23:17 ` [PATCH v2] coresight: Fix scheduling while atomic in coresight_put_percpu_source_ref() sashiko-bot
2026-07-14 10:42 ` Sebastian Andrzej Siewior
2026-07-14 19:42 ` MOHAMED AYMAN
2026-07-15 6:58 ` Sebastian Andrzej Siewior
2026-07-16 3:07 ` MOHAMED AYMAN
2026-07-16 12:32 ` Sebastian Andrzej Siewior
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260713230028.8046-1-mohamedaymanworkspace@gmail.com \
--to=mohamedaymanworkspace@gmail.com \
--cc=alexander.shishkin@linux.intel.com \
--cc=bigeasy@linutronix.de \
--cc=clrkwllms@kernel.org \
--cc=coresight@lists.linaro.org \
--cc=james.clark@linaro.org \
--cc=leo.yan@arm.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rt-devel@lists.linux.dev \
--cc=mike.leach@arm.com \
--cc=rostedt@goodmis.org \
--cc=suzuki.poulose@arm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.