diff --git a/kernel/trace/trace_remote.c b/kernel/trace/trace_remote.c
index a677b093fa07..08a89b7315c3 100644
--- a/kernel/trace/trace_remote.c
+++ b/kernel/trace/trace_remote.c
@@ -26,7 +26,6 @@ enum tri_type {
struct trace_remote_iterator {
struct trace_remote *remote;
struct trace_seq seq;
- struct delayed_work poll_work;
unsigned long lost_events;
u64 ts;
struct ring_buffer_iter *rb_iter;@@ -55,8 +54,10 @@ struct trace_remote {
struct rw_semaphore reader_lock;
struct rw_semaphore *pcpu_reader_locks;
unsigned int nr_readers;
+ unsigned int poll_cnt;
unsigned int poll_ms;
bool tracing_on;
+ struct delayed_work poll_work;
};
static DEFINE_MUTEX(trace_remotes_lock);@@ -351,17 +352,6 @@ static bool trace_remote_has_cpu(struct trace_remote *remote, int cpu)
return ring_buffer_poll_remote(remote->trace_buffer, cpu) == 0;
}
-static void __poll_remote(struct work_struct *work)
-{
- struct delayed_work *dwork = to_delayed_work(work);
- struct trace_remote_iterator *iter;
-
- iter = container_of(dwork, struct trace_remote_iterator, poll_work);
- ring_buffer_poll_remote(iter->remote->trace_buffer, iter->cpu);
- schedule_delayed_work((struct delayed_work *)work,
- msecs_to_jiffies(iter->remote->poll_ms));
-}
-
static void __free_ring_buffer_iter(struct trace_remote_iterator *iter, int cpu)
{
if (cpu != RING_BUFFER_ALL_CPUS) {@@ -405,6 +395,36 @@ static int __alloc_ring_buffer_iter(struct trace_remote_iterator *iter, int cpu)
return 0;
}
+static void trace_remote_do_poll(struct trace_remote *remote)
+{
+ ring_buffer_poll_remote(remote->trace_buffer, RING_BUFFER_ALL_CPUS);
+ schedule_delayed_work(&remote->poll_work, msecs_to_jiffies(remote->poll_ms));
+}
+
+static void __poll_remote(struct work_struct *work)
+{
+ struct delayed_work *dwork = to_delayed_work(work);
+
+ trace_remote_do_poll(container_of(dwork, struct trace_remote, poll_work));
+}
+
+static void trace_remote_inc_poll(struct trace_remote *remote)
+{
+ /* poll_cnt <= nr_readers, inherits its overflow protection */
+ if (!remote->poll_cnt++)
+ trace_remote_do_poll(remote);
+}
+
+static void trace_remote_dec_poll(struct trace_remote *remote)
+{
+ if (WARN_ON_ONCE(!remote->poll_cnt))
+ return;
+
+ remote->poll_cnt--;
+ if (!remote->poll_cnt)
+ cancel_delayed_work_sync(&remote->poll_work);
+}
+
static struct trace_remote_iterator
*trace_remote_iter(struct trace_remote *remote, int cpu, enum tri_type type)
{@@ -434,9 +454,7 @@ static struct trace_remote_iterator
switch (type) {
case TRI_CONSUMING:
- ring_buffer_poll_remote(remote->trace_buffer, cpu);
- INIT_DELAYED_WORK(&iter->poll_work, __poll_remote);
- schedule_delayed_work(&iter->poll_work, msecs_to_jiffies(remote->poll_ms));
+ trace_remote_inc_poll(remote);
break;
case TRI_NONCONSUMING:
ret = __alloc_ring_buffer_iter(iter, cpu);@@ -470,7 +488,7 @@ static void trace_remote_iter_free(struct trace_remote_iterator *iter)
switch (iter->type) {
case TRI_CONSUMING:
- cancel_delayed_work_sync(&iter->poll_work);
+ trace_remote_dec_poll(remote);
break;
case TRI_NONCONSUMING:
__free_ring_buffer_iter(iter, iter->cpu);@@ -1003,6 +1021,7 @@ int trace_remote_register(const char *name, struct trace_remote_callbacks *cbs,
remote->poll_ms = 100;
mutex_init(&remote->lock);
init_rwsem(&remote->reader_lock);
+ INIT_DELAYED_WORK(&remote->poll_work, __poll_remote);
guard(mutex)(&trace_remotes_lock);
--
2.56.0.455.g6c5a503b38-goog