]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
tracing: Add bitmask-list option for human-readable bitmask display
authorAaron Tomlin <atomlin@atomlin.com>
Fri, 26 Dec 2025 16:07:24 +0000 (11:07 -0500)
committerSteven Rostedt (Google) <rostedt@goodmis.org>
Mon, 26 Jan 2026 22:00:50 +0000 (17:00 -0500)
Add support for displaying bitmasks in human-readable list format (e.g.,
0,2-5,7) in addition to the default hexadecimal bitmap representation.
This is particularly useful when tracing CPU masks and other large
bitmasks where individual bit positions are more meaningful than their
hexadecimal encoding.

When the "bitmask-list" option is enabled, the printk "%*pbl" format
specifier is used to render bitmasks as comma-separated ranges, making
trace output easier to interpret for complex CPU configurations and
large bitmask values.

Link: https://patch.msgid.link/20251226160724.2246493-2-atomlin@atomlin.com
Signed-off-by: Aaron Tomlin <atomlin@atomlin.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Documentation/trace/ftrace.rst
include/linux/trace_events.h
include/linux/trace_seq.h
include/trace/stages/stage3_trace_output.h
kernel/trace/trace.h
kernel/trace/trace_output.c
kernel/trace/trace_seq.c

index d1f313a5f4ad68f2b5df913f2ba48d30e5c69dc7..639f4d95732fc3d3eb1989f453fde908f3b55f58 100644 (file)
@@ -1290,6 +1290,15 @@ Here are the available options:
         This will be useful if you want to find out which hashed
         value is corresponding to the real value in trace log.
 
+  bitmask-list
+        When enabled, bitmasks are displayed as a human-readable list of
+        ranges (e.g., 0,2-5,7) using the printk "%*pbl" format specifier.
+        When disabled (the default), bitmasks are displayed in the
+        traditional hexadecimal bitmap representation. The list format is
+        particularly useful for tracing CPU masks and other large bitmasks
+        where individual bit positions are more meaningful than their
+        hexadecimal encoding.
+
   record-cmd
        When any event or tracer is enabled, a hook is enabled
        in the sched_switch trace point to fill comm cache
index 3690221ba3d80d78d5d85c262b7ff591bff6a9ae..0a2b8229b999c9f77920963561f377b881ad1d63 100644 (file)
@@ -38,7 +38,10 @@ const char *trace_print_symbols_seq_u64(struct trace_seq *p,
                                                                 *symbol_array);
 #endif
 
-const char *trace_print_bitmask_seq(struct trace_seq *p, void *bitmask_ptr,
+struct trace_iterator;
+struct trace_event;
+
+const char *trace_print_bitmask_seq(struct trace_iterator *iter, void *bitmask_ptr,
                                    unsigned int bitmask_size);
 
 const char *trace_print_hex_seq(struct trace_seq *p,
@@ -54,9 +57,6 @@ trace_print_hex_dump_seq(struct trace_seq *p, const char *prefix_str,
                         int prefix_type, int rowsize, int groupsize,
                         const void *buf, size_t len, bool ascii);
 
-struct trace_iterator;
-struct trace_event;
-
 int trace_raw_output_prep(struct trace_iterator *iter,
                          struct trace_event *event);
 extern __printf(2, 3)
index 4a0b8c172d274fa54c2a3604ae9693edd1b245c8..697d619aafdca008c06bf67e2fa67a7ca950e800 100644 (file)
@@ -114,7 +114,11 @@ extern void trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
 extern int trace_seq_path(struct trace_seq *s, const struct path *path);
 
 extern void trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp,
-                            int nmaskbits);
+                             int nmaskbits);
+
+extern void trace_seq_bitmask_list(struct trace_seq *s,
+                                  const unsigned long *maskp,
+                                  int nmaskbits);
 
 extern int trace_seq_hex_dump(struct trace_seq *s, const char *prefix_str,
                              int prefix_type, int rowsize, int groupsize,
@@ -137,6 +141,12 @@ trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp,
 {
 }
 
+static inline void
+trace_seq_bitmask_list(struct trace_seq *s, const unsigned long *maskp,
+                      int nmaskbits)
+{
+}
+
 static inline int trace_print_seq(struct seq_file *m, struct trace_seq *s)
 {
        return 0;
index 1e7b0bef95f5257b51880092c43d01842d385a73..fce85ea2df1c882ef998bcc69f5728ad820d9412 100644 (file)
@@ -39,7 +39,7 @@
                void *__bitmask = __get_dynamic_array(field);           \
                unsigned int __bitmask_size;                            \
                __bitmask_size = __get_dynamic_array_len(field);        \
-               trace_print_bitmask_seq(p, __bitmask, __bitmask_size);  \
+               trace_print_bitmask_seq(iter, __bitmask, __bitmask_size);       \
        })
 
 #undef __get_cpumask
