All of lore.kernel.org
 help / color / mirror / Atom feed
From: Beau Belgrave <beaub@linux.microsoft.com>
To: rostedt@goodmis.org, mhiramat@kernel.org, mathieu.desnoyers@efficios.com
Cc: linux-trace-devel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [RFC PATCH v2 5/7] tracing/user_events: Register with trace namespace API
Date: Thu, 28 Jul 2022 16:52:39 -0700	[thread overview]
Message-ID: <20220728235241.2249-6-beaub@linux.microsoft.com> (raw)
In-Reply-To: <20220728235241.2249-1-beaub@linux.microsoft.com>

Register user_events up to the trace namespace API to allow user
programs to interface with isolated events when required. Each namespace
will have their own user_events_status and user_events_data files that
have the same ABI as before, however, the system name for events created
will be different (user_events.<namespace_name> vs user_events).

Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
---
 kernel/trace/trace_events_user.c | 167 ++++++++++++++++++++++++++++++-
 1 file changed, 166 insertions(+), 1 deletion(-)

diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index 44f9efd58af5..9694eee27956 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -23,6 +23,10 @@
 #include "trace.h"
 #include "trace_dynevent.h"
 
+#ifdef CONFIG_TRACE_NAMESPACE
+#include "trace_namespace.h"
+#endif
+
 #define USER_EVENTS_PREFIX_LEN (sizeof(USER_EVENTS_PREFIX)-1)
 
 #define FIELD_DEPTH_TYPE 0
@@ -180,6 +184,18 @@ static void user_event_group_destroy(struct user_event_group *group)
 	kfree(group);
 }
 
