Merge tag 'trace-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull tracing updates from Steven Rostedt:

 - Remove a redundant IS_ERR() check

   trace_pipe_open() already checks for IS_ERR() and does it again in
   the return path. Remove the return check.

 - Export seq_buf_putmem_hex() to allow kunit tests against them

   To add Kunit tests on seq_buf_putmem_hex(), it needs to be exported.

 - Replace strcat() and strcpy() with seq_buf() logic

   The code for synthetic events uses a series of strcat() and strcpy()
   which can be error prone. Replace them with seq_buf() logic that does
   all the necessary bound checking.

 - Add a lockdep rcu_is_watching() to trace_##event##_enabled() call

   The trace_##event##_enabled() is a static branch that is true if the
   "event" is enabled. But this can hide bugs if this logic is in a
   location where RCU is disabled and not "watching". It would only
   trigger if lockdep is enabled and the event is enabled.

   Add a "rcu_is_watching()" warning if lockdep is enabled in that
   helper function to trigger regardless if the event is enabled or not.

 - Remove the local variable in the trace_printk() macro

   For name space integrity, remove the _______STR variable in the
   trace_printk() macro for using the sizeof() macro directly.

 - Use guard()s for the trace_recursion_record.c file

 - Fix typo in a comment of eventfs_callback() kerneldoc

 - Use trace_call__##event() in events within trace_##event##_enabled()

   A couple of events are called within an if block guarded by
   trace_##event##_enabled(). That is a static key that is only enabled
   when the event is enabled. The trace_call_##event() calls the
   tracepoint code directly without adding a redundant static key for
   that check.

 - Allow perf to read synthetic events

   Currently, perf does not have the ability to enable a synthetic
   event. If it does, it will either cause a kernel warning or error
   with "No such device". Synthetic events are not much different than
   kprobes and perf can handle fine with a few modifications.

 - Replace printk(KERN_WARNING ...) with pr_warn()

 - Replace krealloc() on an array with krealloc_array()

 - Fix README file path name for synthetic events

 - Change tracing_map tracing_map_array to use a flexible array

   Instead of allocating a separate pointer to hold the pages field of
   tracing_map_array, allocate the pages field as a flexible array when
   allocating the structure.

 - Fold trace_iterator_increment() into trace_find_next_entry_inc()

   The function trace_iterator_increment() was only used by
   trace_find_next_entry_inc(). It's not big enough to be a helper
   function for one user. Fold it into its caller.

 - Make field_var_str field a flexible array of hist_elt_data

   Instead of allocating a separate pointer for the field_var_str array
   of the hist_elt_data structure, allocate it as a flexible array when
   allocating the structure.

 - Disable KCOV for trace_irqsoff.c

   Like trace_preemptirq.c, trace_irqsoff.c has code that will crash
   when KCOV is enabled on ARM. The irqsoff tracing can be called on ARM
   because the irqsoff tracing code can be run from early interrupt code
   and produce coverage unrelated to syscall inputs.

 - Fix warning in __unregister_ftrace_function() called by perf

   Perf calls unregister_ftrace_function() without checking if its
   ftrace_ops has already been unregistered. There's an error path where
   on clean up it will unregister the ftrace_ops even if it wasn't
   registered and causes a warning.

* tag 'trace-v7.2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  perf/ftrace: Fix WARNING in __unregister_ftrace_function
  tracing: Disable KCOV instrumentation for trace_irqsoff.o
  tracing: Turn hist_elt_data field_var_str into a flexible array
  tracing: Move trace_iterator_increment() into trace_find_next_entry_inc()
  tracing: Simplify pages allocation for tracing_map logic
  tracing: Fix README path for synthetic_events
  tracing: Use krealloc_array() for trace option array growth
  tracing/branch: Use pr_warn() instead of printk(KERN_WARNING)
  tracing: Allow perf to read synthetic events
  HID: Use trace_call__##name() at guarded tracepoint call sites
  cpufreq: amd-pstate: Use trace_call__##name() at guarded tracepoint call site
  tracefs: Fix typo in a comment of eventfs_callback() kerneldoc
  tracing: Switch trace_recursion_record.c code over to use guard()
  tracing: Remove local variable for argument detection from trace_printk()
  tracepoint: Add lockdep rcu_is_watching() check to trace_##name##_enabled()
  tracing: Bound synthetic-field strings with seq_buf
  seq_buf: Export seq_buf_putmem_hex() and add KUnit tests
  tracing: Remove redundant IS_ERR() check in trace_pipe_open()
