All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/7] tracing/user_events: Update user_events ABI from
@ 2022-04-25 18:46 Beau Belgrave
  2022-04-25 18:46 ` [PATCH v2 1/7] tracing/user_events: Fix repeated word in comments Beau Belgrave
                   ` (6 more replies)
  0 siblings, 7 replies; 14+ messages in thread
From: Beau Belgrave @ 2022-04-25 18:46 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers
  Cc: linux-trace-devel, linux-kernel, linux-arch, beaub

This series covers the changes that were brought up once user_events went into
5.18. The largest change is moving away from byte index to a bit index, as
first suggested by Mathieu Desnoyers.

The other changes are either fixes that have accumulated or found by Mathieu.

NOTE: The sample and self-tests do not build unless you manually install
user_events.h into usr/include/linux.

Link:
https://lore.kernel.org/all/2059213643.196683.1648499088753.JavaMail.zimbra@efficios.com/

Psuedo code example of typical usage with the new ABI:
struct user_reg reg;

int page_fd = open("user_events_status", O_RDWR);
char *page_data = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, page_fd,
0);
close(page_fd);

int data_fd = open("user_events_data", O_RDWR);

reg.size = sizeof(reg);
reg.name_args = (__u64)"test";

ioctl(data_fd, DIAG_IOCSREG, &reg);
int status_id = reg.status_bit / 8;
int status_mask = 1 << (reg.status_bit % 8);
int write_id = reg.write_index;

struct iovec io[2];
io[0].iov_base = &write_id;
io[0].iov_len = sizeof(write_id);
io[1].iov_base = payload;
io[1].iov_len = sizeof(payload);

if (page_data[status_id] & status_mask)
	writev(data_fd, io, 2);

V2 Updates:
Changed from status_index and status_mask on user_reg to just status_bit.
Updated and added byte-wise and long-wise indexing pattern into docs.
Updated tests to use byte-wise index pattern.
Updated sample to show long-wise index pattern.

Beau Belgrave (7):
  tracing/user_events: Fix repeated word in comments
  tracing/user_events: Use NULL for strstr checks
  tracing/user_events: Use WRITE instead of READ for io vector import
  tracing/user_events: Ensure user provided strings are safely formatted
  tracing/user_events: Use refcount instead of atomic for ref tracking
  tracing/user_events: Use bits vs bytes for enabled status page data
  tracing/user_events: Update ABI documentation to align to bits vs
    bytes

 Documentation/trace/user_events.rst           |  86 ++++---
 include/linux/user_events.h                   |  15 +-
 kernel/trace/trace_events_user.c              | 212 ++++++++++++------
 samples/user_events/example.c                 |  25 ++-
 .../selftests/user_events/ftrace_test.c       |  47 +++-
 .../testing/selftests/user_events/perf_test.c |  11 +-
 6 files changed, 264 insertions(+), 132 deletions(-)


base-commit: 5cfff569cab8bf544bab62c911c5d6efd5af5e05
-- 
2.25.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 1/7] tracing/user_events: Fix repeated word in comments
  2022-04-25 18:46 [PATCH v2 0/7] tracing/user_events: Update user_events ABI from Beau Belgrave
@ 2022-04-25 18:46 ` Beau Belgrave
  2022-04-25 18:46 ` [PATCH v2 2/7] tracing/user_events: Use NULL for strstr checks Beau Belgrave
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Beau Belgrave @ 2022-04-25 18:46 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers
  Cc: linux-trace-devel, linux-kernel, linux-arch, beaub

Trivial fix to remove accidental double wording of have in comments.

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

diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index 706e1686b5eb..a6621c52ce45 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -567,7 +567,7 @@ static int user_event_set_call_visible(struct user_event *user, bool visible)
 	 * to allow user_event files to be less locked down. The extreme case
 	 * being "other" has read/write access to user_events_data/status.
 	 *
