Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / kernel / trace / trace_events.c
index 4d7e149..29111da 100644 (file)
@@ -147,7 +147,8 @@ int trace_event_raw_init(struct ftrace_event_call *call)
 }
 EXPORT_SYMBOL_GPL(trace_event_raw_init);
 
-int ftrace_event_reg(struct ftrace_event_call *call, enum trace_reg type)
+int ftrace_event_reg(struct ftrace_event_call *call,
+                    enum trace_reg type, void *data)
 {
        switch (type) {
        case TRACE_REG_REGISTER:
@@ -170,6 +171,11 @@ int ftrace_event_reg(struct ftrace_event_call *call, enum trace_reg type)
                                            call->class->perf_probe,
                                            call);
                return 0;
+       case TRACE_REG_PERF_OPEN:
+       case TRACE_REG_PERF_CLOSE:
+       case TRACE_REG_PERF_ADD:
+       case TRACE_REG_PERF_DEL:
+               return 0;
 #endif
        }
        return 0;
@@ -209,7 +215,7 @@ static int ftrace_event_enable_disable(struct ftrace_event_call *call,
                                tracing_stop_cmdline_record();
                                call->flags &= ~TRACE_EVENT_FL_RECORDED_CMD;
                        }
-                       call->class->reg(call, TRACE_REG_UNREGISTER);
+                       call->class->reg(call, TRACE_REG_UNREGISTER, NULL);
                }
                break;
        case 1:
@@ -218,7 +224,7 @@ static int ftrace_event_enable_disable(struct ftrace_event_call *call,
                                tracing_start_cmdline_record();
                                call->flags |= TRACE_EVENT_FL_RECORDED_CMD;
                        }