+static void user_event_group_unlink(struct user_event_group *group)
+{
+	if (WARN_ON(refcount_read(&group->refcnt) != 1))
+		pr_warn("user_event: Group unlink with more than 1 ref\n");
+
+	mutex_lock(&group_mutex);
+	hash_del(&group->node);
+	mutex_unlock(&group_mutex);
+
+	user_event_group_destroy(group);
+}
+
 static char *user_event_group_system_name(const char *name)
 {
 	char *system_name;
@@ -262,6 +278,7 @@ static struct user_event_group *user_event_group_create(const char *name,
 
 	return group;
 error:
+	/* Hash table not added, safe to destroy vs unlink */
 	if (group)
 		user_event_group_destroy(group);
 
@@ -1905,6 +1922,148 @@ static int create_user_tracefs(struct dentry *parent,
 	return -ENODEV;
 }
 
+#ifdef CONFIG_TRACE_NAMESPACE
+static int user_event_ns_create(struct trace_namespace *ns)
+{
+	struct user_event_group *group;
+	int ret;
+
+	group = user_event_group_create(ns->name, ns->id);
+
+	if (!group)
+		return -ENOMEM;
+
+	ret = create_user_tracefs(ns->dir, group);
+
+	user_event_group_release(group);
+
+	if (ret) {
+		user_event_group_unlink(group);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int user_event_ns_remove(struct trace_namespace *ns)
+{
+	struct user_event_group *group = user_event_group_find(ns->id);
+	struct user_event *user;
+	struct hlist_node *tmp;
+	int i, ret = 0;
+
+	if (!group)
+		return -ENOENT;
+
+	/*
+	 * Lock out finding this namespace while we are doing this so that
+	 * user programs trying to open a file owned by this group will block
+	 * until we are done here. The user program upon unblocking will then
+	 * fail to find the group if we removed it.
+	 */
+	mutex_lock(&group_mutex);
+
+	/* Ensure we have the only reference */
+	if (refcount_read(&group->refcnt) != 2) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	/*
+	 * At this point no more files can be opened by user space programs
+	 * while we are holding the group_mutex (they'll block on group_mutex).
+	 * To ensure other parts of the kernel aren't registering something we
+	 * also grab the group register mutex as an extra precaution.
+	 *
+	 * The events might be being recorded, which will result in their
+	 * being busy and we'll bail out.
+	 *
+	 * NOTE: event_mutex is held, locking reg_mutex could deadlock so we
+	 * must try to lock it and treat as busy if we cannot.
+	 */
+	if (!mutex_trylock(&group->reg_mutex)) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	hash_for_each_safe(group->register_table, i, tmp, user, node) {
+		if (!user_event_last_ref(user)) {
+			ret = -EBUSY;
+			break;
+		}
+
+		ret = destroy_user_event(user);
+
+		if (ret)
+			break;
+	}
+
+	mutex_unlock(&group->reg_mutex);
+out:
+	mutex_unlock(&group_mutex);
+
+	user_event_group_release(group);
+
+	if (!ret)
+		user_event_group_unlink(group);
+
+	return ret;
+}
+
+static int user_event_ns_parse(struct trace_namespace *ns, const char *command)
+{
+	return -ECANCELED;
+}
+
+static int user_event_ns_show(struct trace_namespace *ns, struct seq_file *m)
+{
+	return 0;
+}
+
+static bool user_event_ns_is_busy(struct trace_namespace *ns)
+{
+	struct user_event_group *group = user_event_group_find(ns->id);
+	struct user_event *user;
+	int i;
+	bool busy = false;
+
+	if (!group)
+		return false;
+
+	/*
+	 * Quick check to ensure all events aren't busy:
+	 * The actual remove will do a more exhaustive check including
+	 * finding if any outstanding files are opened, etc.
+	 *
+	 * NOTE: event_mutex is held, locking reg_mutex could deadlock so we
+	 * must try to lock it and treat as busy if we cannot.
+	 */
+	if (!mutex_trylock(&group->reg_mutex))
+		return true;
+
+	hash_for_each(group->register_table, i, user, node) {
+		if (!user_event_last_ref(user)) {
+			busy = true;
+			break;
+		}
+	}
+
+	mutex_unlock(&group->reg_mutex);
+
+	user_event_group_release(group);
+
+	return busy;
+}
+
+static struct trace_namespace_operations user_event_ns_ops = {
+	.create = user_event_ns_create,
+	.remove = user_event_ns_remove,
+	.parse = user_event_ns_parse,
+	.show = user_event_ns_show,
+	.is_busy = user_event_ns_is_busy,
+};
+#endif
+
 static int __init trace_events_user_init(void)
 {
 	int ret;
@@ -1918,7 +2077,8 @@ static int __init trace_events_user_init(void)
 
 	if (ret) {
 		pr_warn("user_events could not register with tracefs\n");
-		user_event_group_destroy(root_group);
+		user_event_group_release(root_group);
+		user_event_group_unlink(root_group);
 		root_group = NULL;
 		return ret;
 	}
@@ -1926,6 +2086,11 @@ static int __init trace_events_user_init(void)
 	if (dyn_event_register(&user_event_dops))
 		pr_warn("user_events could not register with dyn_events\n");
 
+#ifdef CONFIG_TRACE_NAMESPACE
+	if (trace_namespace_register(&user_event_ns_ops))
+		pr_warn("user_events could not register with namespaces\n");
+#endif
+
 	return 0;
 }
 
-- 
2.25.1


  parent reply	other threads:[~2022-07-28 23:53 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-07-28 23:52 [RFC PATCH v2 0/7] tracing: Add tracing namespace API for user Beau Belgrave
2022-07-28 23:52 ` [RFC PATCH v2 1/7] tracing/user_events: Remove BROKEN and restore user_events.h location Beau Belgrave
2022-07-28 23:52 ` [RFC PATCH v2 2/7] tracing: Add namespace instance directory to tracefs Beau Belgrave
2022-07-28 23:52 ` [RFC PATCH v2 3/7] tracing: Add tracing namespace API for systems to register with Beau Belgrave
2022-07-28 23:52 ` [RFC PATCH v2 4/7] tracing/user_events: Move pages/locks into groups to prepare for namespaces Beau Belgrave
2022-07-28 23:52 ` Beau Belgrave [this message]
2022-07-28 23:52 ` [RFC PATCH v2 6/7] tracing/user_events: Enable setting event limit within namespace Beau Belgrave
2022-07-28 23:52 ` [RFC PATCH v2 7/7] tracing/user_events: Add self-test for namespace integration Beau Belgrave

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=20220728235241.2249-6-beaub@linux.microsoft.com \
    --to=beaub@linux.microsoft.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-trace-devel@vger.kernel.org \
    --cc=mathieu.desnoyers@efficios.com \
    --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.