]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/module.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bart/ide-2.6
[linux-2.6-omap-h63xx.git] / kernel / module.c
index b7205f67cfaf570aa4aee965cae7e953fec65a2f..0d8d21ee792c4e5812694162d241b7975ffd99bf 100644 (file)
@@ -46,6 +46,8 @@
 #include <asm/cacheflush.h>
 #include <linux/license.h>
 #include <asm/sections.h>
+#include <linux/tracepoint.h>
+#include <linux/ftrace.h>
 
 #if 0
 #define DEBUGP printk
@@ -1430,6 +1432,9 @@ static void free_module(struct module *mod)
        /* Module unload stuff */
        module_unload_free(mod);
 
+       /* release any pointers to mcount in this module */
+       ftrace_release(mod->module_core, mod->core_size);
+
        /* This may be NULL, but that's OK */
        module_free(mod, mod->module_init);
        kfree(mod->args);
@@ -1834,6 +1839,7 @@ static noinline struct module *load_module(void __user *umod,
        Elf_Ehdr *hdr;
        Elf_Shdr *sechdrs;
        char *secstrings, *args, *modmagic, *strtab = NULL;
+       char *staging;
        unsigned int i;
        unsigned int symindex = 0;
        unsigned int strindex = 0;
@@ -1860,9 +1866,13 @@ static noinline struct module *load_module(void __user *umod,
        unsigned int markersindex;
        unsigned int markersstringsindex;
        unsigned int verboseindex;
+       unsigned int tracepointsindex;
+       unsigned int tracepointsstringsindex;
+       unsigned int mcountindex;
        struct module *mod;
        long err = 0;
        void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
+       void *mseg;
        struct exception_table_entry *extable;
        mm_segment_t old_fs;
 
@@ -1989,6 +1999,14 @@ static noinline struct module *load_module(void __user *umod,
                goto free_hdr;
        }
 
+       staging = get_modinfo(sechdrs, infoindex, "staging");
+       if (staging) {
+               add_taint_module(mod, TAINT_CRAP);
+               printk(KERN_WARNING "%s: module is from the staging directory,"
+                      " the quality is unknown, you have been warned.\n",
+                      mod->name);
+       }
+
        /* Now copy in args */
        args = strndup_user(uargs, ~0UL >> 1);
        if (IS_ERR(args)) {
@@ -2147,6 +2165,12 @@ static noinline struct module *load_module(void __user *umod,
        markersstringsindex = find_sec(hdr, sechdrs, secstrings,
                                        "__markers_strings");
        verboseindex = find_sec(hdr, sechdrs, secstrings, "__verbose");
+       tracepointsindex = find_sec(hdr, sechdrs, secstrings, "__tracepoints");
+       tracepointsstringsindex = find_sec(hdr, sechdrs, secstrings,
+                                       "__tracepoints_strings");
+
+       mcountindex = find_sec(hdr, sechdrs, secstrings,
+                              "__mcount_loc");
 
        /* Now do relocations. */
        for (i = 1; i < hdr->e_shnum; i++) {
@@ -2174,6 +2198,12 @@ static noinline struct module *load_module(void __user *umod,
        mod->num_markers =
                sechdrs[markersindex].sh_size / sizeof(*mod->markers);
 #endif
+#ifdef CONFIG_TRACEPOINTS
+       mod->tracepoints = (void *)sechdrs[tracepointsindex].sh_addr;
+       mod->num_tracepoints =
+               sechdrs[tracepointsindex].sh_size / sizeof(*mod->tracepoints);
+#endif
+
 
         /* Find duplicate symbols */
        err = verify_export_symbols(mod);
@@ -2192,12 +2222,22 @@ static noinline struct module *load_module(void __user *umod,
 
        add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
 
+       if (!mod->taints) {
 #ifdef CONFIG_MARKERS
-       if (!mod->taints)
                marker_update_probe_range(mod->markers,
                        mod->markers + mod->num_markers);
 #endif
        dynamic_printk_setup(sechdrs, verboseindex);
+#ifdef CONFIG_TRACEPOINTS
+               tracepoint_update_probe_range(mod->tracepoints,
+                       mod->tracepoints + mod->num_tracepoints);
+#endif
+       }
+
+       /* sechdrs[0].sh_size is always zero */
+       mseg = (void *)sechdrs[mcountindex].sh_addr;
+       ftrace_init_module(mseg, mseg + sechdrs[mcountindex].sh_size);
+
        err = module_finalize(hdr, sechdrs, mod);
        if (err < 0)
                goto cleanup;
@@ -2267,6 +2307,7 @@ static noinline struct module *load_module(void __user *umod,
  cleanup:
        kobject_del(&mod->mkobj.kobj);
        kobject_put(&mod->mkobj.kobj);
+       ftrace_release(mod->module_core, mod->core_size);
  free_unload:
        module_unload_free(mod);
        module_free(mod, mod->module_init);
@@ -2587,6 +2628,8 @@ static char *module_flags(struct module *mod, char *buf)
                        buf[bx++] = 'P';
                if (mod->taints & (1 << TAINT_FORCED_MODULE))
                        buf[bx++] = 'F';
+               if (mod->taints & (1 << TAINT_CRAP))
+                       buf[bx++] = 'C';
                /*
                 * TAINT_FORCED_RMMOD: could be added.
                 * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
@@ -2748,3 +2791,50 @@ void module_update_markers(void)
        mutex_unlock(&module_mutex);
 }
 #endif
+
+#ifdef CONFIG_TRACEPOINTS
+void module_update_tracepoints(void)
+{
+       struct module *mod;
+
+       mutex_lock(&module_mutex);
+       list_for_each_entry(mod, &modules, list)
+               if (!mod->taints)
+                       tracepoint_update_probe_range(mod->tracepoints,
+                               mod->tracepoints + mod->num_tracepoints);
+       mutex_unlock(&module_mutex);
+}
+
+/*
+ * Returns 0 if current not found.
+ * Returns 1 if current found.
+ */
+int module_get_iter_tracepoints(struct tracepoint_iter *iter)
+{
+       struct module *iter_mod;
+       int found = 0;
+
+       mutex_lock(&module_mutex);
+       list_for_each_entry(iter_mod, &modules, list) {
+               if (!iter_mod->taints) {
+                       /*
+                        * Sorted module list
+                        */
+                       if (iter_mod < iter->module)
+                               continue;
+                       else if (iter_mod > iter->module)
+                               iter->tracepoint = NULL;
+                       found = tracepoint_get_iter_range(&iter->tracepoint,
+                               iter_mod->tracepoints,
+                               iter_mod->tracepoints
+                                       + iter_mod->num_tracepoints);
+                       if (found) {
+                               iter->module = iter_mod;
+                               break;
+                       }
+               }
+       }
+       mutex_unlock(&module_mutex);
+       return found;
+}
+#endif