-                       ret = call->class->reg(call, TRACE_REG_REGISTER);
+                       ret = call->class->reg(call, TRACE_REG_REGISTER, NULL);
                        if (ret) {
                                tracing_stop_cmdline_record();
                                pr_info("event trace: Could not enable event "
@@ -244,6 +250,35 @@ static void ftrace_clear_events(void)
        mutex_unlock(&event_mutex);
 }
 
+static void __put_system(struct event_subsystem *system)
+{
+       struct event_filter *filter = system->filter;
+
+       WARN_ON_ONCE(system->ref_count == 0);
+       if (--system->ref_count)
+               return;
+
+       if (filter) {
+               kfree(filter->filter_string);
+               kfree(filter);
+       }
+       kfree(system->name);
+       kfree(system);
+}
+
+static void __get_system(struct event_subsystem *system)
+{
+       WARN_ON_ONCE(system->ref_count == 0);
+       system->ref_count++;
+}
+
+static void put_system(struct event_subsystem *system)
+{
+       mutex_lock(&event_mutex);
+       __put_system(system);
+       mutex_unlock(&event_mutex);
+}
+
 /*
  * __ftrace_set_clr_event(NULL, NULL, NULL, set) will set/unset all events.
  */
@@ -259,6 +294,9 @@ static int __ftrace_set_clr_event(const char *match, const char *sub,
                if (!call->name || !call->class || !call->class->reg)
                        continue;
 
+               if (call->flags & TRACE_EVENT_FL_IGNORE_ENABLE)
+                       continue;
+
                if (match &&
                    strcmp(match, call->name) != 0 &&
                    strcmp(match, call->class->system) != 0)
@@ -519,7 +557,7 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
                   loff_t *ppos)
 {
        const char set_to_char[4] = { '?', '0', '1', 'X' };
-       const char *system = filp->private_data;
+       struct event_subsystem *system = filp->private_data;
        struct ftrace_event_call *call;
        char buf[2];
        int set = 0;
@@ -530,7 +568,7 @@ system_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
                if (!call->name || !call->class || !call->class->reg)
                        continue;
 
-               if (system && strcmp(call->class->system, system) != 0)
+               if (system && strcmp(call->class->system, system->name) != 0)
                        continue;
 
                /*
@@ -560,7 +598,8 @@ static ssize_t
 system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
                    loff_t *ppos)
 {
-       const char *system = filp->private_data;
+       struct event_subsystem *system = filp->private_data;
+       const char *name = NULL;
        unsigned long val;
        ssize_t ret;
 
@@ -575,7 +614,14 @@ system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
        if (val != 0 && val != 1)
                return -EINVAL;
 
-       ret = __ftrace_set_clr_event(NULL, system, NULL, val);
+       /*
+        * Opening of "enable" adds a ref count to system,
+        * so the name is safe to use.
+        */
+       if (system)
+               name = system->name;
+
+       ret = __ftrace_set_clr_event(NULL, name, NULL, val);
        if (ret)
                goto out;
 
@@ -808,6 +854,52 @@ event_filter_write(struct file *filp, const char __user *ubuf, size_t cnt,
        return cnt;
 }
 
+static LIST_HEAD(event_subsystems);
+
+static int subsystem_open(struct inode *inode, struct file *filp)
+{
+       struct event_subsystem *system = NULL;
+       int ret;
+
+       if (!inode->i_private)
+               goto skip_search;
+
+       /* Make sure the system still exists */
+       mutex_lock(&event_mutex);
+       list_for_each_entry(system, &event_subsystems, list) {
+               if (system == inode->i_private) {
+                       /* Don't open systems with no events */
+                       if (!system->nr_events) {
+                               system = NULL;
+                               break;
+                       }
+                       __get_system(system);
+                       break;
+               }
+       }
+       mutex_unlock(&event_mutex);
+
+       if (system != inode->i_private)
+               return -ENODEV;
+
+ skip_search:
+       ret = tracing_open_generic(inode, filp);
+       if (ret < 0 && system)
+               put_system(system);
+
+       return ret;
+}
+
+static int subsystem_release(struct inode *inode, struct file *file)
+{
+       struct event_subsystem *system = inode->i_private;
+
+       if (system)
+               put_system(system);
+
+       return 0;
+}
+
 static ssize_t
 subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
                      loff_t *ppos)
@@ -945,17 +1037,19 @@ static const struct file_operations ftrace_event_filter_fops = {
 };
 
 static const struct file_operations ftrace_subsystem_filter_fops = {
-       .open = tracing_open_generic,
+       .open = subsystem_open,
        .read = subsystem_filter_read,
        .write = subsystem_filter_write,
        .llseek = default_llseek,
+       .release = subsystem_release,
 };
 
 static const struct file_operations ftrace_system_enable_fops = {
-       .open = tracing_open_generic,
+       .open = subsystem_open,
        .read = system_enable_read,
        .write = system_enable_write,
        .llseek = default_llseek,
+       .release = subsystem_release,
 };
 
 static const struct file_operations ftrace_show_header_fops = {
@@ -984,8 +1078,6 @@ static struct dentry *event_trace_events_dir(void)
        return d_events;
 }
 
-static LIST_HEAD(event_subsystems);
-
 static struct dentry *
 event_subsystem_dir(const char *name, struct dentry *d_events)
 {
@@ -1017,6 +1109,7 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
        }
 
        system->nr_events = 1;
+       system->ref_count = 1;
        system->name = kstrdup(name, GFP_KERNEL);
        if (!system->name) {
                debugfs_remove(system->entry);
@@ -1044,8 +1137,7 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
                           "'%s/filter' entry\n", name);
        }
 
-       trace_create_file("enable", 0644, system->entry,
-                         (void *)system->name,
+       trace_create_file("enable", 0644, system->entry, system,
                          &ftrace_system_enable_fops);
 
        return system->entry;
@@ -1075,7 +1167,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
                return -1;
        }
 
-       if (call->class->reg)
+       if (call->class->reg && !(call->flags & TRACE_EVENT_FL_IGNORE_ENABLE))
                trace_create_file("enable", 0644, call->dir, call,
                                  enable);
 
@@ -1166,16 +1258,9 @@ static void remove_subsystem_dir(const char *name)
        list_for_each_entry(system, &event_subsystems, list) {
                if (strcmp(system->name, name) == 0) {
                        if (!--system->nr_events) {
-                               struct event_filter *filter = system->filter;
-
                                debugfs_remove_recursive(system->entry);
                                list_del(&system->list);
-                               if (filter) {
-                                       kfree(filter->filter_string);
-                                       kfree(filter);
-                               }
-                               kfree(system->name);
-                               kfree(system);
+                               __put_system(system);
                        }
                        break;
                }