Re: [PATCH v5 15/37] tracing: Add variable support to hist triggers
Hi Namhyung, On Fri, 2017-11-10 at 16:28 +0900, Namhyung Kim wrote: > Hi Tom, > > On Thu, Nov 09, 2017 at 02:33:46PM -0600, Tom Zanussi wrote: > > Add support for saving the value of a current event's event field by > > assigning it to a variable that can be read by a subsequent event. > > > > The basic syntax for saving a variable is to simply prefix a unique > > variable name not corresponding to any keyword along with an '=' sign > > to any event field. > > > > Both keys and values can be saved and retrieved in this way: > > > > # echo 'hist:keys=next_pid:vals=$ts0:ts0=$common_timestamp ... > > # echo 'hist:timer_pid=common_pid:key=$timer_pid ...' > > > > If a variable isn't a key variable or prefixed with 'vals=', the > > associated event field will be saved in a variable but won't be summed > > as a value: > > > > # echo 'hist:keys=next_pid:ts1=$common_timestamp:... > > > > Multiple variables can be assigned at the same time: > > > > # echo > > 'hist:keys=pid:vals=$ts0,$b,field2:ts0=$common_timestamp,b=field1 ... > > > > Multiple (or single) variables can also be assigned at the same time > > using separate assignments: > > > > # echo 'hist:keys=pid:vals=$ts0:ts0=$common_timestamp:b=field1:c=field2 > > ... > > > > Variables set as above can be used by being referenced from another > > event, as described in a subsequent patch. > > > > Signed-off-by: Tom Zanussi> > Signed-off-by: Baohong Liu > > --- > > [SNIP] > > +static int parse_var_defs(struct hist_trigger_data *hist_data) > > +{ > > + char *s, *str, *var_name, *field_str; > > + unsigned int i, j, n_vars = 0; > > + int ret = 0; > > + > > + for (i = 0; i < hist_data->attrs->n_assignments; i++) { > > + str = hist_data->attrs->assignment_str[i]; > > + for (j = 0; j < TRACING_MAP_VARS_MAX; j++) { > > + field_str = strsep(, ","); > > + if (!field_str) > > + break; > > + > > + var_name = strsep(_str, "="); > > + if (!var_name || !field_str) { > > + ret = -EINVAL; > > + goto free; > > + } > > + > > + s = kstrdup(var_name, GFP_KERNEL); > > + if (!s) { > > + ret = -ENOMEM; > > + goto free; > > + } > > + hist_data->attrs->var_defs.name[n_vars] = s; > > + > > + s = kstrdup(field_str, GFP_KERNEL); > > + if (!s) { > > + kfree(hist_data->attrs->var_defs.name[n_vars]); > > + ret = -ENOMEM; > > + goto free; > > + } > > + hist_data->attrs->var_defs.expr[n_vars++] = s; > > + > > + hist_data->attrs->var_defs.n_vars = n_vars; > > + > > + if (n_vars == TRACING_MAP_VARS_MAX) > > + goto free; > > This will silently discard all variables. Why not returning an error? > Also I think it should be moved to the beginning of this block.. > Yes, thanks for pointing this out. This should fix it, will merge into the appropriate patches in the next version... Tom From: Tom Zanussi Date: Fri, 10 Nov 2017 09:01:21 -0600 Subject: [PATCH] tracing: Fix parse_var_defs max case Fix the VARS_MAX case and add an error condition for it. Merge into variable support and 'last err' patches. Signed-off-by: Tom Zanussi --- kernel/trace/trace_events_hist.c | 9 ++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index 4d1b636..1ea9304 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -4050,6 +4050,12 @@ static int parse_var_defs(struct hist_trigger_data *hist_data) goto free; } + if (n_vars == TRACING_MAP_VARS_MAX) { + hist_err("Too many variables defined: ", var_name); + ret = -EINVAL; + goto free; + } + s = kstrdup(var_name, GFP_KERNEL); if (!s) { ret = -ENOMEM; @@ -4066,9 +4072,6 @@ static int parse_var_defs(struct hist_trigger_data *hist_data) hist_data->attrs->var_defs.expr[n_vars++] = s; hist_data->attrs->var_defs.n_vars = n_vars; - - if (n_vars == TRACING_MAP_VARS_MAX) - goto free; } } -- 2.7.4
Re: [PATCH v5 15/37] tracing: Add variable support to hist triggers
Hi Namhyung, On Fri, 2017-11-10 at 16:28 +0900, Namhyung Kim wrote: > Hi Tom, > > On Thu, Nov 09, 2017 at 02:33:46PM -0600, Tom Zanussi wrote: > > Add support for saving the value of a current event's event field by > > assigning it to a variable that can be read by a subsequent event. > > > > The basic syntax for saving a variable is to simply prefix a unique > > variable name not corresponding to any keyword along with an '=' sign > > to any event field. > > > > Both keys and values can be saved and retrieved in this way: > > > > # echo 'hist:keys=next_pid:vals=$ts0:ts0=$common_timestamp ... > > # echo 'hist:timer_pid=common_pid:key=$timer_pid ...' > > > > If a variable isn't a key variable or prefixed with 'vals=', the > > associated event field will be saved in a variable but won't be summed > > as a value: > > > > # echo 'hist:keys=next_pid:ts1=$common_timestamp:... > > > > Multiple variables can be assigned at the same time: > > > > # echo > > 'hist:keys=pid:vals=$ts0,$b,field2:ts0=$common_timestamp,b=field1 ... > > > > Multiple (or single) variables can also be assigned at the same time > > using separate assignments: > > > > # echo 'hist:keys=pid:vals=$ts0:ts0=$common_timestamp:b=field1:c=field2 > > ... > > > > Variables set as above can be used by being referenced from another > > event, as described in a subsequent patch. > > > > Signed-off-by: Tom Zanussi > > Signed-off-by: Baohong Liu > > --- > > [SNIP] > > +static int parse_var_defs(struct hist_trigger_data *hist_data) > > +{ > > + char *s, *str, *var_name, *field_str; > > + unsigned int i, j, n_vars = 0; > > + int ret = 0; > > + > > + for (i = 0; i < hist_data->attrs->n_assignments; i++) { > > + str = hist_data->attrs->assignment_str[i]; > > + for (j = 0; j < TRACING_MAP_VARS_MAX; j++) { > > + field_str = strsep(, ","); > > + if (!field_str) > > + break; > > + > > + var_name = strsep(_str, "="); > > + if (!var_name || !field_str) { > > + ret = -EINVAL; > > + goto free; > > + } > > + > > + s = kstrdup(var_name, GFP_KERNEL); > > + if (!s) { > > + ret = -ENOMEM; > > + goto free; > > + } > > + hist_data->attrs->var_defs.name[n_vars] = s; > > + > > + s = kstrdup(field_str, GFP_KERNEL); > > + if (!s) { > > + kfree(hist_data->attrs->var_defs.name[n_vars]); > > + ret = -ENOMEM; > > + goto free; > > + } > > + hist_data->attrs->var_defs.expr[n_vars++] = s; > > + > > + hist_data->attrs->var_defs.n_vars = n_vars; > > + > > + if (n_vars == TRACING_MAP_VARS_MAX) > > + goto free; > > This will silently discard all variables. Why not returning an error? > Also I think it should be moved to the beginning of this block.. > Yes, thanks for pointing this out. This should fix it, will merge into the appropriate patches in the next version... Tom From: Tom Zanussi Date: Fri, 10 Nov 2017 09:01:21 -0600 Subject: [PATCH] tracing: Fix parse_var_defs max case Fix the VARS_MAX case and add an error condition for it. Merge into variable support and 'last err' patches. Signed-off-by: Tom Zanussi --- kernel/trace/trace_events_hist.c | 9 ++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index 4d1b636..1ea9304 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -4050,6 +4050,12 @@ static int parse_var_defs(struct hist_trigger_data *hist_data) goto free; } + if (n_vars == TRACING_MAP_VARS_MAX) { + hist_err("Too many variables defined: ", var_name); + ret = -EINVAL; + goto free; + } + s = kstrdup(var_name, GFP_KERNEL); if (!s) { ret = -ENOMEM; @@ -4066,9 +4072,6 @@ static int parse_var_defs(struct hist_trigger_data *hist_data) hist_data->attrs->var_defs.expr[n_vars++] = s; hist_data->attrs->var_defs.n_vars = n_vars; - - if (n_vars == TRACING_MAP_VARS_MAX) - goto free; } } -- 2.7.4
Re: [PATCH v5 15/37] tracing: Add variable support to hist triggers
On Fri, 10 Nov 2017 16:28:41 +0900 Namhyung Kimwrote: > > + hist_data->attrs->var_defs.expr[n_vars++] = s; > > + > > + hist_data->attrs->var_defs.n_vars = n_vars; > > + > > + if (n_vars == TRACING_MAP_VARS_MAX) > > + goto free; > > This will silently discard all variables. Why not returning an error? > Also I think it should be moved to the beginning of this block.. Right, because the check here is already too late. Usually you check the count before doing the assignment. if (n_vars == TRACING_MAP_VARS_MAX) goto free; hist_data->attrs->var_defs.expr[n_vars++] = s; Because it is OK for n_vars to equal TRACING_MAP_VARS_MAX, but not OK to be more. -- Steve
Re: [PATCH v5 15/37] tracing: Add variable support to hist triggers
On Fri, 10 Nov 2017 16:28:41 +0900 Namhyung Kim wrote: > > + hist_data->attrs->var_defs.expr[n_vars++] = s; > > + > > + hist_data->attrs->var_defs.n_vars = n_vars; > > + > > + if (n_vars == TRACING_MAP_VARS_MAX) > > + goto free; > > This will silently discard all variables. Why not returning an error? > Also I think it should be moved to the beginning of this block.. Right, because the check here is already too late. Usually you check the count before doing the assignment. if (n_vars == TRACING_MAP_VARS_MAX) goto free; hist_data->attrs->var_defs.expr[n_vars++] = s; Because it is OK for n_vars to equal TRACING_MAP_VARS_MAX, but not OK to be more. -- Steve
Re: [PATCH v5 15/37] tracing: Add variable support to hist triggers
Hi Tom, On Thu, Nov 09, 2017 at 02:33:46PM -0600, Tom Zanussi wrote: > Add support for saving the value of a current event's event field by > assigning it to a variable that can be read by a subsequent event. > > The basic syntax for saving a variable is to simply prefix a unique > variable name not corresponding to any keyword along with an '=' sign > to any event field. > > Both keys and values can be saved and retrieved in this way: > > # echo 'hist:keys=next_pid:vals=$ts0:ts0=$common_timestamp ... > # echo 'hist:timer_pid=common_pid:key=$timer_pid ...' > > If a variable isn't a key variable or prefixed with 'vals=', the > associated event field will be saved in a variable but won't be summed > as a value: > > # echo 'hist:keys=next_pid:ts1=$common_timestamp:... > > Multiple variables can be assigned at the same time: > > # echo 'hist:keys=pid:vals=$ts0,$b,field2:ts0=$common_timestamp,b=field1 > ... > > Multiple (or single) variables can also be assigned at the same time > using separate assignments: > > # echo 'hist:keys=pid:vals=$ts0:ts0=$common_timestamp:b=field1:c=field2 > ... > > Variables set as above can be used by being referenced from another > event, as described in a subsequent patch. > > Signed-off-by: Tom Zanussi> Signed-off-by: Baohong Liu > --- [SNIP] > +static int parse_var_defs(struct hist_trigger_data *hist_data) > +{ > + char *s, *str, *var_name, *field_str; > + unsigned int i, j, n_vars = 0; > + int ret = 0; > + > + for (i = 0; i < hist_data->attrs->n_assignments; i++) { > + str = hist_data->attrs->assignment_str[i]; > + for (j = 0; j < TRACING_MAP_VARS_MAX; j++) { > + field_str = strsep(, ","); > + if (!field_str) > + break; > + > + var_name = strsep(_str, "="); > + if (!var_name || !field_str) { > + ret = -EINVAL; > + goto free; > + } > + > + s = kstrdup(var_name, GFP_KERNEL); > + if (!s) { > + ret = -ENOMEM; > + goto free; > + } > + hist_data->attrs->var_defs.name[n_vars] = s; > + > + s = kstrdup(field_str, GFP_KERNEL); > + if (!s) { > + kfree(hist_data->attrs->var_defs.name[n_vars]); > + ret = -ENOMEM; > + goto free; > + } > + hist_data->attrs->var_defs.expr[n_vars++] = s; > + > + hist_data->attrs->var_defs.n_vars = n_vars; > + > + if (n_vars == TRACING_MAP_VARS_MAX) > + goto free; This will silently discard all variables. Why not returning an error? Also I think it should be moved to the beginning of this block.. Thanks, Namhyung > + } > + } > + > + return ret; > + free: > + free_var_defs(hist_data); > + > + return ret; > +}
Re: [PATCH v5 15/37] tracing: Add variable support to hist triggers
Hi Tom, On Thu, Nov 09, 2017 at 02:33:46PM -0600, Tom Zanussi wrote: > Add support for saving the value of a current event's event field by > assigning it to a variable that can be read by a subsequent event. > > The basic syntax for saving a variable is to simply prefix a unique > variable name not corresponding to any keyword along with an '=' sign > to any event field. > > Both keys and values can be saved and retrieved in this way: > > # echo 'hist:keys=next_pid:vals=$ts0:ts0=$common_timestamp ... > # echo 'hist:timer_pid=common_pid:key=$timer_pid ...' > > If a variable isn't a key variable or prefixed with 'vals=', the > associated event field will be saved in a variable but won't be summed > as a value: > > # echo 'hist:keys=next_pid:ts1=$common_timestamp:... > > Multiple variables can be assigned at the same time: > > # echo 'hist:keys=pid:vals=$ts0,$b,field2:ts0=$common_timestamp,b=field1 > ... > > Multiple (or single) variables can also be assigned at the same time > using separate assignments: > > # echo 'hist:keys=pid:vals=$ts0:ts0=$common_timestamp:b=field1:c=field2 > ... > > Variables set as above can be used by being referenced from another > event, as described in a subsequent patch. > > Signed-off-by: Tom Zanussi > Signed-off-by: Baohong Liu > --- [SNIP] > +static int parse_var_defs(struct hist_trigger_data *hist_data) > +{ > + char *s, *str, *var_name, *field_str; > + unsigned int i, j, n_vars = 0; > + int ret = 0; > + > + for (i = 0; i < hist_data->attrs->n_assignments; i++) { > + str = hist_data->attrs->assignment_str[i]; > + for (j = 0; j < TRACING_MAP_VARS_MAX; j++) { > + field_str = strsep(, ","); > + if (!field_str) > + break; > + > + var_name = strsep(_str, "="); > + if (!var_name || !field_str) { > + ret = -EINVAL; > + goto free; > + } > + > + s = kstrdup(var_name, GFP_KERNEL); > + if (!s) { > + ret = -ENOMEM; > + goto free; > + } > + hist_data->attrs->var_defs.name[n_vars] = s; > + > + s = kstrdup(field_str, GFP_KERNEL); > + if (!s) { > + kfree(hist_data->attrs->var_defs.name[n_vars]); > + ret = -ENOMEM; > + goto free; > + } > + hist_data->attrs->var_defs.expr[n_vars++] = s; > + > + hist_data->attrs->var_defs.n_vars = n_vars; > + > + if (n_vars == TRACING_MAP_VARS_MAX) > + goto free; This will silently discard all variables. Why not returning an error? Also I think it should be moved to the beginning of this block.. Thanks, Namhyung > + } > + } > + > + return ret; > + free: > + free_var_defs(hist_data); > + > + return ret; > +}
[PATCH v5 15/37] tracing: Add variable support to hist triggers
Add support for saving the value of a current event's event field by assigning it to a variable that can be read by a subsequent event. The basic syntax for saving a variable is to simply prefix a unique variable name not corresponding to any keyword along with an '=' sign to any event field. Both keys and values can be saved and retrieved in this way: # echo 'hist:keys=next_pid:vals=$ts0:ts0=$common_timestamp ... # echo 'hist:timer_pid=common_pid:key=$timer_pid ...' If a variable isn't a key variable or prefixed with 'vals=', the associated event field will be saved in a variable but won't be summed as a value: # echo 'hist:keys=next_pid:ts1=$common_timestamp:... Multiple variables can be assigned at the same time: # echo 'hist:keys=pid:vals=$ts0,$b,field2:ts0=$common_timestamp,b=field1 ... Multiple (or single) variables can also be assigned at the same time using separate assignments: # echo 'hist:keys=pid:vals=$ts0:ts0=$common_timestamp:b=field1:c=field2 ... Variables set as above can be used by being referenced from another event, as described in a subsequent patch. Signed-off-by: Tom ZanussiSigned-off-by: Baohong Liu --- kernel/trace/trace_events_hist.c | 367 ++- 1 file changed, 327 insertions(+), 40 deletions(-) diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index ec2df88..a7eb162 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -30,6 +30,13 @@ typedef u64 (*hist_field_fn_t) (struct hist_field *field, void *event, struct ring_buffer_event *rbe); #define HIST_FIELD_OPERANDS_MAX2 +#define HIST_FIELDS_MAX(TRACING_MAP_FIELDS_MAX + TRACING_MAP_VARS_MAX) + +struct hist_var { + char*name; + struct hist_trigger_data*hist_data; + unsigned intidx; +}; struct hist_field { struct ftrace_event_field *field; @@ -40,6 +47,7 @@ struct hist_field { unsigned intis_signed; struct hist_field *operands[HIST_FIELD_OPERANDS_MAX]; struct hist_trigger_data*hist_data; + struct hist_var var; }; static u64 hist_field_none(struct hist_field *field, void *event, @@ -138,6 +146,13 @@ enum hist_field_flags { HIST_FIELD_FL_LOG2 = 1 << 9, HIST_FIELD_FL_TIMESTAMP = 1 << 10, HIST_FIELD_FL_TIMESTAMP_USECS = 1 << 11, + HIST_FIELD_FL_VAR = 1 << 12, +}; + +struct var_defs { + unsigned intn_vars; + char*name[TRACING_MAP_VARS_MAX]; + char*expr[TRACING_MAP_VARS_MAX]; }; struct hist_trigger_attrs { @@ -150,13 +165,19 @@ struct hist_trigger_attrs { boolclear; boolts_in_usecs; unsigned intmap_bits; + + char*assignment_str[TRACING_MAP_VARS_MAX]; + unsigned intn_assignments; + + struct var_defs var_defs; }; struct hist_trigger_data { - struct hist_field *fields[TRACING_MAP_FIELDS_MAX]; + struct hist_field *fields[HIST_FIELDS_MAX]; unsigned intn_vals; unsigned intn_keys; unsigned intn_fields; + unsigned intn_vars; unsigned intkey_size; struct tracing_map_sort_key sort_keys[TRACING_MAP_SORT_KEYS_MAX]; unsigned intn_sort_keys; @@ -164,6 +185,7 @@ struct hist_trigger_data { struct hist_trigger_attrs *attrs; struct tracing_map *map; boolenable_timestamps; + boolremove; }; static u64 hist_field_timestamp(struct hist_field *hist_field, void *event, @@ -262,9 +284,14 @@ static int parse_map_size(char *str) static void destroy_hist_trigger_attrs(struct hist_trigger_attrs *attrs) { + unsigned int i; + if (!attrs) return; + for (i = 0; i < attrs->n_assignments; i++) + kfree(attrs->assignment_str[i]); + kfree(attrs->name); kfree(attrs->sort_key_str); kfree(attrs->keys_str); @@ -311,8 +338,22 @@ static int parse_assignment(char *str, struct hist_trigger_attrs *attrs) goto out; } attrs->map_bits = map_bits; - } else - ret = -EINVAL; + } else { + char *assignment; + + if (attrs->n_assignments == TRACING_MAP_VARS_MAX) { + ret = -EINVAL; + goto out; + } + + assignment = kstrdup(str, GFP_KERNEL); + if (!assignment) { +
[PATCH v5 15/37] tracing: Add variable support to hist triggers
Add support for saving the value of a current event's event field by assigning it to a variable that can be read by a subsequent event. The basic syntax for saving a variable is to simply prefix a unique variable name not corresponding to any keyword along with an '=' sign to any event field. Both keys and values can be saved and retrieved in this way: # echo 'hist:keys=next_pid:vals=$ts0:ts0=$common_timestamp ... # echo 'hist:timer_pid=common_pid:key=$timer_pid ...' If a variable isn't a key variable or prefixed with 'vals=', the associated event field will be saved in a variable but won't be summed as a value: # echo 'hist:keys=next_pid:ts1=$common_timestamp:... Multiple variables can be assigned at the same time: # echo 'hist:keys=pid:vals=$ts0,$b,field2:ts0=$common_timestamp,b=field1 ... Multiple (or single) variables can also be assigned at the same time using separate assignments: # echo 'hist:keys=pid:vals=$ts0:ts0=$common_timestamp:b=field1:c=field2 ... Variables set as above can be used by being referenced from another event, as described in a subsequent patch. Signed-off-by: Tom Zanussi Signed-off-by: Baohong Liu --- kernel/trace/trace_events_hist.c | 367 ++- 1 file changed, 327 insertions(+), 40 deletions(-) diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c index ec2df88..a7eb162 100644 --- a/kernel/trace/trace_events_hist.c +++ b/kernel/trace/trace_events_hist.c @@ -30,6 +30,13 @@ typedef u64 (*hist_field_fn_t) (struct hist_field *field, void *event, struct ring_buffer_event *rbe); #define HIST_FIELD_OPERANDS_MAX2 +#define HIST_FIELDS_MAX(TRACING_MAP_FIELDS_MAX + TRACING_MAP_VARS_MAX) + +struct hist_var { + char*name; + struct hist_trigger_data*hist_data; + unsigned intidx; +}; struct hist_field { struct ftrace_event_field *field; @@ -40,6 +47,7 @@ struct hist_field { unsigned intis_signed; struct hist_field *operands[HIST_FIELD_OPERANDS_MAX]; struct hist_trigger_data*hist_data; + struct hist_var var; }; static u64 hist_field_none(struct hist_field *field, void *event, @@ -138,6 +146,13 @@ enum hist_field_flags { HIST_FIELD_FL_LOG2 = 1 << 9, HIST_FIELD_FL_TIMESTAMP = 1 << 10, HIST_FIELD_FL_TIMESTAMP_USECS = 1 << 11, + HIST_FIELD_FL_VAR = 1 << 12, +}; + +struct var_defs { + unsigned intn_vars; + char*name[TRACING_MAP_VARS_MAX]; + char*expr[TRACING_MAP_VARS_MAX]; }; struct hist_trigger_attrs { @@ -150,13 +165,19 @@ struct hist_trigger_attrs { boolclear; boolts_in_usecs; unsigned intmap_bits; + + char*assignment_str[TRACING_MAP_VARS_MAX]; + unsigned intn_assignments; + + struct var_defs var_defs; }; struct hist_trigger_data { - struct hist_field *fields[TRACING_MAP_FIELDS_MAX]; + struct hist_field *fields[HIST_FIELDS_MAX]; unsigned intn_vals; unsigned intn_keys; unsigned intn_fields; + unsigned intn_vars; unsigned intkey_size; struct tracing_map_sort_key sort_keys[TRACING_MAP_SORT_KEYS_MAX]; unsigned intn_sort_keys; @@ -164,6 +185,7 @@ struct hist_trigger_data { struct hist_trigger_attrs *attrs; struct tracing_map *map; boolenable_timestamps; + boolremove; }; static u64 hist_field_timestamp(struct hist_field *hist_field, void *event, @@ -262,9 +284,14 @@ static int parse_map_size(char *str) static void destroy_hist_trigger_attrs(struct hist_trigger_attrs *attrs) { + unsigned int i; + if (!attrs) return; + for (i = 0; i < attrs->n_assignments; i++) + kfree(attrs->assignment_str[i]); + kfree(attrs->name); kfree(attrs->sort_key_str); kfree(attrs->keys_str); @@ -311,8 +338,22 @@ static int parse_assignment(char *str, struct hist_trigger_attrs *attrs) goto out; } attrs->map_bits = map_bits; - } else - ret = -EINVAL; + } else { + char *assignment; + + if (attrs->n_assignments == TRACING_MAP_VARS_MAX) { + ret = -EINVAL; + goto out; + } + + assignment = kstrdup(str, GFP_KERNEL); + if (!assignment) { + ret = -ENOMEM; + goto