-	 * When not locked down, processes may not have have permissions to
+	 * When not locked down, processes may not have permissions to
 	 * add/remove calls themselves to tracefs. We need to temporarily
 	 * switch to root file permission to allow for this scenario.
 	 */
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 2/7] tracing/user_events: Use NULL for strstr checks
  2022-04-25 18:46 [PATCH v2 0/7] tracing/user_events: Update user_events ABI from Beau Belgrave
  2022-04-25 18:46 ` [PATCH v2 1/7] tracing/user_events: Fix repeated word in comments Beau Belgrave
@ 2022-04-25 18:46 ` Beau Belgrave
  2022-04-25 18:46 ` [PATCH v2 3/7] tracing/user_events: Use WRITE instead of READ for io vector import Beau Belgrave
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Beau Belgrave @ 2022-04-25 18:46 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers
  Cc: linux-trace-devel, linux-kernel, linux-arch, beaub

Trivial fix to ensure strstr checks use NULL instead of 0.

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

diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index a6621c52ce45..075d694d20e3 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -277,7 +277,7 @@ static int user_event_add_field(struct user_event *user, const char *type,
 	goto add_field;
 
 add_validator:
-	if (strstr(type, "char") != 0)
+	if (strstr(type, "char") != NULL)
 		validator_flags |= VALIDATOR_ENSURE_NULL;
 
 	validator = kmalloc(sizeof(*validator), GFP_KERNEL);
@@ -458,7 +458,7 @@ static const char *user_field_format(const char *type)
 		return "%d";
 	if (strcmp(type, "unsigned char") == 0)
 		return "%u";
-	if (strstr(type, "char[") != 0)
+	if (strstr(type, "char[") != NULL)
 		return "%s";
 
 	/* Unknown, likely struct, allowed treat as 64-bit */
@@ -479,7 +479,7 @@ static bool user_field_is_dyn_string(const char *type, const char **str_func)
 
 	return false;
 check:
-	return strstr(type, "char") != 0;
+	return strstr(type, "char") != NULL;
 }
 
 #define LEN_OR_ZERO (len ? len - pos : 0)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 3/7] tracing/user_events: Use WRITE instead of READ for io vector import
  2022-04-25 18:46 [PATCH v2 0/7] tracing/user_events: Update user_events ABI from Beau Belgrave
  2022-04-25 18:46 ` [PATCH v2 1/7] tracing/user_events: Fix repeated word in comments Beau Belgrave
  2022-04-25 18:46 ` [PATCH v2 2/7] tracing/user_events: Use NULL for strstr checks Beau Belgrave
@ 2022-04-25 18:46 ` Beau Belgrave
  2022-04-25 18:46 ` [PATCH v2 4/7] tracing/user_events: Ensure user provided strings are safely formatted Beau Belgrave
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Beau Belgrave @ 2022-04-25 18:46 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers
  Cc: linux-trace-devel, linux-kernel, linux-arch, beaub

import_single_range expects the direction/rw to be where it came from,
not the protection/limit. Since the import is in a write path use WRITE.

Link: https://lore.kernel.org/all/2059213643.196683.1648499088753.JavaMail.zimbra@efficios.com/

Reported-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
---
 kernel/trace/trace_events_user.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index 075d694d20e3..15edbf6b1e2e 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -1245,7 +1245,8 @@ static ssize_t user_events_write(struct file *file, const char __user *ubuf,
 	if (unlikely(*ppos != 0))
 		return -EFAULT;
 
-	if (unlikely(import_single_range(READ, (char *)ubuf, count, &iov, &i)))
+	if (unlikely(import_single_range(WRITE, (char __user *)ubuf,
+					 count, &iov, &i)))
 		return -EFAULT;
 
 	return user_events_write_core(file, &i);
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 4/7] tracing/user_events: Ensure user provided strings are safely formatted
  2022-04-25 18:46 [PATCH v2 0/7] tracing/user_events: Update user_events ABI from Beau Belgrave
                   ` (2 preceding siblings ...)
  2022-04-25 18:46 ` [PATCH v2 3/7] tracing/user_events: Use WRITE instead of READ for io vector import Beau Belgrave
@ 2022-04-25 18:46 ` Beau Belgrave
  2022-04-25 18:46 ` [PATCH v2 5/7] tracing/user_events: Use refcount instead of atomic for ref tracking Beau Belgrave
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 14+ messages in thread
From: Beau Belgrave @ 2022-04-25 18:46 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers
  Cc: linux-trace-devel, linux-kernel, linux-arch, beaub

User processes can provide bad strings that may cause issues or leak
kernel details back out. Don't trust the content of these strings
when formatting strings for matching.

This also moves to a consistent dynamic length string creation model.

Link: https://lore.kernel.org/all/2059213643.196683.1648499088753.JavaMail.zimbra@efficios.com/

Reported-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
---
 kernel/trace/trace_events_user.c | 91 +++++++++++++++++++++-----------
 1 file changed, 59 insertions(+), 32 deletions(-)

diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index 15edbf6b1e2e..f9bb7d37d76f 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -45,7 +45,6 @@
 #define MAX_EVENT_DESC 512
 #define EVENT_NAME(user_event) ((user_event)->tracepoint.name)
 #define MAX_FIELD_ARRAY_SIZE 1024
-#define MAX_FIELD_ARG_NAME 256
 
 static char *register_page_data;
 
@@ -483,6 +482,48 @@ static bool user_field_is_dyn_string(const char *type, const char **str_func)
 }
 
 #define LEN_OR_ZERO (len ? len - pos : 0)
+static int user_dyn_field_set_string(int argc, const char **argv, int *iout,
+				     char *buf, int len, bool *colon)
+{
+	int pos = 0, i = *iout;
+
+	*colon = false;
+
+	for (; i < argc; ++i) {
+		if (i != *iout)
+			pos += snprintf(buf + pos, LEN_OR_ZERO, " ");
+
+		pos += snprintf(buf + pos, LEN_OR_ZERO, "%s", argv[i]);
+
+		if (strchr(argv[i], ';')) {
+			++i;
+			*colon = true;
+			break;
+		}
+	}
+
+	/* Actual set, advance i */
+	if (len != 0)
+		*iout = i;
+
+	return pos + 1;
+}
+
+static int user_field_set_string(struct ftrace_event_field *field,
+				 char *buf, int len, bool colon)
+{
+	int pos = 0;
+
+	pos += snprintf(buf + pos, LEN_OR_ZERO, "%s", field->type);
+	pos += snprintf(buf + pos, LEN_OR_ZERO, " ");
+	pos += snprintf(buf + pos, LEN_OR_ZERO, "%s", field->name);
+
+	if (colon)
+		pos += snprintf(buf + pos, LEN_OR_ZERO, ";");
+
+	return pos + 1;
+}
+
 static int user_event_set_print_fmt(struct user_event *user, char *buf, int len)
 {
 	struct ftrace_event_field *field, *next;
@@ -926,49 +967,35 @@ static int user_event_free(struct dyn_event *ev)
 static bool user_field_match(struct ftrace_event_field *field, int argc,
 			     const char **argv, int *iout)
 {
-	char *field_name, *arg_name;
-	int len, pos, i = *iout;
+	char *field_name = NULL, *dyn_field_name = NULL;
 	bool colon = false, match = false;
+	int dyn_len, len;
 
-	if (i >= argc)
+	if (*iout >= argc)
 		return false;
 
-	len = MAX_FIELD_ARG_NAME;
-	field_name = kmalloc(len, GFP_KERNEL);
-	arg_name = kmalloc(len, GFP_KERNEL);
+	dyn_len = user_dyn_field_set_string(argc, argv, iout, dyn_field_name,
+					    0, &colon);
 
-	if (!arg_name || !field_name)
-		goto out;
-
-	pos = 0;
-
-	for (; i < argc; ++i) {
-		if (i != *iout)
-			pos += snprintf(arg_name + pos, len - pos, " ");
+	len = user_field_set_string(field, field_name, 0, colon);
 
-		pos += snprintf(arg_name + pos, len - pos, argv[i]);
-
-		if (strchr(argv[i], ';')) {
-			++i;
-			colon = true;
-			break;
-		}
-	}
+	if (dyn_len != len)
+		return false;
 
-	pos = 0;
+	dyn_field_name = kmalloc(dyn_len, GFP_KERNEL);
+	field_name = kmalloc(len, GFP_KERNEL);
 
-	pos += snprintf(field_name + pos, len - pos, field->type);
-	pos += snprintf(field_name + pos, len - pos, " ");
-	pos += snprintf(field_name + pos, len - pos, field->name);
+	if (!dyn_field_name || !field_name)
+		goto out;
 
-	if (colon)
-		pos += snprintf(field_name + pos, len - pos, ";");
+	user_dyn_field_set_string(argc, argv, iout, dyn_field_name,
+				  dyn_len, &colon);
 
-	*iout = i;
+	user_field_set_string(field, field_name, len, colon);
 
-	match = strcmp(arg_name, field_name) == 0;
+	match = strcmp(dyn_field_name, field_name) == 0;
 out:
-	kfree(arg_name);
+	kfree(dyn_field_name);
 	kfree(field_name);
 
 	return match;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 5/7] tracing/user_events: Use refcount instead of atomic for ref tracking
  2022-04-25 18:46 [PATCH v2 0/7] tracing/user_events: Update user_events ABI from Beau Belgrave
                   ` (3 preceding siblings ...)
  2022-04-25 18:46 ` [PATCH v2 4/7] tracing/user_events: Ensure user provided strings are safely formatted Beau Belgrave
@ 2022-04-25 18:46 ` Beau Belgrave
  2022-04-25 18:46 ` [PATCH v2 6/7] tracing/user_events: Use bits vs bytes for enabled status page data Beau Belgrave
  2022-04-25 18:46 ` [PATCH v2 7/7] tracing/user_events: Update ABI documentation to align to bits vs bytes Beau Belgrave
  6 siblings, 0 replies; 14+ messages in thread
From: Beau Belgrave @ 2022-04-25 18:46 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers
  Cc: linux-trace-devel, linux-kernel, linux-arch, beaub

User processes could open up enough event references to cause rollovers.
These could cause use after free scenarios, which we do not want.
Switching to refcount APIs prevent this, but will leak memory once
saturated.

Once saturated, user processes can still use the events. This prevents
a bad user process from stopping existing telemetry from being emitted.

Link: https://lore.kernel.org/all/2059213643.196683.1648499088753.JavaMail.zimbra@efficios.com/

Reported-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
---
 kernel/trace/trace_events_user.c | 53 +++++++++++++++-----------------
 1 file changed, 24 insertions(+), 29 deletions(-)

diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index f9bb7d37d76f..2bcae7abfa81 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -14,6 +14,7 @@
 #include <linux/uio.h>
 #include <linux/ioctl.h>
 #include <linux/jhash.h>
+#include <linux/refcount.h>
 #include <linux/trace_events.h>
 #include <linux/tracefs.h>
 #include <linux/types.h>
@@ -57,7 +58,7 @@ static DECLARE_BITMAP(page_bitmap, MAX_EVENTS);
  * within a file a user_event might be created if it does not
  * already exist. These are globally used and their lifetime
  * is tied to the refcnt member. These cannot go away until the
