mm: memmap defer init doesn't work as expected
[linux-2.6-microblaze.git] / kernel / trace / trace_events_hist.c
index 1b2ef64..39ebe18 100644 (file)
@@ -147,6 +147,8 @@ struct hist_field {
         */
        unsigned int                    var_ref_idx;
        bool                            read_once;
+
+       unsigned int                    var_str_idx;
 };
 
 static u64 hist_field_none(struct hist_field *field,
@@ -349,6 +351,7 @@ struct hist_trigger_data {
        unsigned int                    n_keys;
        unsigned int                    n_fields;
        unsigned int                    n_vars;
+       unsigned int                    n_var_str;
        unsigned int                    key_size;
        struct tracing_map_sort_key     sort_keys[TRACING_MAP_SORT_KEYS_MAX];
        unsigned int                    n_sort_keys;
@@ -1396,7 +1399,14 @@ 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;
+       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;
 
@@ -3279,6 +3289,15 @@ static int check_synth_field(struct synth_event *event,
 
        field = event->fields[field_pos];
 
+       /*
+        * A dynamic string synth field can accept static or
+        * dynamic. A static string synth field can only accept a
+        * same-sized static string, which is checked for later.
+        */
+       if (strstr(hist_field->type, "char[") && field->is_string
+           && field->is_dynamic)
+               return 0;
+
        if (strcmp(field->type, hist_field->type) != 0) {
                if (field->size != hist_field->size ||
                    field->is_signed != hist_field->is_signed)
@@ -3336,7 +3355,7 @@ trace_action_create_field_var(struct hist_trigger_data *hist_data,
        } else {
                field_var = NULL;
                /*
-                * If no explicit system.event is specfied, default to
+                * If no explicit system.event is specified, default to
                 * looking for fields on the onmatch(system.event.xxx)
                 * event.
                 */
@@ -3651,6 +3670,7 @@ static int create_var_field(struct hist_trigger_data *hist_data,
 {
        struct trace_array *tr = hist_data->event_file->tr;
        unsigned long flags = 0;
+       int ret;
 
        if (WARN_ON(val_idx >= TRACING_MAP_VALS_MAX + TRACING_MAP_VARS_MAX))
                return -EINVAL;
@@ -3665,7 +3685,12 @@ static int create_var_field(struct hist_trigger_data *hist_data,
        if (WARN_ON(hist_data->n_vars > TRACING_MAP_VARS_MAX))
                return -EINVAL;
 
-       return __create_val_field(hist_data, val_idx, file, var_name, expr_str, flags);
+       ret = __create_val_field(hist_data, val_idx, file, var_name, expr_str, flags);
+
+       if (!ret && hist_data->fields[val_idx]->flags & HIST_FIELD_FL_STRING)
+               hist_data->fields[val_idx]->var_str_idx = hist_data->n_var_str++;
+
+       return ret;
 }
 
 static int create_val_fields(struct hist_trigger_data *hist_data,
@@ -4392,6 +4417,22 @@ static void hist_trigger_elt_update(struct hist_trigger_data *hist_data,
                hist_val = hist_field->fn(hist_field, elt, rbe, rec);
                if (hist_field->flags & HIST_FIELD_FL_VAR) {
                        var_idx = hist_field->var.idx;
+
+                       if (hist_field->flags & HIST_FIELD_FL_STRING) {
+                               unsigned int str_start, var_str_idx, idx;
+                               char *str, *val_str;
+
+                               str_start = hist_data->n_field_var_str +
+                                       hist_data->n_save_var_str;
+                               var_str_idx = hist_field->var_str_idx;
+                               idx = str_start + var_str_idx;
+
+                               str = elt_data->field_var_str[idx];
+                               val_str = (char *)(uintptr_t)hist_val;
+                               strscpy(str, val_str, STR_VAR_LEN_MAX);
+
+                               hist_val = (u64)(uintptr_t)str;
+                       }
                        tracing_map_set_var(elt, var_idx, hist_val);
                        continue;
                }