All of lore.kernel.org
 help / color / mirror / Atom feed
From: Beau Belgrave <beaub@linux.microsoft.com>
To: rostedt@goodmis.org, mhiramat@kernel.org
Cc: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
	ast@kernel.org
Subject: [PATCH] tracing/user_events: Use non-RCU context for enabler writes
Date: Tue, 16 May 2023 16:58:44 -0700	[thread overview]
Message-ID: <20230516235844.9303-1-beaub@linux.microsoft.com> (raw)

Currently when events are enabled/disabled a top level mm enumeration is
done in a non-RCU context, however, the enablers are still in a
RCU-context. Each enabler is updated via user_event_enabler_write() which
uses pin_user_pages_remote(). This function can reschedule and should not
be used from a RCU-context.

Use the same approach as the top level mm enumeration, which builds a
temporary list of target enablers within a RCU-context then exits. Then
use list from a non-RCU context when calling user_event_enabler_write().

Link: https://lore.kernel.org/all/20230515165707.hv65ekwp2djkjj5i@MacBook-Pro-8.local/
Fixes: 7235759084a4 ("tracing/user_events: Use remote writes for event enablement")
Reported-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
---
 kernel/trace/trace_events_user.c | 69 +++++++++++++++++++++++++-------
 1 file changed, 55 insertions(+), 14 deletions(-)

diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index b1ecd7677642..00d956e7e35a 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -96,12 +96,15 @@ struct user_event {
  * these to track enablement sites that are tied to an event.
  */
 struct user_event_enabler {
-	struct list_head	link;
-	struct user_event	*event;
-	unsigned long		addr;
+	struct list_head		link;
+	struct user_event		*event;
+	unsigned long			addr;
+
+	/* Used to build a list within RCU context for a non-RCU context. */
+	struct user_event_enabler	*next;
 
 	/* Track enable bit, flags, etc. Aligned for bitops. */
-	unsigned int		values;
+	unsigned int			values;
 };
 
 /* Bits 0-5 are for the bit to update upon enable/disable (0-63 allowed) */
@@ -165,6 +168,8 @@ static int user_event_parse(struct user_event_group *group, char *name,
 			    char *args, char *flags,
 			    struct user_event **newuser);
 
+static struct user_event_enabler
+*user_event_enabler_get_all(struct user_event_mm *mm, struct user_event *user);
 static struct user_event_mm *user_event_mm_get(struct user_event_mm *mm);
 static struct user_event_mm *user_event_mm_get_all(struct user_event *user);
 static void user_event_mm_put(struct user_event_mm *mm);
@@ -450,25 +455,28 @@ static bool user_event_enabler_exists(struct user_event_mm *mm,
 
 static void user_event_enabler_update(struct user_event *user)
 {
-	struct user_event_enabler *enabler;
 	struct user_event_mm *mm = user_event_mm_get_all(user);
+	struct user_event_enabler *enabler;
 	struct user_event_mm *next;
 	int attempt;
 
 	while (mm) {
 		next = mm->next;
+		enabler = user_event_enabler_get_all(mm, user);
+
+		if (unlikely(!enabler))
+			goto next_mm;
+
 		mmap_read_lock(mm->mm);
-		rcu_read_lock();
 
-		list_for_each_entry_rcu(enabler, &mm->enablers, link) {
-			if (enabler->event == user) {
-				attempt = 0;
-				user_event_enabler_write(mm, enabler, true, &attempt);
-			}
+		while (enabler) {
+			attempt = 0;
+			user_event_enabler_write(mm, enabler, true, &attempt);
+			enabler = enabler->next;
 		}
 
-		rcu_read_unlock();
 		mmap_read_unlock(mm->mm);
+next_mm:
 		user_event_mm_put(mm);
 		mm = next;
 	}
@@ -500,6 +508,35 @@ static bool user_event_enabler_dup(struct user_event_enabler *orig,
 	return true;
 }
 
+static struct user_event_enabler
+*user_event_enabler_get_all(struct user_event_mm *mm, struct user_event *user)
+{
+	struct user_event_enabler *found = NULL;
+	struct user_event_enabler *enabler;
+
+	lockdep_assert_held(&event_mutex);
+
+	/*
+	 * We need to get enablers from within a RCU context to a non-RCU
+	 * context quickly. We build a single linked list under the RCU
+	 * to enable this. Typically this is required for doing actions
+	 * on enablers that might sleep or schedule.
+	 */
+	rcu_read_lock();
+
+	list_for_each_entry_rcu(enabler, &mm->enablers, link) {
+		if (enabler->event == user) {
+			enabler->next = found;
+			found = enabler;
+			break;
+		}
+	}
+
+	rcu_read_unlock();
+
+	return found;
+}
+
 static struct user_event_mm *user_event_mm_get(struct user_event_mm *mm)
 {
 	refcount_inc(&mm->refcnt);
@@ -513,6 +550,8 @@ static struct user_event_mm *user_event_mm_get_all(struct user_event *user)
 	struct user_event_enabler *enabler;
 	struct user_event_mm *mm;
 
+	lockdep_assert_held(&event_mutex);
+
 	/*
 	 * We do not want to block fork/exec while enablements are being
 	 * updated, so we use RCU to walk the current tasks that have used
@@ -525,13 +564,15 @@ static struct user_event_mm *user_event_mm_get_all(struct user_event *user)
 	 */
 	rcu_read_lock();
 
-	list_for_each_entry_rcu(mm, &user_event_mms, link)
-		list_for_each_entry_rcu(enabler, &mm->enablers, link)
+	list_for_each_entry_rcu(mm, &user_event_mms, link) {
+		list_for_each_entry_rcu(enabler, &mm->enablers, link) {
 			if (enabler->event == user) {
 				mm->next = found;
 				found = user_event_mm_get(mm);
 				break;
 			}
+		}
+	}
 
 	rcu_read_unlock();
 

base-commit: 3862f86c1529fa0016de6344eb974877b4cd3838
-- 
2.25.1


                 reply	other threads:[~2023-05-16 23:58 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

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=20230516235844.9303-1-beaub@linux.microsoft.com \
    --to=beaub@linux.microsoft.com \
    --cc=ast@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-trace-kernel@vger.kernel.org \
    --cc=mhiramat@kernel.org \
    --cc=rostedt@goodmis.org \
    /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.