Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tracing: Acquire buffer from temparary trace sequence

there is one dwc3 trace event declare as below,
DECLARE_EVENT_CLASS(dwc3_log_event,
TP_PROTO(u32 event, struct dwc3 *dwc),
TP_ARGS(event, dwc),
TP_STRUCT__entry(
__field(u32, event)
__field(u32, ep0state)
__dynamic_array(char, str, DWC3_MSG_MAX)
),
TP_fast_assign(
__entry->event = event;
__entry->ep0state = dwc->ep0state;
),
TP_printk("event (%08x): %s", __entry->event,
dwc3_decode_event(__get_str(str), DWC3_MSG_MAX,
__entry->event, __entry->ep0state))
);
the problem is when trace function called, it will allocate up to
DWC3_MSG_MAX bytes from trace event buffer, but never fill the buffer
during fast assignment, it only fill the buffer when output function are
called, so this means if output function are not called, the buffer will
never used.

add __get_buf(len) which acquiree buffer from iter->tmp_seq when trace
output function called, it allow user write string to acquired buffer.

the mentioned dwc3 trace event will changed as below,
DECLARE_EVENT_CLASS(dwc3_log_event,
TP_PROTO(u32 event, struct dwc3 *dwc),
TP_ARGS(event, dwc),
TP_STRUCT__entry(
__field(u32, event)
__field(u32, ep0state)
),
TP_fast_assign(
__entry->event = event;
__entry->ep0state = dwc->ep0state;
),
TP_printk("event (%08x): %s", __entry->event,
dwc3_decode_event(__get_buf(DWC3_MSG_MAX), DWC3_MSG_MAX,
__entry->event, __entry->ep0state))
);.

Link: https://lore.kernel.org/linux-trace-kernel/1675065249-23368-1-git-send-email-quic_linyyuan@quicinc.com

Cc: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Linyu Yuan <quic_linyyuan@quicinc.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>

authored by

Linyu Yuan and committed by
Steven Rostedt (Google)
a9c4bdd5 a2ff84a5

+32
+5
include/linux/trace_seq.h
··· 95 95 extern int trace_seq_hex_dump(struct trace_seq *s, const char *prefix_str, 96 96 int prefix_type, int rowsize, int groupsize, 97 97 const void *buf, size_t len, bool ascii); 98 + char *trace_seq_acquire(struct trace_seq *s, unsigned int len); 98 99 99 100 #else /* CONFIG_TRACING */ 100 101 static inline __printf(2, 3) ··· 139 138 static inline int trace_seq_path(struct trace_seq *s, const struct path *path) 140 139 { 141 140 return 0; 141 + } 142 + static inline char *trace_seq_acquire(struct trace_seq *s, unsigned int len) 143 + { 144 + return NULL; 142 145 } 143 146 #endif /* CONFIG_TRACING */ 144 147
+3
include/trace/stages/stage3_trace_output.h
··· 139 139 u64 ____val = (u64)(value); \ 140 140 (u32) do_div(____val, NSEC_PER_SEC); \ 141 141 }) 142 + 143 + #undef __get_buf 144 + #define __get_buf(len) trace_seq_acquire(p, (len))
+1
include/trace/stages/stage7_class_define.h
··· 23 23 #undef __get_rel_sockaddr 24 24 #undef __print_array 25 25 #undef __print_hex_dump 26 + #undef __get_buf 26 27 27 28 /* 28 29 * The below is not executed in the kernel. It is only what is
+23
kernel/trace/trace_seq.c
··· 403 403 return 1; 404 404 } 405 405 EXPORT_SYMBOL(trace_seq_hex_dump); 406 + 407 + /* 408 + * trace_seq_acquire - acquire seq buffer with size len 409 + * @s: trace sequence descriptor 410 + * @len: size of buffer to be acquired 411 + * 412 + * acquire buffer with size of @len from trace_seq for output usage, 413 + * user can fill string into that buffer. 414 + * 415 + * Returns start address of acquired buffer. 416 + * 417 + * it allow multiple usage in one trace output function call. 418 + */ 419 + char *trace_seq_acquire(struct trace_seq *s, unsigned int len) 420 + { 421 + char *ret = trace_seq_buffer_ptr(s); 422 + 423 + if (!WARN_ON_ONCE(seq_buf_buffer_left(&s->seq) < len)) 424 + seq_buf_commit(&s->seq, len); 425 + 426 + return ret; 427 + } 428 + EXPORT_SYMBOL(trace_seq_acquire);