tracing/filter: Remove empty subsystem and its directory
Xiao Guangrong [Thu, 9 Jul 2009 08:22:22 +0000 (16:22 +0800)]
Remove empty subsystem and its directory when module unload.

Before patch:
 # rmmod trace-events-sample.ko
 # ls sample
 enable  filter

After patch:
 # rmmod trace-events-sample.ko
 # ls sample
 ls: cannot access sample: No such file or directory

Signed-off-by: Xiao Guangrong <xiaoguangrong@cn.fujitsu.com>
Acked-by: Tom Zanussi <tzanussi@gmail.com>
Reviewed-by: Li Zefan <lizf@cn.fujitsu.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
LKML-Reference: <4A55A8BE.9010707@cn.fujitsu.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

kernel/trace/trace.h
kernel/trace/trace_events.c

index 52eb0d8..94305c7 100644 (file)
@@ -757,6 +757,7 @@ struct event_subsystem {
        const char              *name;
        struct dentry           *entry;
        void                    *filter;
+       int                     nr_events;
 };
 
 struct filter_pred;
index fecac13..90cf936 100644 (file)
@@ -851,8 +851,10 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
 
        /* First see if we did not already create this dir */
        list_for_each_entry(system, &event_subsystems, list) {
-               if (strcmp(system->name, name) == 0)
+               if (strcmp(system->name, name) == 0) {
+                       system->nr_events++;
                        return system->entry;
+               }
        }
 
        /* need to create new entry */
@@ -871,6 +873,7 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
                return d_events;
        }
 
+       system->nr_events = 1;
        system->name = kstrdup(name, GFP_KERNEL);
        if (!system->name) {
                debugfs_remove(system->entry);
@@ -905,6 +908,32 @@ event_subsystem_dir(const char *name, struct dentry *d_events)
        return system->entry;
 }
 
+static void remove_subsystem_dir(const char *name)
+{
+       struct event_subsystem *system;
+
+       if (strcmp(name, TRACE_SYSTEM) == 0)
+               return;
+
+       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);
+                       }
+                       break;
+               }
+       }
+}
+
 static int
 event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
                 const struct file_operations *id,
@@ -1079,6 +1108,7 @@ static void trace_module_remove_events(struct module *mod)
                        list_del(&call->list);
                        trace_destroy_fields(call);
                        destroy_preds(call);
+                       remove_subsystem_dir(call->system);
                }
        }