- * refcnt reaches zero.
+ * refcnt reaches one.
  */
 struct user_event {
 	struct tracepoint tracepoint;
@@ -67,7 +68,7 @@ struct user_event {
 	struct hlist_node node;
 	struct list_head fields;
 	struct list_head validators;
-	atomic_t refcnt;
+	refcount_t refcnt;
 	int index;
 	int flags;
 	int min_size;
@@ -105,6 +106,12 @@ static u32 user_event_key(char *name)
 	return jhash(name, strlen(name), 0);
 }
 
+static __always_inline __must_check
+bool user_event_last_ref(struct user_event *user)
+{
+	return refcount_read(&user->refcnt) == 1;
+}
+
 static __always_inline __must_check
 size_t copy_nofault(void *addr, size_t bytes, struct iov_iter *i)
 {
@@ -662,7 +669,7 @@ static struct user_event *find_user_event(char *name, u32 *outkey)
 
 	hash_for_each_possible(register_table, user, node, key)
 		if (!strcmp(EVENT_NAME(user), name)) {
-			atomic_inc(&user->refcnt);
+			refcount_inc(&user->refcnt);
 			return user;
 		}
 
@@ -876,12 +883,12 @@ static int user_event_reg(struct trace_event_call *call,
 
 	return ret;
 inc:
-	atomic_inc(&user->refcnt);
+	refcount_inc(&user->refcnt);
 	update_reg_page_for(user);
 	return 0;
 dec:
 	update_reg_page_for(user);
-	atomic_dec(&user->refcnt);
+	refcount_dec(&user->refcnt);
 	return 0;
 }
 
@@ -907,7 +914,7 @@ static int user_event_create(const char *raw_command)
 	ret = user_event_parse_cmd(name, &user);
 
 	if (!ret)
-		atomic_dec(&user->refcnt);
+		refcount_dec(&user->refcnt);
 
 	mutex_unlock(&reg_mutex);
 
@@ -951,14 +958,14 @@ static bool user_event_is_busy(struct dyn_event *ev)
 {
 	struct user_event *user = container_of(ev, struct user_event, devent);
 
-	return atomic_read(&user->refcnt) != 0;
+	return !user_event_last_ref(user);
 }
 
 static int user_event_free(struct dyn_event *ev)
 {
 	struct user_event *user = container_of(ev, struct user_event, devent);
 
-	if (atomic_read(&user->refcnt) != 0)
+	if (!user_event_last_ref(user))
 		return -EBUSY;
 
 	return destroy_user_event(user);
@@ -1137,8 +1144,8 @@ static int user_event_parse(char *name, char *args, char *flags,
 
 	user->index = index;
 
-	/* Ensure we track ref */
-	atomic_inc(&user->refcnt);
+	/* Ensure we track self ref and caller ref (2) */
+	refcount_set(&user->refcnt, 2);
 
 	dyn_event_init(&user->devent, &user_event_dops);
 	dyn_event_add(&user->devent, &user->call);
@@ -1164,29 +1171,17 @@ static int user_event_parse(char *name, char *args, char *flags,
 static int delete_user_event(char *name)
 {
 	u32 key;
-	int ret;
 	struct user_event *user = find_user_event(name, &key);
 
 	if (!user)
 		return -ENOENT;
 
-	/* Ensure we are the last ref */
-	if (atomic_read(&user->refcnt) != 1) {
-		ret = -EBUSY;
-		goto put_ref;
-	}
-
-	ret = destroy_user_event(user);
+	refcount_dec(&user->refcnt);
 
-	if (ret)
-		goto put_ref;
-
-	return ret;
-put_ref:
-	/* No longer have this ref */
-	atomic_dec(&user->refcnt);
+	if (!user_event_last_ref(user))
+		return -EBUSY;
 
-	return ret;
+	return destroy_user_event(user);
 }
 
 /*
@@ -1314,7 +1309,7 @@ static int user_events_ref_add(struct file *file, struct user_event *user)
 
 	new_refs->events[i] = user;
 
-	atomic_inc(&user->refcnt);
+	refcount_inc(&user->refcnt);
 
 	rcu_assign_pointer(file->private_data, new_refs);
 
@@ -1374,7 +1369,7 @@ static long user_events_ioctl_reg(struct file *file, unsigned long uarg)
 	ret = user_events_ref_add(file, user);
 
 	/* No longer need parse ref, ref_add either worked or not */
-	atomic_dec(&user->refcnt);
+	refcount_dec(&user->refcnt);
 
 	/* Positive number is index and valid */
 	if (ret < 0)
@@ -1464,7 +1459,7 @@ static int user_events_release(struct inode *node, struct file *file)
 		user = refs->events[i];
 
 		if (user)
-			atomic_dec(&user->refcnt);
+			refcount_dec(&user->refcnt);
 	}
 out:
 	file->private_data = NULL;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 6/7] tracing/user_events: Use bits vs bytes for enabled status page data
  2022-04-25 18:46 [PATCH v2 0/7] tracing/user_events: Update user_events ABI from Beau Belgrave
                   ` (4 preceding siblings ...)
  2022-04-25 18:46 ` [PATCH v2 5/7] tracing/user_events: Use refcount instead of atomic for ref tracking Beau Belgrave
@ 2022-04-25 18:46 ` Beau Belgrave
  2022-07-26 22:01   ` Steven Rostedt
  2022-04-25 18:46 ` [PATCH v2 7/7] tracing/user_events: Update ABI documentation to align to bits vs bytes Beau Belgrave
  6 siblings, 1 reply; 14+ messages in thread
From: Beau Belgrave @ 2022-04-25 18:46 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers
  Cc: linux-trace-devel, linux-kernel, linux-arch, beaub

User processes may require many events and when they do the cache
performance of a byte index status check is less ideal than a bit index.
The previous event limit per-page was 4096, the new limit is 32,768.

This change adds a bitwise index to the user_reg struct. Programs check
that the bit at status_bit has a bit set within the status page(s).

Link: https://lore.kernel.org/all/2059213643.196683.1648499088753.JavaMail.zimbra@efficios.com/

Suggested-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
---
 include/linux/user_events.h                   | 15 +----
 kernel/trace/trace_events_user.c              | 57 ++++++++++++++++---
 samples/user_events/example.c                 | 25 +++++---
 .../selftests/user_events/ftrace_test.c       | 47 ++++++++++++---
 .../testing/selftests/user_events/perf_test.c | 11 +++-
 5 files changed, 117 insertions(+), 38 deletions(-)

diff --git a/include/linux/user_events.h b/include/linux/user_events.h
index 736e05603463..592a3fbed98e 100644
--- a/include/linux/user_events.h
+++ b/include/linux/user_events.h
@@ -20,15 +20,6 @@
 #define USER_EVENTS_SYSTEM "user_events"
 #define USER_EVENTS_PREFIX "u:"
 
-/* Bits 0-6 are for known probe types, Bit 7 is for unknown probes */
-#define EVENT_BIT_FTRACE 0
-#define EVENT_BIT_PERF 1
-#define EVENT_BIT_OTHER 7
-
-#define EVENT_STATUS_FTRACE (1 << EVENT_BIT_FTRACE)
-#define EVENT_STATUS_PERF (1 << EVENT_BIT_PERF)
-#define EVENT_STATUS_OTHER (1 << EVENT_BIT_OTHER)
-
 /* Create dynamic location entry within a 32-bit value */
 #define DYN_LOC(offset, size) ((size) << 16 | (offset))
 
@@ -45,12 +36,12 @@ struct user_reg {
 	/* Input: Pointer to string with event name, description and flags */
 	__u64 name_args;
 
-	/* Output: Byte index of the event within the status page */
-	__u32 status_index;
+	/* Output: Bitwise index of the event within the status page */
+	__u32 status_bit;
 
 	/* Output: Index of the event to use when writing data */
 	__u32 write_index;
-};
+} __attribute__((__packed__));
 
 #define DIAG_IOC_MAGIC '*'
 
diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
index 2bcae7abfa81..4afc41e321ac 100644
--- a/kernel/trace/trace_events_user.c
+++ b/kernel/trace/trace_events_user.c
@@ -40,17 +40,26 @@
  */
 #define MAX_PAGE_ORDER 0
 #define MAX_PAGES (1 << MAX_PAGE_ORDER)
-#define MAX_EVENTS (MAX_PAGES * PAGE_SIZE)
+#define MAX_BYTES (MAX_PAGES * PAGE_SIZE)
+#define MAX_EVENTS (MAX_BYTES * 8)
 
 /* Limit how long of an event name plus args within the subsystem. */
 #define MAX_EVENT_DESC 512
 #define EVENT_NAME(user_event) ((user_event)->tracepoint.name)
 #define MAX_FIELD_ARRAY_SIZE 1024
 
+#define STATUS_BYTE(bit) ((bit) >> 3)
+#define STATUS_MASK(bit) (1 << ((bit) & 7))
+
+/* Internal bits to keep track of connected probes */
+#define EVENT_STATUS_FTRACE (1 << 0)
+#define EVENT_STATUS_PERF (1 << 1)
+#define EVENT_STATUS_OTHER (1 << 7)
+
 static char *register_page_data;
 
 static DEFINE_MUTEX(reg_mutex);
-static DEFINE_HASHTABLE(register_table, 4);
+static DEFINE_HASHTABLE(register_table, 8);
 static DECLARE_BITMAP(page_bitmap, MAX_EVENTS);
 
 /*
@@ -72,6 +81,7 @@ struct user_event {
 	int index;
 	int flags;
 	int min_size;
+	char status;
 };
 
 /*
@@ -106,6 +116,22 @@ static u32 user_event_key(char *name)
 	return jhash(name, strlen(name), 0);
 }
 
+static __always_inline
+void user_event_register_set(struct user_event *user)
+{
+	int i = user->index;
+
+	register_page_data[STATUS_BYTE(i)] |= STATUS_MASK(i);
+}
+
+static __always_inline
+void user_event_register_clear(struct user_event *user)
+{
+	int i = user->index;
+
+	register_page_data[STATUS_BYTE(i)] &= ~STATUS_MASK(i);
+}
+
 static __always_inline __must_check
 bool user_event_last_ref(struct user_event *user)
 {
@@ -648,7 +674,7 @@ static int destroy_user_event(struct user_event *user)
 
 	dyn_event_remove(&user->devent);
 
-	register_page_data[user->index] = 0;
+	user_event_register_clear(user);
 	clear_bit(user->index, page_bitmap);
 	hash_del(&user->node);
 
@@ -827,7 +853,12 @@ static void update_reg_page_for(struct user_event *user)
 		rcu_read_unlock_sched();
 	}
 
-	register_page_data[user->index] = status;
+	if (status)
+		user_event_register_set(user);
+	else
+		user_event_register_clear(user);
+
+	user->status = status;
 }
 
 /*
@@ -1332,7 +1363,17 @@ static long user_reg_get(struct user_reg __user *ureg, struct user_reg *kreg)
 	if (size > PAGE_SIZE)
 		return -E2BIG;
 
-	return copy_struct_from_user(kreg, sizeof(*kreg), ureg, size);
+	if (size < offsetofend(struct user_reg, write_index))
+		return -EINVAL;
+
+	ret = copy_struct_from_user(kreg, sizeof(*kreg), ureg, size);
+
+	if (ret)
+		return ret;
+
+	kreg->size = size;
+
+	return 0;
 }
 
 /*
@@ -1376,7 +1417,7 @@ static long user_events_ioctl_reg(struct file *file, unsigned long uarg)
 		return ret;
 
 	put_user((u32)ret, &ureg->write_index);
-	put_user(user->index, &ureg->status_index);
+	put_user(user->index, &ureg->status_bit);
 
 	return 0;
 }
@@ -1485,7 +1526,7 @@ static int user_status_mmap(struct file *file, struct vm_area_struct *vma)
 {
 	unsigned long size = vma->vm_end - vma->vm_start;
 
-	if (size != MAX_EVENTS)
+	if (size != MAX_BYTES)
 		return -EINVAL;
 
 	return remap_pfn_range(vma, vma->vm_start,
@@ -1520,7 +1561,7 @@ static int user_seq_show(struct seq_file *m, void *p)
 	mutex_lock(&reg_mutex);
 
 	hash_for_each(register_table, i, user, node) {
-		status = register_page_data[user->index];
+		status = user->status;
 		flags = user->flags;
 
 		seq_printf(m, "%d:%s", user->index, EVENT_NAME(user));
diff --git a/samples/user_events/example.c b/samples/user_events/example.c
index 4f5778e441c0..d06dc24156ec 100644
--- a/samples/user_events/example.c
+++ b/samples/user_events/example.c
@@ -12,13 +12,21 @@
 #include <fcntl.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <asm/bitsperlong.h>
+#include <endian.h>
 #include <linux/user_events.h>
 
+#if __BITS_PER_LONG == 64
+#define endian_swap(x) htole64(x)
+#else
+#define endian_swap(x) htole32(x)
+#endif
+
 /* Assumes debugfs is mounted */
 const char *data_file = "/sys/kernel/debug/tracing/user_events_data";
 const char *status_file = "/sys/kernel/debug/tracing/user_events_status";
 
-static int event_status(char **status)
+static int event_status(long **status)
 {
 	int fd = open(status_file, O_RDONLY);
 
@@ -33,7 +41,8 @@ static int event_status(char **status)
 	return 0;
 }
 
-static int event_reg(int fd, const char *command, int *status, int *write)
+static int event_reg(int fd, const char *command, long *index, long *mask,
+		     int *write)
 {
 	struct user_reg reg = {0};
 
@@ -43,7 +52,8 @@ static int event_reg(int fd, const char *command, int *status, int *write)
 	if (ioctl(fd, DIAG_IOCSREG, &reg) == -1)
 		return -1;
 
-	*status = reg.status_index;
+	*index = reg.status_bit / __BITS_PER_LONG;
+	*mask = endian_swap(1L << (reg.status_bit % __BITS_PER_LONG));
 	*write = reg.write_index;
 
 	return 0;
@@ -51,8 +61,9 @@ static int event_reg(int fd, const char *command, int *status, int *write)
 
 int main(int argc, char **argv)
 {
-	int data_fd, status, write;
-	char *status_page;
+	int data_fd, write;
+	long index, mask;
+	long *status_page;
 	struct iovec io[2];
 	__u32 count = 0;
 
@@ -61,7 +72,7 @@ int main(int argc, char **argv)
 
 	data_fd = open(data_file, O_RDWR);
 
-	if (event_reg(data_fd, "test u32 count", &status, &write) == -1)
+	if (event_reg(data_fd, "test u32 count", &index, &mask, &write) == -1)
 		return errno;
 
 	/* Setup iovec */
@@ -75,7 +86,7 @@ int main(int argc, char **argv)
 	getchar();
 
 	/* Check if anyone is listening */
-	if (status_page[status]) {
+	if (status_page[index] & mask) {
 		/* Yep, trace out our data */
 		writev(data_fd, (const struct iovec *)io, 2);
 
diff --git a/tools/testing/selftests/user_events/ftrace_test.c b/tools/testing/selftests/user_events/ftrace_test.c
index a80fb5ef61d5..404a2713dcae 100644
--- a/tools/testing/selftests/user_events/ftrace_test.c
+++ b/tools/testing/selftests/user_events/ftrace_test.c
@@ -22,6 +22,11 @@ const char *enable_file = "/sys/kernel/debug/tracing/events/user_events/__test_e
 const char *trace_file = "/sys/kernel/debug/tracing/trace";
 const char *fmt_file = "/sys/kernel/debug/tracing/events/user_events/__test_event/format";
 
+static inline int status_check(char *status_page, int status_bit)
+{
+	return status_page[status_bit >> 3] & (1 << (status_bit & 7));
+}
+
 static int trace_bytes(void)
 {
 	int fd = open(trace_file, O_RDONLY);
@@ -197,12 +202,12 @@ TEST_F(user, register_events) {
 	/* Register should work */
 	ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
 	ASSERT_EQ(0, reg.write_index);
-	ASSERT_NE(0, reg.status_index);
+	ASSERT_NE(0, reg.status_bit);
 
 	/* Multiple registers should result in same index */
 	ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
 	ASSERT_EQ(0, reg.write_index);
-	ASSERT_NE(0, reg.status_index);
+	ASSERT_NE(0, reg.status_bit);
 
 	/* Ensure disabled */
 	self->enable_fd = open(enable_file, O_RDWR);
@@ -212,15 +217,15 @@ TEST_F(user, register_events) {
 	/* MMAP should work and be zero'd */
 	ASSERT_NE(MAP_FAILED, status_page);
 	ASSERT_NE(NULL, status_page);
-	ASSERT_EQ(0, status_page[reg.status_index]);
+	ASSERT_EQ(0, status_check(status_page, reg.status_bit));
 
 	/* Enable event and ensure bits updated in status */
 	ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1")))
-	ASSERT_EQ(EVENT_STATUS_FTRACE, status_page[reg.status_index]);
+	ASSERT_NE(0, status_check(status_page, reg.status_bit));
 
 	/* Disable event and ensure bits updated in status */
 	ASSERT_NE(-1, write(self->enable_fd, "0", sizeof("0")))
-	ASSERT_EQ(0, status_page[reg.status_index]);
+	ASSERT_EQ(0, status_check(status_page, reg.status_bit));
 
 	/* File still open should return -EBUSY for delete */
 	ASSERT_EQ(-1, ioctl(self->data_fd, DIAG_IOCSDEL, "__test_event"));
@@ -240,6 +245,8 @@ TEST_F(user, write_events) {
 	struct iovec io[3];
 	__u32 field1, field2;
 	int before = 0, after = 0;
+	int page_size = sysconf(_SC_PAGESIZE);
+	char *status_page;
 
 	reg.size = sizeof(reg);
 	reg.name_args = (__u64)"__test_event u32 field1; u32 field2";
@@ -254,10 +261,18 @@ TEST_F(user, write_events) {
 	io[2].iov_base = &field2;
 	io[2].iov_len = sizeof(field2);
 
+	status_page = mmap(NULL, page_size, PROT_READ, MAP_SHARED,
+			   self->status_fd, 0);
+
 	/* Register should work */
 	ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
 	ASSERT_EQ(0, reg.write_index);
-	ASSERT_NE(0, reg.status_index);
+	ASSERT_NE(0, reg.status_bit);
+
+	/* MMAP should work and be zero'd */
+	ASSERT_NE(MAP_FAILED, status_page);
+	ASSERT_NE(NULL, status_page);
+	ASSERT_EQ(0, status_check(status_page, reg.status_bit));
 
 	/* Write should fail on invalid slot with ENOENT */
 	io[0].iov_base = &field2;
@@ -271,6 +286,9 @@ TEST_F(user, write_events) {
 	self->enable_fd = open(enable_file, O_RDWR);
 	ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1")))
 
+	/* Event should now be enabled */
+	ASSERT_NE(0, status_check(status_page, reg.status_bit));
+
 	/* Write should make it out to ftrace buffers */
 	before = trace_bytes();
 	ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 3));
@@ -298,7 +316,7 @@ TEST_F(user, write_fault) {
 	/* Register should work */
 	ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
 	ASSERT_EQ(0, reg.write_index);
-	ASSERT_NE(0, reg.status_index);
+	ASSERT_NE(0, reg.status_bit);
 
 	/* Write should work normally */
 	ASSERT_NE(-1, writev(self->data_fd, (const struct iovec *)io, 2));
@@ -315,6 +333,11 @@ TEST_F(user, write_validator) {
 	int loc, bytes;
 	char data[8];
 	int before = 0, after = 0;
+	int page_size = sysconf(_SC_PAGESIZE);
+	char *status_page;
+
+	status_page = mmap(NULL, page_size, PROT_READ, MAP_SHARED,
+			   self->status_fd, 0);
 
 	reg.size = sizeof(reg);
 	reg.name_args = (__u64)"__test_event __rel_loc char[] data";
@@ -322,7 +345,12 @@ TEST_F(user, write_validator) {
 	/* Register should work */
 	ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
 	ASSERT_EQ(0, reg.write_index);
-	ASSERT_NE(0, reg.status_index);
+	ASSERT_NE(0, reg.status_bit);
+
+	/* MMAP should work and be zero'd */
+	ASSERT_NE(MAP_FAILED, status_page);
+	ASSERT_NE(NULL, status_page);
+	ASSERT_EQ(0, status_check(status_page, reg.status_bit));
 
 	io[0].iov_base = &reg.write_index;
 	io[0].iov_len = sizeof(reg.write_index);
@@ -340,6 +368,9 @@ TEST_F(user, write_validator) {
 	self->enable_fd = open(enable_file, O_RDWR);
 	ASSERT_NE(-1, write(self->enable_fd, "1", sizeof("1")))
 
+	/* Event should now be enabled */
+	ASSERT_NE(0, status_check(status_page, reg.status_bit));
+
 	/* Full in-bounds write should work */
 	before = trace_bytes();
 	loc = DYN_LOC(0, bytes);
diff --git a/tools/testing/selftests/user_events/perf_test.c b/tools/testing/selftests/user_events/perf_test.c
index 26851d51d6bb..8b4c7879d5a7 100644
--- a/tools/testing/selftests/user_events/perf_test.c
+++ b/tools/testing/selftests/user_events/perf_test.c
@@ -35,6 +35,11 @@ static long perf_event_open(struct perf_event_attr *pe, pid_t pid,
 	return syscall(__NR_perf_event_open, pe, pid, cpu, group_fd, flags);
 }
 
+static inline int status_check(char *status_page, int status_bit)
+{
+	return status_page[status_bit >> 3] & (1 << (status_bit & 7));
+}
+
 static int get_id(void)
 {
 	FILE *fp = fopen(id_file, "r");
@@ -120,8 +125,8 @@ TEST_F(user, perf_write) {
 	/* Register should work */
 	ASSERT_EQ(0, ioctl(self->data_fd, DIAG_IOCSREG, &reg));
 	ASSERT_EQ(0, reg.write_index);
-	ASSERT_NE(0, reg.status_index);
-	ASSERT_EQ(0, status_page[reg.status_index]);
+	ASSERT_NE(0, reg.status_bit);
+	ASSERT_EQ(0, status_check(status_page, reg.status_bit));
 
 	/* Id should be there */
 	id = get_id();
@@ -144,7 +149,7 @@ TEST_F(user, perf_write) {
 	ASSERT_NE(MAP_FAILED, perf_page);
 
 	/* Status should be updated */
-	ASSERT_EQ(EVENT_STATUS_PERF, status_page[reg.status_index]);
+	ASSERT_NE(0, status_check(status_page, reg.status_bit));
 
 	event.index = reg.write_index;
 	event.field1 = 0xc001;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 7/7] tracing/user_events: Update ABI documentation to align to bits vs bytes
  2022-04-25 18:46 [PATCH v2 0/7] tracing/user_events: Update user_events ABI from Beau Belgrave
                   ` (5 preceding siblings ...)
  2022-04-25 18:46 ` [PATCH v2 6/7] tracing/user_events: Use bits vs bytes for enabled status page data Beau Belgrave
@ 2022-04-25 18:46 ` Beau Belgrave
  6 siblings, 0 replies; 14+ messages in thread
From: Beau Belgrave @ 2022-04-25 18:46 UTC (permalink / raw)
  To: rostedt, mhiramat, mathieu.desnoyers
  Cc: linux-trace-devel, linux-kernel, linux-arch, beaub

Update the documentation to reflect the new ABI requirements and how to
use the byte index with the mask properly to check event status.

Signed-off-by: Beau Belgrave <beaub@linux.microsoft.com>
---
 Documentation/trace/user_events.rst | 86 +++++++++++++++++++----------
 1 file changed, 58 insertions(+), 28 deletions(-)

diff --git a/Documentation/trace/user_events.rst b/Documentation/trace/user_events.rst
index c180936f49fc..9f181f342a70 100644
--- a/Documentation/trace/user_events.rst
+++ b/Documentation/trace/user_events.rst
@@ -20,14 +20,14 @@ dynamic_events is the same as the ioctl with the u: prefix applied.
 
 Typically programs will register a set of events that they wish to expose to
 tools that can read trace_events (such as ftrace and perf). The registration
-process gives back two ints to the program for each event. The first int is the
-status index. This index describes which byte in the
+process gives back two ints to the program for each event. The first int is
+the status bit. This describes which bit in little-endian format in the
 /sys/kernel/debug/tracing/user_events_status file represents this event. The
-second int is the write index. This index describes the data when a write() or
+second int is the write index which describes the data when a write() or
 writev() is called on the /sys/kernel/debug/tracing/user_events_data file.
 
-The structures referenced in this document are contained with the
-/include/uap/linux/user_events.h file in the source tree.
+The structures referenced in this document are contained within the
+/include/uapi/linux/user_events.h file in the source tree.
 
 **NOTE:** *Both user_events_status and user_events_data are under the tracefs
 filesystem and may be mounted at different paths than above.*
@@ -38,18 +38,18 @@ Registering within a user process is done via ioctl() out to the
 /sys/kernel/debug/tracing/user_events_data file. The command to issue is
 DIAG_IOCSREG.
 
-This command takes a struct user_reg as an argument::
+This command takes a packed struct user_reg as an argument::
 
   struct user_reg {
         u32 size;
         u64 name_args;
-        u32 status_index;
+        u32 status_bit;
         u32 write_index;
   };
 
 The struct user_reg requires two inputs, the first is the size of the structure
 to ensure forward and backward compatibility. The second is the command string
-to issue for registering. Upon success two outputs are set, the status index
+to issue for registering. Upon success two outputs are set, the status bit
 and the write index.
 
 User based events show up under tracefs like any other event under the
@@ -111,15 +111,56 @@ in realtime. This allows user programs to only incur the cost of the write() or
 writev() calls when something is actively attached to the event.
 
 User programs call mmap() on /sys/kernel/debug/tracing/user_events_status to
-check the status for each event that is registered. The byte to check in the
-file is given back after the register ioctl() via user_reg.status_index.
+check the status for each event that is registered. The bit to check in the
+file is given back after the register ioctl() via user_reg.status_bit. The bit
+is always in little-endian format. Programs can check if the bit is set either
+using a byte-wise index with a mask or a long-wise index with a little-endian
+mask.
+
 Currently the size of user_events_status is a single page, however, custom
 kernel configurations can change this size to allow more user based events. In
 all cases the size of the file is a multiple of a page size.
 
-For example, if the register ioctl() gives back a status_index of 3 you would
-check byte 3 of the returned mmap data to see if anything is attached to that
-event.
+For example, if the register ioctl() gives back a status_bit of 3 you would
+check byte 0 (3 / 8) of the returned mmap data and then AND the result with 8
+(1 << (3 % 8)) to see if anything is attached to that event.
+
+A byte-wise index check is performed as follows::
+
+  int index, mask;
+  char *status_page;
+
+  index = status_bit / 8;
+  mask = 1 << (status_bit % 8);
+
+  ...
+
+  if (status_page[index] & mask) {
+        /* Enabled */
+  }
+
+A long-wise index check is performed as follows::
+
+  #include <asm/bitsperlong.h>
+  #include <endian.h>
+
+  #if __BITS_PER_LONG == 64
+  #define endian_swap(x) htole64(x)
+  #else
+  #define endian_swap(x) htole32(x)
+  #endif
+
+  long index, mask, *status_page;
+
+  index = status_bit / __BITS_PER_LONG;
+  mask = 1L << (status_bit % __BITS_PER_LONG);
+  mask = endian_swap(mask);
+
+  ...
+
+  if (status_page[index] & mask) {
+        /* Enabled */
+  }
 
 Administrators can easily check the status of all registered events by reading
 the user_events_status file directly via a terminal. The output is as follows::
@@ -137,7 +178,7 @@ For example, on a system that has a single event the output looks like this::
 
   Active: 1
   Busy: 0
-  Max: 4096
+  Max: 32768
 
 If a user enables the user event via ftrace, the output would change to this::
 
@@ -145,21 +186,10 @@ If a user enables the user event via ftrace, the output would change to this::
 
   Active: 1
   Busy: 1
-  Max: 4096
-
-**NOTE:** *A status index of 0 will never be returned. This allows user
-programs to have an index that can be used on error cases.*
-
-Status Bits
-^^^^^^^^^^^
-The byte being checked will be non-zero if anything is attached. Programs can
-check specific bits in the byte to see what mechanism has been attached.
-
-The following values are defined to aid in checking what has been attached:
-
-**EVENT_STATUS_FTRACE** - Bit set if ftrace has been attached (Bit 0).
+  Max: 32768
 
-**EVENT_STATUS_PERF** - Bit set if perf has been attached (Bit 1).
+**NOTE:** *A status bit of 0 will never be returned. This allows user programs
+to have a bit that can be used on error cases.*
 
 Writing Data
 ------------
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 6/7] tracing/user_events: Use bits vs bytes for enabled status page data
  2022-04-25 18:46 ` [PATCH v2 6/7] tracing/user_events: Use bits vs bytes for enabled status page data Beau Belgrave
@ 2022-07-26 22:01   ` Steven Rostedt
  2022-07-27  0:02     ` Beau Belgrave
  0 siblings, 1 reply; 14+ messages in thread
From: Steven Rostedt @ 2022-07-26 22:01 UTC (permalink / raw)
  To: Beau Belgrave
  Cc: mhiramat, mathieu.desnoyers, linux-trace-devel, linux-kernel, linux-arch

On Mon, 25 Apr 2022 11:46:30 -0700
Beau Belgrave <beaub@linux.microsoft.com> wrote:

> diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
> index 2bcae7abfa81..4afc41e321ac 100644
> --- a/kernel/trace/trace_events_user.c
> +++ b/kernel/trace/trace_events_user.c
> @@ -40,17 +40,26 @@
>   */
>  #define MAX_PAGE_ORDER 0
>  #define MAX_PAGES (1 << MAX_PAGE_ORDER)
> -#define MAX_EVENTS (MAX_PAGES * PAGE_SIZE)
> +#define MAX_BYTES (MAX_PAGES * PAGE_SIZE)
> +#define MAX_EVENTS (MAX_BYTES * 8)
>  
>  /* Limit how long of an event name plus args within the subsystem. */
>  #define MAX_EVENT_DESC 512
>  #define EVENT_NAME(user_event) ((user_event)->tracepoint.name)
>  #define MAX_FIELD_ARRAY_SIZE 1024
>  
> +#define STATUS_BYTE(bit) ((bit) >> 3)
> +#define STATUS_MASK(bit) (1 << ((bit) & 7))
> +
> +/* Internal bits to keep track of connected probes */
> +#define EVENT_STATUS_FTRACE (1 << 0)
> +#define EVENT_STATUS_PERF (1 << 1)
> +#define EVENT_STATUS_OTHER (1 << 7)

Did you mean to shift STATUS_OTHER by 7?

Is EVENT_STATUS_OTHER suppose to be one of the flags within the 3 bits of
the 7 in STATUS_MASK?

-- Steve

> +
>  static char *register_page_data;
>  
>  static DEFINE_MUTEX(reg_mutex);
> -static DEFINE_HASHTABLE(register_table, 4);
> +static DEFINE_HASHTABLE(register_table, 8);
>  static DECLARE_BITMAP(page_bitmap, MAX_EVENTS);
>  
>  /*
> @@ -72,6 +81,7 @@ struct user_event {
>  	int index;
>  	int flags;
>  	int min_size;
> +	char status;
>  };

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 6/7] tracing/user_events: Use bits vs bytes for enabled status page data
  2022-07-26 22:01   ` Steven Rostedt
@ 2022-07-27  0:02     ` Beau Belgrave
  2022-07-27  0:14       ` Steven Rostedt
  0 siblings, 1 reply; 14+ messages in thread
From: Beau Belgrave @ 2022-07-27  0:02 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: mhiramat, mathieu.desnoyers, linux-trace-devel, linux-kernel, linux-arch

On Tue, Jul 26, 2022 at 06:01:15PM -0400, Steven Rostedt wrote:
> On Mon, 25 Apr 2022 11:46:30 -0700
> Beau Belgrave <beaub@linux.microsoft.com> wrote:
> 
> > diff --git a/kernel/trace/trace_events_user.c b/kernel/trace/trace_events_user.c
> > index 2bcae7abfa81..4afc41e321ac 100644
> > --- a/kernel/trace/trace_events_user.c
> > +++ b/kernel/trace/trace_events_user.c
> > @@ -40,17 +40,26 @@
> >   */
> >  #define MAX_PAGE_ORDER 0
> >  #define MAX_PAGES (1 << MAX_PAGE_ORDER)
> > -#define MAX_EVENTS (MAX_PAGES * PAGE_SIZE)
> > +#define MAX_BYTES (MAX_PAGES * PAGE_SIZE)
> > +#define MAX_EVENTS (MAX_BYTES * 8)
> >  
> >  /* Limit how long of an event name plus args within the subsystem. */
> >  #define MAX_EVENT_DESC 512
> >  #define EVENT_NAME(user_event) ((user_event)->tracepoint.name)
> >  #define MAX_FIELD_ARRAY_SIZE 1024
> >  
> > +#define STATUS_BYTE(bit) ((bit) >> 3)
> > +#define STATUS_MASK(bit) (1 << ((bit) & 7))
> > +
> > +/* Internal bits to keep track of connected probes */
> > +#define EVENT_STATUS_FTRACE (1 << 0)
> > +#define EVENT_STATUS_PERF (1 << 1)
> > +#define EVENT_STATUS_OTHER (1 << 7)
> 
> Did you mean to shift STATUS_OTHER by 7?
> 

Yes, it should be the value 128.

> Is EVENT_STATUS_OTHER suppose to be one of the flags within the 3 bits of
> the 7 in STATUS_MASK?
> 

My thought was that STATUS_OTHER would stay on the highest bit.
Then when we have other systems they would slot into (1 << 2), etc.

This may not be as important now since the byte is never given back to
the user and is only used when printing out status via the
user_events_status file in text form.

> -- Steve
> 

Thanks,
-Beau

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 6/7] tracing/user_events: Use bits vs bytes for enabled status page data
  2022-07-27  0:02     ` Beau Belgrave
@ 2022-07-27  0:14       ` Steven Rostedt
  2022-07-27  2:01         ` Beau Belgrave
  0 siblings, 1 reply; 14+ messages in thread
From: Steven Rostedt @ 2022-07-27  0:14 UTC (permalink / raw)
  To: Beau Belgrave
  Cc: mhiramat, mathieu.desnoyers, linux-trace-devel, linux-kernel, linux-arch

On Tue, 26 Jul 2022 17:02:49 -0700
Beau Belgrave <beaub@linux.microsoft.com> wrote:

> > >  /* Limit how long of an event name plus args within the subsystem. */
> > >  #define MAX_EVENT_DESC 512
> > >  #define EVENT_NAME(user_event) ((user_event)->tracepoint.name)
> > >  #define MAX_FIELD_ARRAY_SIZE 1024
> > >  
> > > +#define STATUS_BYTE(bit) ((bit) >> 3)
> > > +#define STATUS_MASK(bit) (1 << ((bit) & 7))
> > > +
> > > +/* Internal bits to keep track of connected probes */
> > > +#define EVENT_STATUS_FTRACE (1 << 0)
> > > +#define EVENT_STATUS_PERF (1 << 1)
> > > +#define EVENT_STATUS_OTHER (1 << 7)  
> > 
> > Did you mean to shift STATUS_OTHER by 7?
> >   
> 
> Yes, it should be the value 128.
> 
> > Is EVENT_STATUS_OTHER suppose to be one of the flags within the 3 bits of
> > the 7 in STATUS_MASK?
> >   
> 
> My thought was that STATUS_OTHER would stay on the highest bit.
> Then when we have other systems they would slot into (1 << 2), etc.
> 
> This may not be as important now since the byte is never given back to
> the user and is only used when printing out status via the
> user_events_status file in text form.

So, it is confusing because of STATUS_MASK() is bits 0,1,2 and we are
only using bits 0 and 1, with a OTHER bit at bit 7. And it would be
good to use the BIT() macro.

Is STATUS_OTHER suppose to be part of STATUS_MASK()?

-- Steve

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 6/7] tracing/user_events: Use bits vs bytes for enabled status page data
  2022-07-27  0:14       ` Steven Rostedt
@ 2022-07-27  2:01         ` Beau Belgrave
  2022-07-27 13:45           ` Steven Rostedt
  0 siblings, 1 reply; 14+ messages in thread
From: Beau Belgrave @ 2022-07-27  2:01 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: mhiramat, mathieu.desnoyers, linux-trace-devel, linux-kernel, linux-arch

On Tue, Jul 26, 2022 at 08:14:12PM -0400, Steven Rostedt wrote:
> On Tue, 26 Jul 2022 17:02:49 -0700
> Beau Belgrave <beaub@linux.microsoft.com> wrote:
> 
> > > >  /* Limit how long of an event name plus args within the subsystem. */
> > > >  #define MAX_EVENT_DESC 512
> > > >  #define EVENT_NAME(user_event) ((user_event)->tracepoint.name)
> > > >  #define MAX_FIELD_ARRAY_SIZE 1024
> > > >  
> > > > +#define STATUS_BYTE(bit) ((bit) >> 3)
> > > > +#define STATUS_MASK(bit) (1 << ((bit) & 7))
> > > > +
> > > > +/* Internal bits to keep track of connected probes */
> > > > +#define EVENT_STATUS_FTRACE (1 << 0)
> > > > +#define EVENT_STATUS_PERF (1 << 1)
> > > > +#define EVENT_STATUS_OTHER (1 << 7)  
> > > 
> > > Did you mean to shift STATUS_OTHER by 7?
> > >   
> > 
> > Yes, it should be the value 128.
> > 
> > > Is EVENT_STATUS_OTHER suppose to be one of the flags within the 3 bits of
> > > the 7 in STATUS_MASK?
> > >   
> > 
> > My thought was that STATUS_OTHER would stay on the highest bit.
> > Then when we have other systems they would slot into (1 << 2), etc.
> > 
> > This may not be as important now since the byte is never given back to
> > the user and is only used when printing out status via the
> > user_events_status file in text form.
> 
> So, it is confusing because of STATUS_MASK() is bits 0,1,2 and we are
> only using bits 0 and 1, with a OTHER bit at bit 7. And it would be
> good to use the BIT() macro.
> 

Ah, I see the confusion. Sorry.  

EVENT_STATUS_* are internal bits that aren't used with STATUS_MASK or
STATUS_BYTE. It's only used to set and check the user event status byte
for checking if anything is attached and outputting which probe is
connected within the kernel side.

STATUS_BYTE and STATUS_MASK take a bit in a bitmap and figure out which
byte in the status mapping should be used and which bit in that byte
should be set/reset (mask) when it's enabled/disabled via a probe. Both
the user and kernel need to align on this logic.

IE: Bits above the lower 3 of the index/bit of the event to enable is the byte
and the lower 3 bits (& 7) is the actual bit to set.

For example if the user_event with the index 1024 is enabled, we need to
figure out which byte and bit represents that event when a probe is
attached.

I got into detail of this in the documentation for both a byte and long
wise checking of these values.

Hope that helps explain it.

> Is STATUS_OTHER suppose to be part of STATUS_MASK()?
> 
> -- Steve

Thanks,
-Beau

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 6/7] tracing/user_events: Use bits vs bytes for enabled status page data
  2022-07-27  2:01         ` Beau Belgrave
@ 2022-07-27 13:45           ` Steven Rostedt
  2022-07-27 19:01             ` Beau Belgrave
  0 siblings, 1 reply; 14+ messages in thread
From: Steven Rostedt @ 2022-07-27 13:45 UTC (permalink / raw)
  To: Beau Belgrave
  Cc: mhiramat, mathieu.desnoyers, linux-trace-devel, linux-kernel, linux-arch

On Tue, 26 Jul 2022 19:01:47 -0700
Beau Belgrave <beaub@linux.microsoft.com> wrote:

> Ah, I see the confusion. Sorry.  
> 
> EVENT_STATUS_* are internal bits that aren't used with STATUS_MASK or
> STATUS_BYTE. It's only used to set and check the user event status byte
> for checking if anything is attached and outputting which probe is
> connected within the kernel side.
> 
> STATUS_BYTE and STATUS_MASK take a bit in a bitmap and figure out which
> byte in the status mapping should be used and which bit in that byte
> should be set/reset (mask) when it's enabled/disabled via a probe. Both
> the user and kernel need to align on this logic.
> 
> IE: Bits above the lower 3 of the index/bit of the event to enable is the byte
> and the lower 3 bits (& 7) is the actual bit to set.
> 
> For example if the user_event with the index 1024 is enabled, we need to
> figure out which byte and bit represents that event when a probe is
> attached.
> 
> I got into detail of this in the documentation for both a byte and long
> wise checking of these values.
> 
> Hope that helps explain it.

Yes, but that should be in the comments above the code.

-- Steve

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 6/7] tracing/user_events: Use bits vs bytes for enabled status page data
  2022-07-27 13:45           ` Steven Rostedt
