Skip to content

Commit d380dcd

Browse files
Tom Zanussirostedt
authored andcommitted
tracing: Fix now invalid var_ref_vals assumption in trace action
The patch 'tracing: Fix histogram code when expression has same var as value' added code to return an existing variable reference when creating a new variable reference, which resulted in var_ref_vals slots being reused instead of being duplicated. The implementation of the trace action assumes that the end of the var_ref_vals array starting at action_data.var_ref_idx corresponds to the values that will be assigned to the trace params. The patch mentioned above invalidates that assumption, which means that each param needs to explicitly specify its index into var_ref_vals. This fix changes action_data.var_ref_idx to an array of var ref indexes to account for that. Link: https://lore.kernel.org/r/[email protected] Fixes: 8bcebc7 ("tracing: Fix histogram code when expression has same var as value") Signed-off-by: Tom Zanussi <[email protected]> Signed-off-by: Steven Rostedt (VMware) <[email protected]>
1 parent fdeb1ac commit d380dcd

File tree

1 file changed

+38
-15
lines changed

1 file changed

+38
-15
lines changed

kernel/trace/trace_events_hist.c

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -476,11 +476,12 @@ struct action_data {
476476
* When a histogram trigger is hit, the values of any
477477
* references to variables, including variables being passed
478478
* as parameters to synthetic events, are collected into a
479-
* var_ref_vals array. This var_ref_idx is the index of the
480-
* first param in the array to be passed to the synthetic
481-
* event invocation.
479+
* var_ref_vals array. This var_ref_idx array is an array of
480+
* indices into the var_ref_vals array, one for each synthetic
481+
* event param, and is passed to the synthetic event
482+
* invocation.
482483
*/
483-
unsigned int var_ref_idx;
484+
unsigned int var_ref_idx[TRACING_MAP_VARS_MAX];
484485
struct synth_event *synth_event;
485486
bool use_trace_keyword;
486487
char *synth_event_name;
@@ -884,14 +885,14 @@ static struct trace_event_functions synth_event_funcs = {
884885

885886
static notrace void trace_event_raw_event_synth(void *__data,
886887
u64 *var_ref_vals,
887-
unsigned int var_ref_idx)
888+
unsigned int *var_ref_idx)
888889
{
889890
struct trace_event_file *trace_file = __data;
890891
struct synth_trace_event *entry;
891892
struct trace_event_buffer fbuffer;
892893
struct trace_buffer *buffer;
893894
struct synth_event *event;
894-
unsigned int i, n_u64;
895+
unsigned int i, n_u64, val_idx;
895896
int fields_size = 0;
896897

897898
event = trace_file->event_call->data;
@@ -914,15 +915,16 @@ static notrace void trace_event_raw_event_synth(void *__data,
914915
goto out;
915916

916917
for (i = 0, n_u64 = 0; i < event->n_fields; i++) {
918+
val_idx = var_ref_idx[i];
917919
if (event->fields[i]->is_string) {
918-
char *str_val = (char *)(long)var_ref_vals[var_ref_idx + i];
920+
char *str_val = (char *)(long)var_ref_vals[val_idx];
919921
char *str_field = (char *)&entry->fields[n_u64];
920922

921923
strscpy(str_field, str_val, STR_VAR_LEN_MAX);
922924
n_u64 += STR_VAR_LEN_MAX / sizeof(u64);
923925
} else {
924926
struct synth_field *field = event->fields[i];
925-
u64 val = var_ref_vals[var_ref_idx + i];
927+
u64 val = var_ref_vals[val_idx];
926928

927929
switch (field->size) {
928930
case 1:
@@ -1122,10 +1124,10 @@ static struct tracepoint *alloc_synth_tracepoint(char *name)
11221124
}
11231125

11241126
typedef void (*synth_probe_func_t) (void *__data, u64 *var_ref_vals,
1125-
unsigned int var_ref_idx);
1127+
unsigned int *var_ref_idx);
11261128

11271129
static inline void trace_synth(struct synth_event *event, u64 *var_ref_vals,
1128-
unsigned int var_ref_idx)
1130+
unsigned int *var_ref_idx)
11291131
{
11301132
struct tracepoint *tp = event->tp;
11311133

@@ -3506,6 +3508,22 @@ static int init_var_ref(struct hist_field *ref_field,
35063508
goto out;
35073509
}
35083510

3511+
static int find_var_ref_idx(struct hist_trigger_data *hist_data,
3512+
struct hist_field *var_field)
3513+
{
3514+
struct hist_field *ref_field;
3515+
int i;
3516+
3517+
for (i = 0; i < hist_data->n_var_refs; i++) {
3518+
ref_field = hist_data->var_refs[i];
3519+
if (ref_field->var.idx == var_field->var.idx &&
3520+
ref_field->var.hist_data == var_field->hist_data)
3521+
return i;
3522+
}
3523+
3524+
return -ENOENT;
3525+
}
3526+
35093527
/**
35103528
* create_var_ref - Create a variable reference and attach it to trigger
35113529
* @hist_data: The trigger that will be referencing the variable
@@ -5071,11 +5089,11 @@ static int trace_action_create(struct hist_trigger_data *hist_data,
50715089
struct trace_array *tr = hist_data->event_file->tr;
50725090
char *event_name, *param, *system = NULL;
50735091
struct hist_field *hist_field, *var_ref;
5074-
unsigned int i, var_ref_idx;
5092+
unsigned int i;
50755093
unsigned int field_pos = 0;
50765094
struct synth_event *event;
50775095
char *synth_event_name;
5078-
int ret = 0;
5096+
int var_ref_idx, ret = 0;
50795097

50805098
lockdep_assert_held(&event_mutex);
50815099

@@ -5092,8 +5110,6 @@ static int trace_action_create(struct hist_trigger_data *hist_data,
50925110

50935111
event->ref++;
50945112

5095-
var_ref_idx = hist_data->n_var_refs;
5096-
50975113
for (i = 0; i < data->n_params; i++) {
50985114
char *p;
50995115

@@ -5142,6 +5158,14 @@ static int trace_action_create(struct hist_trigger_data *hist_data,
51425158
goto err;
51435159
}
51445160

5161+
var_ref_idx = find_var_ref_idx(hist_data, var_ref);
5162+
if (WARN_ON(var_ref_idx < 0)) {
5163+
ret = var_ref_idx;
5164+
goto err;
5165+
}
5166+
5167+
data->var_ref_idx[i] = var_ref_idx;
5168+
51455169
field_pos++;
51465170
kfree(p);
51475171
continue;
@@ -5160,7 +5184,6 @@ static int trace_action_create(struct hist_trigger_data *hist_data,
51605184
}
51615185

51625186
data->synth_event = event;
5163-
data->var_ref_idx = var_ref_idx;
51645187
out:
51655188
return ret;
51665189
err:

0 commit comments

Comments
 (0)