@@ -51,7 +51,7 @@
                void *__bitmask = __get_rel_dynamic_array(field);               \
                unsigned int __bitmask_size;                            \
                __bitmask_size = __get_rel_dynamic_array_len(field);    \
-               trace_print_bitmask_seq(p, __bitmask, __bitmask_size);  \
+               trace_print_bitmask_seq(iter, __bitmask, __bitmask_size);       \
        })
 
 #undef __get_rel_cpumask
index b6d42fe061150290bbd6e6ebe5e5d1dcfca39ff6..8888fc9335b679f978529593a818c839751aeb53 100644 (file)
@@ -1411,6 +1411,7 @@ extern int trace_get_user(struct trace_parser *parser, const char __user *ubuf,
                C(COPY_MARKER,          "copy_trace_marker"),   \
                C(PAUSE_ON_TRACE,       "pause-on-trace"),      \
                C(HASH_PTR,             "hash-ptr"),    /* Print hashed pointer */ \
+               C(BITMASK_LIST,         "bitmask-list"),        \
                FUNCTION_FLAGS                                  \
                FGRAPH_FLAGS                                    \
                STACK_FLAGS                                     \
index cc2d3306bb607ffa70b0cb04a547926e75e856e2..1996d7aba038327edb5e45a0687cbb914205f9bf 100644 (file)
@@ -194,13 +194,37 @@ trace_print_symbols_seq_u64(struct trace_seq *p, unsigned long long val,
 EXPORT_SYMBOL(trace_print_symbols_seq_u64);
 #endif
 
+/**
+ * trace_print_bitmask_seq - print a bitmask to a sequence buffer
+ * @iter: The trace iterator for the current event instance
+ * @bitmask_ptr: The pointer to the bitmask data
+ * @bitmask_size: The size of the bitmask in bytes
+ *
+ * Prints a bitmask into a sequence buffer as either a hex string or a
+ * human-readable range list, depending on the instance's "bitmask-list"
+ * trace option. The bitmask is formatted into the iterator's temporary
+ * scratchpad rather than the primary sequence buffer. This avoids
+ * duplication and pointer-collision issues when the returned string is
+ * processed by a "%s" specifier in a TP_printk() macro.
+ *
+ * Returns a pointer to the formatted string within the temporary buffer.
+ */
 const char *
-trace_print_bitmask_seq(struct trace_seq *p, void *bitmask_ptr,
+trace_print_bitmask_seq(struct trace_iterator *iter, void *bitmask_ptr,
                        unsigned int bitmask_size)
 {
-       const char *ret = trace_seq_buffer_ptr(p);
+       struct trace_seq *p = &iter->tmp_seq;
+       const struct trace_array *tr = iter->tr;
+       const char *ret;
+
+       trace_seq_init(p);
+       ret = trace_seq_buffer_ptr(p);
+
+       if (tr->trace_flags & TRACE_ITER(BITMASK_LIST))
+               trace_seq_bitmask_list(p, bitmask_ptr, bitmask_size * 8);
+       else
+               trace_seq_bitmask(p, bitmask_ptr, bitmask_size * 8);
 
-       trace_seq_bitmask(p, bitmask_ptr, bitmask_size * 8);
        trace_seq_putc(p, 0);
 
        return ret;
index 32684ef4fb9dc7333b5b88b2db4702b69fdf0830..85f6f10d107f94e8880d3460d1a4eeba4890bbb5 100644 (file)
@@ -106,7 +106,7 @@ EXPORT_SYMBOL_GPL(trace_seq_printf);
  * Writes a ASCII representation of a bitmask string into @s.
  */
 void trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp,
-                     int nmaskbits)
+                      int nmaskbits)
 {
        unsigned int save_len = s->seq.len;
 
@@ -124,6 +124,33 @@ void trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp,
 }
 EXPORT_SYMBOL_GPL(trace_seq_bitmask);
 
+/**
+ * trace_seq_bitmask_list - write a bitmask array in its list representation
+ * @s:         trace sequence descriptor
+ * @maskp:     points to an array of unsigned longs that represent a bitmask
+ * @nmaskbits: The number of bits that are valid in @maskp
+ *
+ * Writes a list representation (e.g., 0-3,5-7) of a bitmask string into @s.
+ */
+void trace_seq_bitmask_list(struct trace_seq *s, const unsigned long *maskp,
+                      int nmaskbits)
+{
+       unsigned int save_len = s->seq.len;
+
+       if (s->full)
+               return;
+
+       __trace_seq_init(s);
+
+       seq_buf_printf(&s->seq, "%*pbl", nmaskbits, maskp);
+
+       if (unlikely(seq_buf_has_overflowed(&s->seq))) {
+               s->seq.len = save_len;
+               s->full = 1;
+       }
+}
+EXPORT_SYMBOL_GPL(trace_seq_bitmask_list);
+
 /**
  * trace_seq_vprintf - sequence printing of trace information
  * @s: trace sequence descriptor