@ 2022-07-27 19:01             ` Beau Belgrave
  0 siblings, 0 replies; 14+ messages in thread
From: Beau Belgrave @ 2022-07-27 19:01 UTC (permalink / raw)
  To: Steven Rostedt
  Cc: mhiramat, mathieu.desnoyers, linux-trace-devel, linux-kernel, linux-arch

On Wed, Jul 27, 2022 at 09:45:17AM -0400, Steven Rostedt wrote:
> On Tue, 26 Jul 2022 19:01:47 -0700
> Beau Belgrave <beaub@linux.microsoft.com> wrote:
> 
> > Ah, I see the confusion. Sorry.  
> > 
> > EVENT_STATUS_* are internal bits that aren't used with STATUS_MASK or
> > STATUS_BYTE. It's only used to set and check the user event status byte
> > for checking if anything is attached and outputting which probe is
> > connected within the kernel side.
> > 
> > STATUS_BYTE and STATUS_MASK take a bit in a bitmap and figure out which
> > byte in the status mapping should be used and which bit in that byte
> > should be set/reset (mask) when it's enabled/disabled via a probe. Both
> > the user and kernel need to align on this logic.
> > 
> > IE: Bits above the lower 3 of the index/bit of the event to enable is the byte
> > and the lower 3 bits (& 7) is the actual bit to set.
> > 
> > For example if the user_event with the index 1024 is enabled, we need to
> > figure out which byte and bit represents that event when a probe is
> > attached.
> > 
> > I got into detail of this in the documentation for both a byte and long
> > wise checking of these values.
> > 
> > Hope that helps explain it.
> 
> Yes, but that should be in the comments above the code.
> 

Will do, I will also change to use the BIT() macro as you suggested.

> -- Steve

Thanks,
-Beau

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2022-07-27 19:14 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-25 18:46 [PATCH v2 0/7] tracing/user_events: Update user_events ABI from Beau Belgrave
2022-04-25 18:46 ` [PATCH v2 1/7] tracing/user_events: Fix repeated word in comments Beau Belgrave
2022-04-25 18:46 ` [PATCH v2 2/7] tracing/user_events: Use NULL for strstr checks Beau Belgrave
2022-04-25 18:46 ` [PATCH v2 3/7] tracing/user_events: Use WRITE instead of READ for io vector import Beau Belgrave
2022-04-25 18:46 ` [PATCH v2 4/7] tracing/user_events: Ensure user provided strings are safely formatted Beau Belgrave
2022-04-25 18:46 ` [PATCH v2 5/7] tracing/user_events: Use refcount instead of atomic for ref tracking Beau Belgrave
2022-04-25 18:46 ` [PATCH v2 6/7] tracing/user_events: Use bits vs bytes for enabled status page data Beau Belgrave
2022-07-26 22:01   ` Steven Rostedt
2022-07-27  0:02     ` Beau Belgrave
2022-07-27  0:14       ` Steven Rostedt
2022-07-27  2:01         ` Beau Belgrave
2022-07-27 13:45           ` Steven Rostedt
2022-07-27 19:01             ` Beau Belgrave
2022-04-25 18:46 ` [PATCH v2 7/7] tracing/user_events: Update ABI documentation to align to bits vs bytes Beau Belgrave

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.