This commit is contained in:
Linus Torvalds
2026-06-18 20:53:00 -07:00
17 changed files with 222 additions and 113 deletions

View File

@@ -361,7 +361,8 @@ static int amd_pstate_set_floor_perf(struct cpufreq_policy *policy, u8 perf)
out_trace:
if (trace_amd_pstate_cppc_req2_enabled())
trace_amd_pstate_cppc_req2(cpudata->cpu, perf, changed, ret);
trace_call__amd_pstate_cppc_req2(cpudata->cpu, perf, changed,
ret);
return ret;
}

View File

@@ -110,7 +110,7 @@ void ish_event_tracer(struct ishtp_device *dev, const char *format, ...)
vsnprintf(tmp_buf, sizeof(tmp_buf), format, args);
va_end(args);
trace_ishtp_dump(tmp_buf);
trace_call__ishtp_dump(tmp_buf);
}
}

View File

@@ -86,8 +86,7 @@ do { \
#define trace_printk(fmt, ...) \
do { \
char _______STR[] = __stringify((__VA_ARGS__)); \
if (sizeof(_______STR) > 3) \
if (sizeof __stringify((__VA_ARGS__)) > 3) \
do_trace_printk(fmt, ##__VA_ARGS__); \
else \
trace_puts(fmt); \

View File

@@ -30,7 +30,7 @@ struct eventfs_file;
* @data: data to pass to the created file ops
* @fops: the file operations of the created file
*
* The evetnfs files are dynamically created. The struct eventfs_entry array
* The eventfs files are dynamically created. The struct eventfs_entry array
* is passed to eventfs_create_dir() or eventfs_create_events_dir() that will
* be used to create the files within those directories. When a lookup
* or access to a file within the directory is made, the struct eventfs_entry

View File

@@ -294,6 +294,10 @@ static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p)
static inline bool \
trace_##name##_enabled(void) \
{ \
if (IS_ENABLED(CONFIG_LOCKDEP)) { \
WARN_ONCE(!rcu_is_watching(), \
"RCU not watching for tracepoint"); \
} \
return static_branch_unlikely(&__tracepoint_##name.key);\
}

View File

@@ -48,9 +48,10 @@ ifdef CONFIG_GCOV_PROFILE_FTRACE
GCOV_PROFILE := y
endif
# Functions in this file could be invoked from early interrupt
# code and produce random code coverage.
# Functions in these files can run from IRQ entry before hardirq context
# is visible to KCOV, and produce coverage unrelated to syscall inputs.
KCOV_INSTRUMENT_trace_preemptirq.o := n
KCOV_INSTRUMENT_trace_irqsoff.o := n
CFLAGS_bpf_trace.o := -I$(src)

View File

@@ -2338,15 +2338,6 @@ void trace_last_func_repeats(struct trace_array *tr,
__buffer_unlock_commit(buffer, event);
}
static void trace_iterator_increment(struct trace_iterator *iter)
{
struct ring_buffer_iter *buf_iter = trace_buffer_iter(iter, iter->cpu);
iter->idx++;
if (buf_iter)
ring_buffer_iter_advance(buf_iter);
}
static struct trace_entry *
peek_next_entry(struct trace_iterator *iter, int cpu, u64 *ts,
unsigned long *lost_events)
@@ -2676,11 +2667,17 @@ struct trace_entry *trace_find_next_entry(struct trace_iterator *iter,
/* Find the next real entry, and increment the iterator to the next entry */
void *trace_find_next_entry_inc(struct trace_iterator *iter)
{
struct ring_buffer_iter *buf_iter;
iter->ent = __find_next_entry(iter, &iter->cpu,
&iter->lost_events, &iter->ts);
if (iter->ent)
trace_iterator_increment(iter);
if (iter->ent) {
iter->idx++;
buf_iter = trace_buffer_iter(iter, iter->cpu);
if (buf_iter)
ring_buffer_iter_advance(buf_iter);
}
return iter->ent ? iter : NULL;
}
@@ -4474,7 +4471,7 @@ static const char readme_msg[] =
"\t snapshot() - snapshot the trace buffer\n\n"
#endif
#ifdef CONFIG_SYNTH_EVENTS
" events/synthetic_events\t- Create/append/remove/show synthetic events\n"
" synthetic_events\t- Create/append/remove/show synthetic events\n"
"\t Write into this file to define/undefine new synthetic events.\n"
"\t example: echo 'myevent u64 lat; char name[]; long[] stack' >> synthetic_events\n"
#endif
@@ -7928,8 +7925,8 @@ create_trace_option_files(struct trace_array *tr, struct tracer *tracer,
if (!topts)
return 0;
tr_topts = krealloc(tr->topts, sizeof(*tr->topts) * (tr->nr_topts + 1),
GFP_KERNEL);
tr_topts = krealloc_array(tr->topts, tr->nr_topts + 1, sizeof(*tr->topts),
GFP_KERNEL);
if (!tr_topts) {
kfree(topts);
return -ENOMEM;

View File

@@ -181,8 +181,7 @@ __init static int init_branch_tracer(void)
ret = register_trace_event(&trace_branch_event);
if (!ret) {
printk(KERN_WARNING "Warning: could not register "
"branch events\n");
pr_warn("Warning: could not register branch events\n");
return 1;
}
return register_tracer(&branch_trace);
@@ -374,8 +373,7 @@ __init static int init_annotated_branch_stats(void)
ret = register_stat_tracer(&annotated_branch_stats);
if (ret) {
printk(KERN_WARNING "Warning: could not register "
"annotated branches stats\n");
pr_warn("Warning: could not register annotated branches stats\n");
return ret;
}
return 0;
@@ -439,8 +437,7 @@ __init static int all_annotated_branch_stats(void)
ret = register_stat_tracer(&all_branch_stats);
if (ret) {
printk(KERN_WARNING "Warning: could not register "
"all branches stats\n");
pr_warn("Warning: could not register all branches stats\n");
return ret;
}
return 0;

View File

@@ -497,7 +497,17 @@ static int perf_ftrace_function_register(struct perf_event *event)
static int perf_ftrace_function_unregister(struct perf_event *event)
{
struct ftrace_ops *ops = &event->ftrace_ops;
int ret = unregister_ftrace_function(ops);
int ret = 0;
/*
* Perf will call this unconditionally even if the ops is not
* enabled. The unregister_ftrace_function() will warn if called
* when not enabled. Just bypass the unregistering if ops isn't
* enabled here.
*/
if (ops->flags & FTRACE_OPS_FL_ENABLED)
ret = unregister_ftrace_function(ops);
ftrace_free_filter(ops);
return ret;
}

View File

@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/kallsyms.h>
#include <linux/security.h>
#include <linux/seq_buf.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/stacktrace.h>
@@ -682,8 +683,8 @@ struct track_data {
struct hist_elt_data {
char *comm;
u64 *var_ref_vals;
char **field_var_str;
int n_field_var_str;
char *field_var_str[] __counted_by(n_field_var_str);
};
struct snapshot_context {
@@ -1628,8 +1629,6 @@ static void hist_elt_data_free(struct hist_elt_data *elt_data)
for (i = 0; i < elt_data->n_field_var_str; i++)
kfree(elt_data->field_var_str[i]);
kfree(elt_data->field_var_str);
kfree(elt_data->comm);
kfree(elt_data);
}
@@ -1649,10 +1648,19 @@ static int hist_trigger_elt_data_alloc(struct tracing_map_elt *elt)
struct hist_field *hist_field;
unsigned int i, n_str;
elt_data = kzalloc_obj(*elt_data);
BUILD_BUG_ON(STR_VAR_LEN_MAX & (sizeof(u64) - 1));
n_str = hist_data->n_field_var_str + hist_data->n_save_var_str +
hist_data->n_var_str;
if (n_str > SYNTH_FIELDS_MAX)
return -EINVAL;
elt_data = kzalloc_flex(*elt_data, field_var_str, n_str);
if (!elt_data)
return -ENOMEM;
elt_data->n_field_var_str = n_str;
for_each_hist_field(i, hist_data) {
hist_field = hist_data->fields[i];
@@ -1666,24 +1674,8 @@ static int hist_trigger_elt_data_alloc(struct tracing_map_elt *elt)
}
}
n_str = hist_data->n_field_var_str + hist_data->n_save_var_str +
hist_data->n_var_str;
if (n_str > SYNTH_FIELDS_MAX) {
hist_elt_data_free(elt_data);
return -EINVAL;
}
BUILD_BUG_ON(STR_VAR_LEN_MAX & (sizeof(u64) - 1));
size = STR_VAR_LEN_MAX;
elt_data->field_var_str = kcalloc(n_str, sizeof(char *), GFP_KERNEL);
if (!elt_data->field_var_str) {
hist_elt_data_free(elt_data);
return -EINVAL;
}
elt_data->n_field_var_str = n_str;
for (i = 0; i < n_str; i++) {
elt_data->field_var_str[i] = kzalloc(size, GFP_KERNEL);
if (!elt_data->field_var_str[i]) {
@@ -2967,13 +2959,22 @@ find_synthetic_field_var(struct hist_trigger_data *target_hist_data,
{
struct hist_field *event_var;
char *synthetic_name;
struct seq_buf s;
synthetic_name = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
if (!synthetic_name)
return ERR_PTR(-ENOMEM);
strcpy(synthetic_name, "synthetic_");
strcat(synthetic_name, field_name);
seq_buf_init(&s, synthetic_name, MAX_FILTER_STR_VAL);
seq_buf_printf(&s, "synthetic_%s", field_name);
/* Terminate synthetic_name with a NUL. */
seq_buf_str(&s);
if (seq_buf_has_overflowed(&s)) {
kfree(synthetic_name);
return ERR_PTR(-E2BIG);
}
event_var = find_event_var(target_hist_data, system, event_name, synthetic_name);
@@ -3019,6 +3020,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,
struct hist_field *key_field;
struct hist_field *event_var;
char *saved_filter;
struct seq_buf s;
char *cmd;
int ret;
@@ -3063,28 +3065,34 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,
return ERR_PTR(-ENOMEM);
}
seq_buf_init(&s, cmd, MAX_FILTER_STR_VAL);
/* Use the same keys as the compatible histogram */
strcat(cmd, "keys=");
seq_buf_puts(&s, "keys=");
for_each_hist_key_field(i, hist_data) {
key_field = hist_data->fields[i];
if (!first)
strcat(cmd, ",");
strcat(cmd, key_field->field->name);
seq_buf_putc(&s, ',');
seq_buf_puts(&s, key_field->field->name);
first = false;
}
/* Create the synthetic field variable specification */
strcat(cmd, ":synthetic_");
strcat(cmd, field_name);
strcat(cmd, "=");
strcat(cmd, field_name);
seq_buf_printf(&s, ":synthetic_%s=%s", field_name, field_name);
/* Use the same filter as the compatible histogram */
saved_filter = find_trigger_filter(hist_data, file);
if (saved_filter) {
strcat(cmd, " if ");
strcat(cmd, saved_filter);
if (saved_filter)
seq_buf_printf(&s, " if %s", saved_filter);
/* Terminate cmd with a NUL. */
seq_buf_str(&s);
if (seq_buf_has_overflowed(&s)) {
kfree(cmd);
kfree(var_hist);
return ERR_PTR(-E2BIG);
}
var_hist->cmd = kstrdup(cmd, GFP_KERNEL);

View File

@@ -499,28 +499,19 @@ static unsigned int trace_stack(struct synth_trace_event *entry,
return len;
}
static void trace_event_raw_event_synth(void *__data,
u64 *var_ref_vals,
unsigned int *var_ref_idx)
static __always_inline int get_field_size(struct synth_event *event,
u64 *var_ref_vals,
unsigned int *var_ref_idx)
{
unsigned int i, n_u64, val_idx, len, data_size = 0;
struct trace_event_file *trace_file = __data;
struct synth_trace_event *entry;
struct trace_event_buffer fbuffer;
struct trace_buffer *buffer;
struct synth_event *event;
int fields_size = 0;
event = trace_file->event_call->data;
if (trace_trigger_soft_disabled(trace_file))
return;
int fields_size;
fields_size = event->n_u64 * sizeof(u64);
for (i = 0; i < event->n_dynamic_fields; i++) {
for (int i = 0; i < event->n_dynamic_fields; i++) {
unsigned int field_pos = event->dynamic_fields[i]->field_pos;
char *str_val;
int val_idx;
int len;
val_idx = var_ref_idx[field_pos];
str_val = (char *)(long)var_ref_vals[val_idx];
@@ -535,18 +526,18 @@ static void trace_event_raw_event_synth(void *__data,
fields_size += len;
}
return fields_size;
}
/*
* Avoid ring buffer recursion detection, as this event
* is being performed within another event.
*/
buffer = trace_file->tr->array_buffer.buffer;
guard(ring_buffer_nest)(buffer);
entry = trace_event_buffer_reserve(&fbuffer, trace_file,
sizeof(*entry) + fields_size);
if (!entry)
return;
static __always_inline void write_synth_entry(struct synth_event *event,
struct synth_trace_event *entry,
u64 *var_ref_vals,
unsigned int *var_ref_idx)
{
int data_size = 0;
int i, n_u64;
int val_idx;
int len;
for (i = 0, n_u64 = 0; i < event->n_fields; i++) {
val_idx = var_ref_idx[i];
@@ -587,10 +578,83 @@ static void trace_event_raw_event_synth(void *__data,
n_u64++;
}
}
}
static void trace_event_raw_event_synth(void *__data,
u64 *var_ref_vals,
unsigned int *var_ref_idx)
{
struct trace_event_file *trace_file = __data;
struct synth_trace_event *entry;
struct trace_event_buffer fbuffer;
struct trace_buffer *buffer;
struct synth_event *event;
int fields_size;
event = trace_file->event_call->data;
if (trace_trigger_soft_disabled(trace_file))
return;
fields_size = get_field_size(event, var_ref_vals, var_ref_idx);
/*
* Avoid ring buffer recursion detection, as this event
* is being performed within another event.
*/
buffer = trace_file->tr->array_buffer.buffer;
guard(ring_buffer_nest)(buffer);
entry = trace_event_buffer_reserve(&fbuffer, trace_file,
sizeof(*entry) + fields_size);
if (!entry)
return;
write_synth_entry(event, entry, var_ref_vals, var_ref_idx);
trace_event_buffer_commit(&fbuffer);
}
#ifdef CONFIG_PERF_EVENTS
static void perf_event_raw_event_synth(void *__data,
u64 *var_ref_vals,
unsigned int *var_ref_idx)
{
struct trace_event_call *call = __data;
struct synth_trace_event *entry;
struct hlist_head *perf_head;
struct synth_event *event;
struct pt_regs *regs;
int fields_size;
size_t size;
int context;
event = call->data;
perf_head = this_cpu_ptr(call->perf_events);
if (!perf_head || hlist_empty(perf_head))
return;
fields_size = get_field_size(event, var_ref_vals, var_ref_idx);
size = ALIGN(sizeof(*entry) + fields_size, 8);
entry = perf_trace_buf_alloc(size, &regs, &context);
if (unlikely(!entry))
return;
write_synth_entry(event, entry, var_ref_vals, var_ref_idx);
perf_fetch_caller_regs(regs);
perf_trace_buf_submit(entry, size, context,
call->event.type, 1, regs,
perf_head, NULL);
}
#endif
static void free_synth_event_print_fmt(struct trace_event_call *call)
{
if (call) {
@@ -917,6 +981,9 @@ static int register_synth_event(struct synth_event *event)
call->flags = TRACE_EVENT_FL_TRACEPOINT;
call->class->reg = synth_event_reg;
call->class->probe = trace_event_raw_event_synth;
#ifdef CONFIG_PERF_EVENTS
call->class->perf_probe = perf_event_raw_event_synth;
#endif
call->data = event;
call->tp = event->tp;

View File

@@ -180,9 +180,8 @@ static const struct seq_operations recursed_function_seq_ops = {
static int recursed_function_open(struct inode *inode, struct file *file)
{
int ret = 0;
guard(mutex)(&recursed_function_lock);
mutex_lock(&recursed_function_lock);
/* If this file was opened for write, then erase contents */
if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
/* disable updating records */
@@ -194,10 +193,9 @@ static int recursed_function_open(struct inode *inode, struct file *file)
atomic_set(&nr_records, 0);
}
if (file->f_mode & FMODE_READ)
ret = seq_open(file, &recursed_function_seq_ops);
mutex_unlock(&recursed_function_lock);
return seq_open(file, &recursed_function_seq_ops);
return ret;
return 0;
}
static ssize_t recursed_function_write(struct file *file,

View File

@@ -602,7 +602,7 @@ static int trace_pipe_open(struct inode *inode, struct file *filp)
filp->private_data = iter;
return IS_ERR(iter) ? PTR_ERR(iter) : 0;
return 0;
}
static int trace_pipe_release(struct inode *inode, struct file *filp)

View File

@@ -288,9 +288,6 @@ static void tracing_map_array_clear(struct tracing_map_array *a)
{
unsigned int i;
if (!a->pages)
return;
for (i = 0; i < a->n_pages; i++)
memset(a->pages[i], 0, PAGE_SIZE);
}
@@ -302,9 +299,6 @@ static void tracing_map_array_free(struct tracing_map_array *a)
if (!a)
return;
if (!a->pages)
goto free;
for (i = 0; i < a->n_pages; i++) {
if (!a->pages[i])
break;
@@ -312,9 +306,6 @@ static void tracing_map_array_free(struct tracing_map_array *a)
free_page((unsigned long)a->pages[i]);
}
kfree(a->pages);
free:
kfree(a);
}
@@ -322,24 +313,25 @@ static struct tracing_map_array *tracing_map_array_alloc(unsigned int n_elts,
unsigned int entry_size)
{
struct tracing_map_array *a;
unsigned int entry_size_shift;
unsigned int entries_per_page;
unsigned int n_pages;
unsigned int i;
a = kzalloc_obj(*a);
entry_size_shift = fls(roundup_pow_of_two(entry_size) - 1);
entries_per_page = PAGE_SIZE / (1 << entry_size_shift);
n_pages = max(1, n_elts / entries_per_page);
a = kzalloc_flex(*a, pages, n_pages);
if (!a)
return NULL;
a->entry_size_shift = fls(roundup_pow_of_two(entry_size) - 1);
a->entries_per_page = PAGE_SIZE / (1 << a->entry_size_shift);
a->n_pages = n_elts / a->entries_per_page;
if (!a->n_pages)
a->n_pages = 1;
a->entry_size_shift = entry_size_shift;
a->entries_per_page = entries_per_page;
a->n_pages = n_pages;
a->entry_shift = fls(a->entries_per_page) - 1;
a->entry_mask = (1 << a->entry_shift) - 1;
a->pages = kcalloc(a->n_pages, sizeof(void *), GFP_KERNEL);
if (!a->pages)
goto free;
for (i = 0; i < a->n_pages; i++) {
a->pages[i] = (void *)get_zeroed_page(GFP_KERNEL);
if (!a->pages[i])

View File

@@ -167,7 +167,7 @@ struct tracing_map_array {
unsigned int entry_shift;
unsigned int entry_mask;
unsigned int n_pages;
void **pages;
void *pages[] __counted_by(n_pages);
};
#define TRACING_MAP_ARRAY_ELT(array, idx) \

View File

@@ -298,6 +298,7 @@ int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,
}
return 0;
}
EXPORT_SYMBOL_GPL(seq_buf_putmem_hex);
/**
* seq_buf_path - copy a path into the sequence buffer

View File

@@ -184,6 +184,38 @@ static void seq_buf_get_buf_commit_test(struct kunit *test)
KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s));
}
static void seq_buf_putmem_hex_test(struct kunit *test)
{
DECLARE_SEQ_BUF(s, 24);
const u8 data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
#ifdef __BIG_ENDIAN
const char *expected = "0001020304050607 0809 ";
#else
const char *expected = "0706050403020100 0908 ";
#endif
KUNIT_EXPECT_EQ(test, seq_buf_putmem_hex(&s, data, sizeof(data)), 0);
KUNIT_EXPECT_FALSE(test, seq_buf_has_overflowed(&s));
KUNIT_EXPECT_EQ(test, seq_buf_used(&s), strlen(expected));
KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), expected);
}
static void seq_buf_putmem_hex_overflow_test(struct kunit *test)
{
DECLARE_SEQ_BUF(s, 20);
const u8 data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
#ifdef __BIG_ENDIAN
const char *expected = "0001020304050607 ";
#else
const char *expected = "0706050403020100 ";
#endif
KUNIT_EXPECT_EQ(test, seq_buf_putmem_hex(&s, data, sizeof(data)), -1);
KUNIT_EXPECT_TRUE(test, seq_buf_has_overflowed(&s));
KUNIT_EXPECT_EQ(test, seq_buf_used(&s), 20);
KUNIT_EXPECT_STREQ(test, seq_buf_str(&s), expected);
}
static struct kunit_case seq_buf_test_cases[] = {
KUNIT_CASE(seq_buf_init_test),
KUNIT_CASE(seq_buf_declare_test),
@@ -194,6 +226,8 @@ static struct kunit_case seq_buf_test_cases[] = {
KUNIT_CASE(seq_buf_printf_test),
KUNIT_CASE(seq_buf_printf_overflow_test),
KUNIT_CASE(seq_buf_get_buf_commit_test),
KUNIT_CASE(seq_buf_putmem_hex_test),
KUNIT_CASE(seq_buf_putmem_hex_overflow_test),
{}
};