diff options
Diffstat (limited to 'kernel/trace/trace.c')
| -rw-r--r-- | kernel/trace/trace.c | 491 |
1 files changed, 391 insertions, 100 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 62c6506d663f..91eecaaa43e0 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -20,6 +20,7 @@ | |||
| 20 | #include <linux/notifier.h> | 20 | #include <linux/notifier.h> |
| 21 | #include <linux/irqflags.h> | 21 | #include <linux/irqflags.h> |
| 22 | #include <linux/debugfs.h> | 22 | #include <linux/debugfs.h> |
| 23 | #include <linux/tracefs.h> | ||
| 23 | #include <linux/pagemap.h> | 24 | #include <linux/pagemap.h> |
| 24 | #include <linux/hardirq.h> | 25 | #include <linux/hardirq.h> |
| 25 | #include <linux/linkage.h> | 26 | #include <linux/linkage.h> |
| @@ -31,6 +32,7 @@ | |||
| 31 | #include <linux/splice.h> | 32 | #include <linux/splice.h> |
| 32 | #include <linux/kdebug.h> | 33 | #include <linux/kdebug.h> |
| 33 | #include <linux/string.h> | 34 | #include <linux/string.h> |
| 35 | #include <linux/mount.h> | ||
| 34 | #include <linux/rwsem.h> | 36 | #include <linux/rwsem.h> |
| 35 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
| 36 | #include <linux/ctype.h> | 38 | #include <linux/ctype.h> |
| @@ -123,6 +125,42 @@ enum ftrace_dump_mode ftrace_dump_on_oops; | |||
| 123 | /* When set, tracing will stop when a WARN*() is hit */ | 125 | /* When set, tracing will stop when a WARN*() is hit */ |
| 124 | int __disable_trace_on_warning; | 126 | int __disable_trace_on_warning; |
| 125 | 127 | ||
| 128 | #ifdef CONFIG_TRACE_ENUM_MAP_FILE | ||
| 129 | /* Map of enums to their values, for "enum_map" file */ | ||
| 130 | struct trace_enum_map_head { | ||
| 131 | struct module *mod; | ||
| 132 | unsigned long length; | ||
| 133 | }; | ||
| 134 | |||
| 135 | union trace_enum_map_item; | ||
| 136 | |||
| 137 | struct trace_enum_map_tail { | ||
| 138 | /* | ||
| 139 | * "end" is first and points to NULL as it must be different | ||
| 140 | * than "mod" or "enum_string" | ||
| 141 | */ | ||
| 142 | union trace_enum_map_item *next; | ||
| 143 | const char *end; /* points to NULL */ | ||
| 144 | }; | ||
| 145 | |||
| 146 | static DEFINE_MUTEX(trace_enum_mutex); | ||
| 147 | |||
| 148 | /* | ||
| 149 | * The trace_enum_maps are saved in an array with two extra elements, | ||
| 150 | * one at the beginning, and one at the end. The beginning item contains | ||
| 151 | * the count of the saved maps (head.length), and the module they | ||
| 152 | * belong to if not built in (head.mod). The ending item contains a | ||
| 153 | * pointer to the next array of saved enum_map items. | ||
| 154 | */ | ||
| 155 | union trace_enum_map_item { | ||
| 156 | struct trace_enum_map map; | ||
| 157 | struct trace_enum_map_head head; | ||
| 158 | struct trace_enum_map_tail tail; | ||
| 159 | }; | ||
| 160 | |||
| 161 | static union trace_enum_map_item *trace_enum_maps; | ||
| 162 | #endif /* CONFIG_TRACE_ENUM_MAP_FILE */ | ||
| 163 | |||
| 126 | static int tracing_set_tracer(struct trace_array *tr, const char *buf); | 164 | static int tracing_set_tracer(struct trace_array *tr, const char *buf); |
| 127 | 165 | ||
| 128 | #define MAX_TRACER_SIZE 100 | 166 | #define MAX_TRACER_SIZE 100 |
| @@ -3908,6 +3946,182 @@ static const struct file_operations tracing_saved_cmdlines_size_fops = { | |||
| 3908 | .write = tracing_saved_cmdlines_size_write, | 3946 | .write = tracing_saved_cmdlines_size_write, |
| 3909 | }; | 3947 | }; |
| 3910 | 3948 | ||
| 3949 | #ifdef CONFIG_TRACE_ENUM_MAP_FILE | ||
| 3950 | static union trace_enum_map_item * | ||
| 3951 | update_enum_map(union trace_enum_map_item *ptr) | ||
| 3952 | { | ||
| 3953 | if (!ptr->map.enum_string) { | ||
| 3954 | if (ptr->tail.next) { | ||
| 3955 | ptr = ptr->tail.next; | ||
| 3956 | /* Set ptr to the next real item (skip head) */ | ||
| 3957 | ptr++; | ||
| 3958 | } else | ||
| 3959 | return NULL; | ||
| 3960 | } | ||
| 3961 | return ptr; | ||
| 3962 | } | ||
| 3963 | |||
| 3964 | static void *enum_map_next(struct seq_file *m, void *v, loff_t *pos) | ||
| 3965 | { | ||
| 3966 | union trace_enum_map_item *ptr = v; | ||
| 3967 | |||
| 3968 | /* | ||
| 3969 | * Paranoid! If ptr points to end, we don't want to increment past it. | ||
| 3970 | * This really should never happen. | ||
| 3971 | */ | ||
| 3972 | ptr = update_enum_map(ptr); | ||
| 3973 | if (WARN_ON_ONCE(!ptr)) | ||
| 3974 | return NULL; | ||
| 3975 | |||
| 3976 | ptr++; | ||
| 3977 | |||
| 3978 | (*pos)++; | ||
| 3979 | |||
| 3980 | ptr = update_enum_map(ptr); | ||
| 3981 | |||
| 3982 | return ptr; | ||
| 3983 | } | ||
| 3984 | |||
| 3985 | static void *enum_map_start(struct seq_file *m, loff_t *pos) | ||
| 3986 | { | ||
| 3987 | union trace_enum_map_item *v; | ||
| 3988 | loff_t l = 0; | ||
| 3989 | |||
| 3990 | mutex_lock(&trace_enum_mutex); | ||
| 3991 | |||
| 3992 | v = trace_enum_maps; | ||
| 3993 | if (v) | ||
| 3994 | v++; | ||
| 3995 | |||
| 3996 | while (v && l < *pos) { | ||
| 3997 | v = enum_map_next(m, v, &l); | ||
| 3998 | } | ||
| 3999 | |||
| 4000 | return v; | ||
| 4001 | } | ||
| 4002 | |||
| 4003 | static void enum_map_stop(struct seq_file *m, void *v) | ||
| 4004 | { | ||
| 4005 | mutex_unlock(&trace_enum_mutex); | ||
| 4006 | } | ||
| 4007 | |||
| 4008 | static int enum_map_show(struct seq_file *m, void *v) | ||
| 4009 | { | ||
| 4010 | union trace_enum_map_item *ptr = v; | ||
| 4011 | |||
| 4012 | seq_printf(m, "%s %ld (%s)\n", | ||
| 4013 | ptr->map.enum_string, ptr->map.enum_value, | ||
| 4014 | ptr->map.system); | ||
| 4015 | |||
| 4016 | return 0; | ||
| 4017 | } | ||
| 4018 | |||
| 4019 | static const struct seq_operations tracing_enum_map_seq_ops = { | ||
| 4020 | .start = enum_map_start, | ||
| 4021 | .next = enum_map_next, | ||
| 4022 | .stop = enum_map_stop, | ||
| 4023 | .show = enum_map_show, | ||
| 4024 | }; | ||
| 4025 | |||
| 4026 | static int tracing_enum_map_open(struct inode *inode, struct file *filp) | ||
| 4027 | { | ||
| 4028 | if (tracing_disabled) | ||
| 4029 | return -ENODEV; | ||
| 4030 | |||
| 4031 | return seq_open(filp, &tracing_enum_map_seq_ops); | ||
| 4032 | } | ||
| 4033 | |||
| 4034 | static const struct file_operations tracing_enum_map_fops = { | ||
| 4035 | .open = tracing_enum_map_open, | ||
| 4036 | .read = seq_read, | ||
| 4037 | .llseek = seq_lseek, | ||
| 4038 | .release = seq_release, | ||
| 4039 | }; | ||
| 4040 | |||
| 4041 | static inline union trace_enum_map_item * | ||
| 4042 | trace_enum_jmp_to_tail(union trace_enum_map_item *ptr) | ||
| 4043 | { | ||
| 4044 | /* Return tail of array given the head */ | ||
| 4045 | return ptr + ptr->head.length + 1; | ||
| 4046 | } | ||
| 4047 | |||
| 4048 | static void | ||
| 4049 | trace_insert_enum_map_file(struct module *mod, struct trace_enum_map **start, | ||
| 4050 | int len) | ||
| 4051 | { | ||
| 4052 | struct trace_enum_map **stop; | ||
| 4053 | struct trace_enum_map **map; | ||
| 4054 | union trace_enum_map_item *map_array; | ||
| 4055 | union trace_enum_map_item *ptr; | ||
| 4056 | |||
| 4057 | stop = start + len; | ||
| 4058 | |||
| 4059 | /* | ||
| 4060 | * The trace_enum_maps contains the map plus a head and tail item, | ||
| 4061 | * where the head holds the module and length of array, and the | ||
| 4062 | * tail holds a pointer to the next list. | ||
| 4063 | */ | ||
| 4064 | map_array = kmalloc(sizeof(*map_array) * (len + 2), GFP_KERNEL); | ||
| 4065 | if (!map_array) { | ||
| 4066 | pr_warning("Unable to allocate trace enum mapping\n"); | ||
| 4067 | return; | ||
| 4068 | } | ||
| 4069 | |||
| 4070 | mutex_lock(&trace_enum_mutex); | ||
| 4071 | |||
| 4072 | if (!trace_enum_maps) | ||
| 4073 | trace_enum_maps = map_array; | ||
| 4074 | else { | ||
| 4075 | ptr = trace_enum_maps; | ||
| 4076 | for (;;) { | ||
| 4077 | ptr = trace_enum_jmp_to_tail(ptr); | ||
| 4078 | if (!ptr->tail.next) | ||
| 4079 | break; | ||
| 4080 | ptr = ptr->tail.next; | ||
| 4081 | |||
| 4082 | } | ||
| 4083 | ptr->tail.next = map_array; | ||
| 4084 | } | ||
| 4085 | map_array->head.mod = mod; | ||
| 4086 | map_array->head.length = len; | ||
| 4087 | map_array++; | ||
| 4088 | |||
| 4089 | for (map = start; (unsigned long)map < (unsigned long)stop; map++) { | ||
| 4090 | map_array->map = **map; | ||
| 4091 | map_array++; | ||
| 4092 | } | ||
| 4093 | memset(map_array, 0, sizeof(*map_array)); | ||
| 4094 | |||
| 4095 | mutex_unlock(&trace_enum_mutex); | ||
| 4096 | } | ||
| 4097 | |||
| 4098 | static void trace_create_enum_file(struct dentry *d_tracer) | ||
| 4099 | { | ||
| 4100 | trace_create_file("enum_map", 0444, d_tracer, | ||
| 4101 | NULL, &tracing_enum_map_fops); | ||
| 4102 | } | ||
| 4103 | |||
| 4104 | #else /* CONFIG_TRACE_ENUM_MAP_FILE */ | ||
| 4105 | static inline void trace_create_enum_file(struct dentry *d_tracer) { } | ||
| 4106 | static inline void trace_insert_enum_map_file(struct module *mod, | ||
| 4107 | struct trace_enum_map **start, int len) { } | ||
| 4108 | #endif /* !CONFIG_TRACE_ENUM_MAP_FILE */ | ||
| 4109 | |||
| 4110 | static void trace_insert_enum_map(struct module *mod, | ||
| 4111 | struct trace_enum_map **start, int len) | ||
| 4112 | { | ||
| 4113 | struct trace_enum_map **map; | ||
| 4114 | |||
| 4115 | if (len <= 0) | ||
| 4116 | return; | ||
| 4117 | |||
| 4118 | map = start; | ||
| 4119 | |||
| 4120 | trace_event_enum_update(map, len); | ||
| 4121 | |||
| 4122 | trace_insert_enum_map_file(mod, start, len); | ||
| 4123 | } | ||
| 4124 | |||
| 3911 | static ssize_t | 4125 | static ssize_t |
| 3912 | tracing_set_trace_read(struct file *filp, char __user *ubuf, | 4126 | tracing_set_trace_read(struct file *filp, char __user *ubuf, |
| 3913 | size_t cnt, loff_t *ppos) | 4127 | size_t cnt, loff_t *ppos) |
| @@ -4105,9 +4319,24 @@ static void tracing_set_nop(struct trace_array *tr) | |||
| 4105 | tr->current_trace = &nop_trace; | 4319 | tr->current_trace = &nop_trace; |
| 4106 | } | 4320 | } |
| 4107 | 4321 | ||
| 4108 | static int tracing_set_tracer(struct trace_array *tr, const char *buf) | 4322 | static void update_tracer_options(struct trace_array *tr, struct tracer *t) |
| 4109 | { | 4323 | { |
| 4110 | static struct trace_option_dentry *topts; | 4324 | static struct trace_option_dentry *topts; |
| 4325 | |||
| 4326 | /* Only enable if the directory has been created already. */ | ||
| 4327 | if (!tr->dir) | ||
| 4328 | return; | ||
| 4329 | |||
| 4330 | /* Currently, only the top instance has options */ | ||
| 4331 | if (!(tr->flags & TRACE_ARRAY_FL_GLOBAL)) | ||
| 4332 | return; | ||
| 4333 | |||
| 4334 | destroy_trace_option_files(topts); | ||
| 4335 | topts = create_trace_option_files(tr, t); | ||
| 4336 | } | ||
| 4337 | |||
| 4338 | static int tracing_set_tracer(struct trace_array *tr, const char *buf) | ||
| 4339 | { | ||
| 4111 | struct tracer *t; | 4340 | struct tracer *t; |
| 4112 | #ifdef CONFIG_TRACER_MAX_TRACE | 4341 | #ifdef CONFIG_TRACER_MAX_TRACE |
| 4113 | bool had_max_tr; | 4342 | bool had_max_tr; |
| @@ -4172,11 +4401,7 @@ static int tracing_set_tracer(struct trace_array *tr, const char *buf) | |||
| 4172 | free_snapshot(tr); | 4401 | free_snapshot(tr); |
| 4173 | } | 4402 | } |
| 4174 | #endif | 4403 | #endif |
| 4175 | /* Currently, only the top instance has options */ | 4404 | update_tracer_options(tr, t); |
| 4176 | if (tr->flags & TRACE_ARRAY_FL_GLOBAL) { | ||
| 4177 | destroy_trace_option_files(topts); | ||
| 4178 | topts = create_trace_option_files(tr, t); | ||
| 4179 | } | ||
| 4180 | 4405 | ||
| 4181 | #ifdef CONFIG_TRACER_MAX_TRACE | 4406 | #ifdef CONFIG_TRACER_MAX_TRACE |
| 4182 | if (t->use_max_tr && !had_max_tr) { | 4407 | if (t->use_max_tr && !had_max_tr) { |
| @@ -5817,6 +6042,14 @@ static inline __init int register_snapshot_cmd(void) { return 0; } | |||
| 5817 | 6042 | ||
| 5818 | static struct dentry *tracing_get_dentry(struct trace_array *tr) | 6043 | static struct dentry *tracing_get_dentry(struct trace_array *tr) |
| 5819 | { | 6044 | { |
| 6045 | if (WARN_ON(!tr->dir)) | ||
| 6046 | return ERR_PTR(-ENODEV); | ||
| 6047 | |||
| 6048 | /* Top directory uses NULL as the parent */ | ||
| 6049 | if (tr->flags & TRACE_ARRAY_FL_GLOBAL) | ||
| 6050 | return NULL; | ||
| 6051 | |||
| 6052 | /* All sub buffers have a descriptor */ | ||
| 5820 | return tr->dir; | 6053 | return tr->dir; |
| 5821 | } | 6054 | } |
| 5822 | 6055 | ||
| @@ -5831,10 +6064,10 @@ static struct dentry *tracing_dentry_percpu(struct trace_array *tr, int cpu) | |||
| 5831 | if (IS_ERR(d_tracer)) | 6064 | if (IS_ERR(d_tracer)) |
| 5832 | return NULL; | 6065 | return NULL; |
| 5833 | 6066 | ||
| 5834 | tr->percpu_dir = debugfs_create_dir("per_cpu", d_tracer); | 6067 | tr->percpu_dir = tracefs_create_dir("per_cpu", d_tracer); |
| 5835 | 6068 | ||
| 5836 | WARN_ONCE(!tr->percpu_dir, | 6069 | WARN_ONCE(!tr->percpu_dir, |
| 5837 | "Could not create debugfs directory 'per_cpu/%d'\n", cpu); | 6070 | "Could not create tracefs directory 'per_cpu/%d'\n", cpu); |
| 5838 | 6071 | ||
| 5839 | return tr->percpu_dir; | 6072 | return tr->percpu_dir; |
| 5840 | } | 6073 | } |
| @@ -5851,7 +6084,7 @@ trace_create_cpu_file(const char *name, umode_t mode, struct dentry *parent, | |||
| 5851 | } | 6084 | } |
| 5852 | 6085 | ||
| 5853 | static void | 6086 | static void |
| 5854 | tracing_init_debugfs_percpu(struct trace_array *tr, long cpu) | 6087 | tracing_init_tracefs_percpu(struct trace_array *tr, long cpu) |
| 5855 | { | 6088 | { |
| 5856 | struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu); | 6089 | struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu); |
| 5857 | struct dentry *d_cpu; | 6090 | struct dentry *d_cpu; |
| @@ -5861,9 +6094,9 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu) | |||
| 5861 | return; | 6094 | return; |
| 5862 | 6095 | ||
| 5863 | snprintf(cpu_dir, 30, "cpu%ld", cpu); | 6096 | snprintf(cpu_dir, 30, "cpu%ld", cpu); |
| 5864 | d_cpu = debugfs_create_dir(cpu_dir, d_percpu); | 6097 | d_cpu = tracefs_create_dir(cpu_dir, d_percpu); |
| 5865 | if (!d_cpu) { | 6098 | if (!d_cpu) { |
| 5866 | pr_warning("Could not create debugfs '%s' entry\n", cpu_dir); | 6099 | pr_warning("Could not create tracefs '%s' entry\n", cpu_dir); |
| 5867 | return; | 6100 | return; |
| 5868 | } | 6101 | } |
| 5869 | 6102 | ||
| @@ -6015,9 +6248,9 @@ struct dentry *trace_create_file(const char *name, | |||
| 6015 | { | 6248 | { |
| 6016 | struct dentry *ret; | 6249 | struct dentry *ret; |
| 6017 | 6250 | ||
| 6018 | ret = debugfs_create_file(name, mode, parent, data, fops); | 6251 | ret = tracefs_create_file(name, mode, parent, data, fops); |
| 6019 | if (!ret) | 6252 | if (!ret) |
| 6020 | pr_warning("Could not create debugfs '%s' entry\n", name); | 6253 | pr_warning("Could not create tracefs '%s' entry\n", name); |
| 6021 | 6254 | ||
| 6022 | return ret; | 6255 | return ret; |
| 6023 | } | 6256 | } |
| @@ -6034,9 +6267,9 @@ static struct dentry *trace_options_init_dentry(struct trace_array *tr) | |||
| 6034 | if (IS_ERR(d_tracer)) | 6267 | if (IS_ERR(d_tracer)) |
| 6035 | return NULL; | 6268 | return NULL; |
| 6036 | 6269 | ||
| 6037 | tr->options = debugfs_create_dir("options", d_tracer); | 6270 | tr->options = tracefs_create_dir("options", d_tracer); |
| 6038 | if (!tr->options) { | 6271 | if (!tr->options) { |
| 6039 | pr_warning("Could not create debugfs directory 'options'\n"); | 6272 | pr_warning("Could not create tracefs directory 'options'\n"); |
| 6040 | return NULL; | 6273 | return NULL; |
| 6041 | } | 6274 | } |
| 6042 | 6275 | ||
| @@ -6105,7 +6338,7 @@ destroy_trace_option_files(struct trace_option_dentry *topts) | |||
| 6105 | return; | 6338 | return; |
| 6106 | 6339 | ||
| 6107 | for (cnt = 0; topts[cnt].opt; cnt++) | 6340 | for (cnt = 0; topts[cnt].opt; cnt++) |
| 6108 | debugfs_remove(topts[cnt].entry); | 6341 | tracefs_remove(topts[cnt].entry); |
| 6109 | 6342 | ||
| 6110 | kfree(topts); | 6343 | kfree(topts); |
| 6111 | } | 6344 | } |
| @@ -6194,7 +6427,7 @@ static const struct file_operations rb_simple_fops = { | |||
| 6194 | struct dentry *trace_instance_dir; | 6427 | struct dentry *trace_instance_dir; |
| 6195 | 6428 | ||
| 6196 | static void | 6429 | static void |
| 6197 | init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer); | 6430 | init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer); |
| 6198 | 6431 | ||
| 6199 | static int | 6432 | static int |
| 6200 | allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size) | 6433 | allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size) |
| @@ -6271,7 +6504,7 @@ static void free_trace_buffers(struct trace_array *tr) | |||
| 6271 | #endif | 6504 | #endif |
| 6272 | } | 6505 | } |
| 6273 | 6506 | ||
| 6274 | static int new_instance_create(const char *name) | 6507 | static int instance_mkdir(const char *name) |
| 6275 | { | 6508 | { |
| 6276 | struct trace_array *tr; | 6509 | struct trace_array *tr; |
| 6277 | int ret; | 6510 | int ret; |
| @@ -6310,17 +6543,17 @@ static int new_instance_create(const char *name) | |||
| 6310 | if (allocate_trace_buffers(tr, trace_buf_size) < 0) | 6543 | if (allocate_trace_buffers(tr, trace_buf_size) < 0) |
| 6311 | goto out_free_tr; | 6544 | goto out_free_tr; |
| 6312 | 6545 | ||
| 6313 | tr->dir = debugfs_create_dir(name, trace_instance_dir); | 6546 | tr->dir = tracefs_create_dir(name, trace_instance_dir); |
| 6314 | if (!tr->dir) | 6547 | if (!tr->dir) |
| 6315 | goto out_free_tr; | 6548 | goto out_free_tr; |
| 6316 | 6549 | ||
| 6317 | ret = event_trace_add_tracer(tr->dir, tr); | 6550 | ret = event_trace_add_tracer(tr->dir, tr); |
| 6318 | if (ret) { | 6551 | if (ret) { |
| 6319 | debugfs_remove_recursive(tr->dir); | 6552 | tracefs_remove_recursive(tr->dir); |
| 6320 | goto out_free_tr; | 6553 | goto out_free_tr; |
| 6321 | } | 6554 | } |
| 6322 | 6555 | ||
| 6323 | init_tracer_debugfs(tr, tr->dir); | 6556 | init_tracer_tracefs(tr, tr->dir); |
| 6324 | 6557 | ||
| 6325 | list_add(&tr->list, &ftrace_trace_arrays); | 6558 | list_add(&tr->list, &ftrace_trace_arrays); |
| 6326 | 6559 | ||
| @@ -6341,7 +6574,7 @@ static int new_instance_create(const char *name) | |||
| 6341 | 6574 | ||
| 6342 | } | 6575 | } |
| 6343 | 6576 | ||
| 6344 | static int instance_delete(const char *name) | 6577 | static int instance_rmdir(const char *name) |
| 6345 | { | 6578 | { |
| 6346 | struct trace_array *tr; | 6579 | struct trace_array *tr; |
| 6347 | int found = 0; | 6580 | int found = 0; |
| @@ -6382,82 +6615,17 @@ static int instance_delete(const char *name) | |||
| 6382 | return ret; | 6615 | return ret; |
| 6383 | } | 6616 | } |
| 6384 | 6617 | ||
| 6385 | static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t mode) | ||
| 6386 | { | ||
| 6387 | struct dentry *parent; | ||
| 6388 | int ret; | ||
| 6389 | |||
| 6390 | /* Paranoid: Make sure the parent is the "instances" directory */ | ||
| 6391 | parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); | ||
| 6392 | if (WARN_ON_ONCE(parent != trace_instance_dir)) | ||
| 6393 | return -ENOENT; | ||
| 6394 | |||
| 6395 | /* | ||
| 6396 | * The inode mutex is locked, but debugfs_create_dir() will also | ||
| 6397 | * take the mutex. As the instances directory can not be destroyed | ||
| 6398 | * or changed in any other way, it is safe to unlock it, and | ||
| 6399 | * let the dentry try. If two users try to make the same dir at | ||
| 6400 | * the same time, then the new_instance_create() will determine the | ||
| 6401 | * winner. | ||
| 6402 | */ | ||
| 6403 | mutex_unlock(&inode->i_mutex); | ||
| 6404 | |||
| 6405 | ret = new_instance_create(dentry->d_iname); | ||
| 6406 | |||
| 6407 | mutex_lock(&inode->i_mutex); | ||
| 6408 | |||
| 6409 | return ret; | ||
| 6410 | } | ||
| 6411 | |||
| 6412 | static int instance_rmdir(struct inode *inode, struct dentry *dentry) | ||
| 6413 | { | ||
| 6414 | struct dentry *parent; | ||
| 6415 | int ret; | ||
| 6416 | |||
| 6417 | /* Paranoid: Make sure the parent is the "instances" directory */ | ||
| 6418 | parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); | ||
| 6419 | if (WARN_ON_ONCE(parent != trace_instance_dir)) | ||
| 6420 | return -ENOENT; | ||
| 6421 | |||
| 6422 | /* The caller did a dget() on dentry */ | ||
| 6423 | mutex_unlock(&dentry->d_inode->i_mutex); | ||
| 6424 | |||
| 6425 | /* | ||
| 6426 | * The inode mutex is locked, but debugfs_create_dir() will also | ||
| 6427 | * take the mutex. As the instances directory can not be destroyed | ||
| 6428 | * or changed in any other way, it is safe to unlock it, and | ||
| 6429 | * let the dentry try. If two users try to make the same dir at | ||
| 6430 | * the same time, then the instance_delete() will determine the | ||
| 6431 | * winner. | ||
| 6432 | */ | ||
| 6433 | mutex_unlock(&inode->i_mutex); | ||
| 6434 | |||
| 6435 | ret = instance_delete(dentry->d_iname); | ||
| 6436 | |||
| 6437 | mutex_lock_nested(&inode->i_mutex, I_MUTEX_PARENT); | ||
| 6438 | mutex_lock(&dentry->d_inode->i_mutex); | ||
| 6439 | |||
| 6440 | return ret; | ||
| 6441 | } | ||
| 6442 | |||
| 6443 | static const struct inode_operations instance_dir_inode_operations = { | ||
| 6444 | .lookup = simple_lookup, | ||
| 6445 | .mkdir = instance_mkdir, | ||
| 6446 | .rmdir = instance_rmdir, | ||
| 6447 | }; | ||
| 6448 | |||
| 6449 | static __init void create_trace_instances(struct dentry *d_tracer) | 6618 | static __init void create_trace_instances(struct dentry *d_tracer) |
| 6450 | { | 6619 | { |
| 6451 | trace_instance_dir = debugfs_create_dir("instances", d_tracer); | 6620 | trace_instance_dir = tracefs_create_instance_dir("instances", d_tracer, |
| 6621 | instance_mkdir, | ||
| 6622 | instance_rmdir); | ||
| 6452 | if (WARN_ON(!trace_instance_dir)) | 6623 | if (WARN_ON(!trace_instance_dir)) |
| 6453 | return; | 6624 | return; |
| 6454 | |||
| 6455 | /* Hijack the dir inode operations, to allow mkdir */ | ||
| 6456 | trace_instance_dir->d_inode->i_op = &instance_dir_inode_operations; | ||
| 6457 | } | 6625 | } |
| 6458 | 6626 | ||
| 6459 | static void | 6627 | static void |
| 6460 | init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer) | 6628 | init_tracer_tracefs(struct trace_array *tr, struct dentry *d_tracer) |
| 6461 | { | 6629 | { |
| 6462 | int cpu; | 6630 | int cpu; |
| 6463 | 6631 | ||
| @@ -6511,10 +6679,32 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer) | |||
| 6511 | #endif | 6679 | #endif |
| 6512 | 6680 | ||
| 6513 | for_each_tracing_cpu(cpu) | 6681 | for_each_tracing_cpu(cpu) |
| 6514 | tracing_init_debugfs_percpu(tr, cpu); | 6682 | tracing_init_tracefs_percpu(tr, cpu); |
| 6515 | 6683 | ||
| 6516 | } | 6684 | } |
| 6517 | 6685 | ||
| 6686 | static struct vfsmount *trace_automount(void *ingore) | ||
| 6687 | { | ||
| 6688 | struct vfsmount *mnt; | ||
| 6689 | struct file_system_type *type; | ||
| 6690 | |||
| 6691 | /* | ||
| 6692 | * To maintain backward compatibility for tools that mount | ||
| 6693 | * debugfs to get to the tracing facility, tracefs is automatically | ||
| 6694 | * mounted to the debugfs/tracing directory. | ||
| 6695 | */ | ||
| 6696 | type = get_fs_type("tracefs"); | ||
| 6697 | if (!type) | ||
| 6698 | return NULL; | ||
| 6699 | mnt = vfs_kern_mount(type, 0, "tracefs", NULL); | ||
| 6700 | put_filesystem(type); | ||
| 6701 | if (IS_ERR(mnt)) | ||
| 6702 | return NULL; | ||
| 6703 | mntget(mnt); | ||
| 6704 | |||
| 6705 | return mnt; | ||
| 6706 | } | ||
| 6707 | |||
| 6518 | /** | 6708 | /** |
| 6519 | * tracing_init_dentry - initialize top level trace array | 6709 | * tracing_init_dentry - initialize top level trace array |
| 6520 | * | 6710 | * |
| @@ -6526,23 +6716,112 @@ struct dentry *tracing_init_dentry(void) | |||
| 6526 | { | 6716 | { |
| 6527 | struct trace_array *tr = &global_trace; | 6717 | struct trace_array *tr = &global_trace; |
| 6528 | 6718 | ||
| 6719 | /* The top level trace array uses NULL as parent */ | ||
| 6529 | if (tr->dir) | 6720 | if (tr->dir) |
| 6530 | return tr->dir; | 6721 | return NULL; |
| 6531 | 6722 | ||
| 6532 | if (WARN_ON(!debugfs_initialized())) | 6723 | if (WARN_ON(!debugfs_initialized())) |
| 6533 | return ERR_PTR(-ENODEV); | 6724 | return ERR_PTR(-ENODEV); |
| 6534 | 6725 | ||
| 6535 | tr->dir = debugfs_create_dir("tracing", NULL); | 6726 | /* |
| 6536 | 6727 | * As there may still be users that expect the tracing | |
| 6728 | * files to exist in debugfs/tracing, we must automount | ||
| 6729 | * the tracefs file system there, so older tools still | ||
| 6730 | * work with the newer kerenl. | ||
| 6731 | */ | ||
| 6732 | tr->dir = debugfs_create_automount("tracing", NULL, | ||
| 6733 | trace_automount, NULL); | ||
| 6537 | if (!tr->dir) { | 6734 | if (!tr->dir) { |
| 6538 | pr_warn_once("Could not create debugfs directory 'tracing'\n"); | 6735 | pr_warn_once("Could not create debugfs directory 'tracing'\n"); |
| 6539 | return ERR_PTR(-ENOMEM); | 6736 | return ERR_PTR(-ENOMEM); |
| 6540 | } | 6737 | } |
| 6541 | 6738 | ||
| 6542 | return tr->dir; | 6739 | return NULL; |
| 6740 | } | ||
| 6741 | |||
| 6742 | extern struct trace_enum_map *__start_ftrace_enum_maps[]; | ||
| 6743 | extern struct trace_enum_map *__stop_ftrace_enum_maps[]; | ||
| 6744 | |||
| 6745 | static void __init trace_enum_init(void) | ||
| 6746 | { | ||
| 6747 | int len; | ||
| 6748 | |||
| 6749 | len = __stop_ftrace_enum_maps - __start_ftrace_enum_maps; | ||
| 6750 | trace_insert_enum_map(NULL, __start_ftrace_enum_maps, len); | ||
| 6751 | } | ||
| 6752 | |||
| 6753 | #ifdef CONFIG_MODULES | ||
| 6754 | static void trace_module_add_enums(struct module *mod) | ||
| 6755 | { | ||
| 6756 | if (!mod->num_trace_enums) | ||
| 6757 | return; | ||
| 6758 | |||
| 6759 | /* | ||
| 6760 | * Modules with bad taint do not have events created, do | ||
| 6761 | * not bother with enums either. | ||
| 6762 | */ | ||
| 6763 | if (trace_module_has_bad_taint(mod)) | ||
| 6764 | return; | ||
| 6765 | |||
| 6766 | trace_insert_enum_map(mod, mod->trace_enums, mod->num_trace_enums); | ||
| 6543 | } | 6767 | } |
| 6544 | 6768 | ||
| 6545 | static __init int tracer_init_debugfs(void) | 6769 | #ifdef CONFIG_TRACE_ENUM_MAP_FILE |
| 6770 | static void trace_module_remove_enums(struct module *mod) | ||
| 6771 | { | ||
| 6772 | union trace_enum_map_item *map; | ||
| 6773 | union trace_enum_map_item **last = &trace_enum_maps; | ||
| 6774 | |||
| 6775 | if (!mod->num_trace_enums) | ||
| 6776 | return; | ||
| 6777 | |||
| 6778 | mutex_lock(&trace_enum_mutex); | ||
| 6779 | |||
| 6780 | map = trace_enum_maps; | ||
| 6781 | |||
| 6782 | while (map) { | ||
| 6783 | if (map->head.mod == mod) | ||
| 6784 | break; | ||
| 6785 | map = trace_enum_jmp_to_tail(map); | ||
| 6786 | last = &map->tail.next; | ||
| 6787 | map = map->tail.next; | ||
| 6788 | } | ||
| 6789 | if (!map) | ||
| 6790 | goto out; | ||
| 6791 | |||
| 6792 | *last = trace_enum_jmp_to_tail(map)->tail.next; | ||
| 6793 | kfree(map); | ||
| 6794 | out: | ||
| 6795 | mutex_unlock(&trace_enum_mutex); | ||
| 6796 | } | ||
| 6797 | #else | ||
| 6798 | static inline void trace_module_remove_enums(struct module *mod) { } | ||
| 6799 | #endif /* CONFIG_TRACE_ENUM_MAP_FILE */ | ||
| 6800 | |||
| 6801 | static int trace_module_notify(struct notifier_block *self, | ||
| 6802 | unsigned long val, void *data) | ||
| 6803 | { | ||
| 6804 | struct module *mod = data; | ||
| 6805 | |||
| 6806 | switch (val) { | ||
| 6807 | case MODULE_STATE_COMING: | ||
| 6808 | trace_module_add_enums(mod); | ||
| 6809 | break; | ||
| 6810 | case MODULE_STATE_GOING: | ||
| 6811 | trace_module_remove_enums(mod); | ||
| 6812 | break; | ||
| 6813 | } | ||
| 6814 | |||
| 6815 | return 0; | ||
| 6816 | } | ||
| 6817 | |||
| 6818 | static struct notifier_block trace_module_nb = { | ||
| 6819 | .notifier_call = trace_module_notify, | ||
| 6820 | .priority = 0, | ||
| 6821 | }; | ||
| 6822 | #endif /* CONFIG_MODULES */ | ||
| 6823 | |||
| 6824 | static __init int tracer_init_tracefs(void) | ||
| 6546 | { | 6825 | { |
| 6547 | struct dentry *d_tracer; | 6826 | struct dentry *d_tracer; |
| 6548 | 6827 | ||
| @@ -6552,7 +6831,7 @@ static __init int tracer_init_debugfs(void) | |||
| 6552 | if (IS_ERR(d_tracer)) | 6831 | if (IS_ERR(d_tracer)) |
| 6553 | return 0; | 6832 | return 0; |
| 6554 | 6833 | ||
| 6555 | init_tracer_debugfs(&global_trace, d_tracer); | 6834 | init_tracer_tracefs(&global_trace, d_tracer); |
| 6556 | 6835 | ||
| 6557 | trace_create_file("tracing_thresh", 0644, d_tracer, | 6836 | trace_create_file("tracing_thresh", 0644, d_tracer, |
| 6558 | &global_trace, &tracing_thresh_fops); | 6837 | &global_trace, &tracing_thresh_fops); |
| @@ -6566,6 +6845,14 @@ static __init int tracer_init_debugfs(void) | |||
| 6566 | trace_create_file("saved_cmdlines_size", 0644, d_tracer, | 6845 | trace_create_file("saved_cmdlines_size", 0644, d_tracer, |
| 6567 | NULL, &tracing_saved_cmdlines_size_fops); | 6846 | NULL, &tracing_saved_cmdlines_size_fops); |
| 6568 | 6847 | ||
| 6848 | trace_enum_init(); | ||
| 6849 | |||
| 6850 | trace_create_enum_file(d_tracer); | ||
| 6851 | |||
| 6852 | #ifdef CONFIG_MODULES | ||
| 6853 | register_module_notifier(&trace_module_nb); | ||
| 6854 | #endif | ||
| 6855 | |||
| 6569 | #ifdef CONFIG_DYNAMIC_FTRACE | 6856 | #ifdef CONFIG_DYNAMIC_FTRACE |
| 6570 | trace_create_file("dyn_ftrace_total_info", 0444, d_tracer, | 6857 | trace_create_file("dyn_ftrace_total_info", 0444, d_tracer, |
| 6571 | &ftrace_update_tot_cnt, &tracing_dyn_info_fops); | 6858 | &ftrace_update_tot_cnt, &tracing_dyn_info_fops); |
| @@ -6575,6 +6862,10 @@ static __init int tracer_init_debugfs(void) | |||
| 6575 | 6862 | ||
| 6576 | create_trace_options_dir(&global_trace); | 6863 | create_trace_options_dir(&global_trace); |
| 6577 | 6864 | ||
| 6865 | /* If the tracer was started via cmdline, create options for it here */ | ||
| 6866 | if (global_trace.current_trace != &nop_trace) | ||
| 6867 | update_tracer_options(&global_trace, global_trace.current_trace); | ||
| 6868 | |||
| 6578 | return 0; | 6869 | return 0; |
| 6579 | } | 6870 | } |
| 6580 | 6871 | ||
| @@ -6888,7 +7179,7 @@ void __init trace_init(void) | |||
| 6888 | tracepoint_printk = 0; | 7179 | tracepoint_printk = 0; |
| 6889 | } | 7180 | } |
| 6890 | tracer_alloc_buffers(); | 7181 | tracer_alloc_buffers(); |
| 6891 | trace_event_init(); | 7182 | trace_event_init(); |
| 6892 | } | 7183 | } |
| 6893 | 7184 | ||
| 6894 | __init static int clear_boot_tracer(void) | 7185 | __init static int clear_boot_tracer(void) |
| @@ -6910,5 +7201,5 @@ __init static int clear_boot_tracer(void) | |||
| 6910 | return 0; | 7201 | return 0; |
| 6911 | } | 7202 | } |
| 6912 | 7203 | ||
| 6913 | fs_initcall(tracer_init_debugfs); | 7204 | fs_initcall(tracer_init_tracefs); |
| 6914 | late_initcall(clear_boot_tracer); | 7205 | late_initcall(clear_boot_tracer); |
