modules: de-mutex more symbol lookup paths in the module code
[powerpc.git] / kernel / module.c
index 7734595..c2e3e2e 100644 (file)
@@ -81,7 +81,8 @@ int unregister_module_notifier(struct notifier_block * nb)
 }
 EXPORT_SYMBOL(unregister_module_notifier);
 
-/* We require a truly strong try_module_get() */
+/* We require a truly strong try_module_get(): 0 means failure due to
+   ongoing or failed initialization etc. */
 static inline int strong_try_module_get(struct module *mod)
 {
        if (mod && mod->state == MODULE_STATE_COMING)
@@ -952,7 +953,8 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
        ret = __find_symbol(name, &owner, &crc,
                        !(mod->taints & TAINT_PROPRIETARY_MODULE));
        if (ret) {
-               /* use_module can fail due to OOM, or module unloading */
+               /* use_module can fail due to OOM,
+                  or module initialization or unloading */
                if (!check_version(sechdrs, versindex, name, mod, crc) ||
                    !use_module(mod, owner))
                        ret = 0;
@@ -1369,7 +1371,7 @@ dup:
        return ret;
 }
 
-/* Change all symbols so that sh_value encodes the pointer directly. */
+/* Change all symbols so that st_value encodes the pointer directly. */
 static int simplify_symbols(Elf_Shdr *sechdrs,
                            unsigned int symindex,
                            const char *strtab,
@@ -1673,6 +1675,8 @@ static struct module *load_module(void __user *umod,
        unsigned int unusedcrcindex;
        unsigned int unusedgplindex;
        unsigned int unusedgplcrcindex;
+       unsigned int markersindex;
+       unsigned int markersstringsindex;
        struct module *mod;
        long err = 0;
        void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1939,6 +1943,9 @@ static struct module *load_module(void __user *umod,
                add_taint_module(mod, TAINT_FORCED_MODULE);
        }
 #endif
+       markersindex = find_sec(hdr, sechdrs, secstrings, "__markers");
+       markersstringsindex = find_sec(hdr, sechdrs, secstrings,
+                                       "__markers_strings");
 
        /* Now do relocations. */
        for (i = 1; i < hdr->e_shnum; i++) {
@@ -1961,6 +1968,11 @@ static struct module *load_module(void __user *umod,
                if (err < 0)
                        goto cleanup;
        }
+#ifdef CONFIG_MARKERS
+       mod->markers = (void *)sechdrs[markersindex].sh_addr;
+       mod->num_markers =
+               sechdrs[markersindex].sh_size / sizeof(*mod->markers);
+#endif
 
         /* Find duplicate symbols */
        err = verify_export_symbols(mod);
@@ -1979,6 +1991,11 @@ static struct module *load_module(void __user *umod,
 
        add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
 
+#ifdef CONFIG_MARKERS
+       if (!mod->taints)
+               marker_update_probe_range(mod->markers,
+                       mod->markers + mod->num_markers, NULL, NULL);
+#endif
        err = module_finalize(hdr, sechdrs, mod);
        if (err < 0)
                goto cleanup;
@@ -2197,29 +2214,34 @@ static const char *get_ksymbol(struct module *mod,
 /* For kallsyms to ask for address resolution.  NULL means not found.
    We don't lock, as this is used for oops resolution and races are a
    lesser concern. */
+/* FIXME: Risky: returns a pointer into a module w/o lock */
 const char *module_address_lookup(unsigned long addr,
                                  unsigned long *size,
                                  unsigned long *offset,
                                  char **modname)
 {
        struct module *mod;
+       const char *ret = NULL;
 
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (within(addr, mod->module_init, mod->init_size)
                    || within(addr, mod->module_core, mod->core_size)) {
                        if (modname)
                                *modname = mod->name;
-                       return get_ksymbol(mod, addr, size, offset);
+                       ret = get_ksymbol(mod, addr, size, offset);
+                       break;
                }
        }
-       return NULL;
+       preempt_enable();
+       return ret;
 }
 
 int lookup_module_symbol_name(unsigned long addr, char *symname)
 {
        struct module *mod;
 
-       mutex_lock(&module_mutex);
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (within(addr, mod->module_init, mod->init_size) ||
                    within(addr, mod->module_core, mod->core_size)) {
@@ -2229,12 +2251,12 @@ int lookup_module_symbol_name(unsigned long addr, char *symname)
                        if (!sym)
                                goto out;
                        strlcpy(symname, sym, KSYM_NAME_LEN);
-                       mutex_unlock(&module_mutex);
+                       preempt_enable();
                        return 0;
                }
        }
 out:
-       mutex_unlock(&module_mutex);
+       preempt_enable();
        return -ERANGE;
 }
 
@@ -2243,7 +2265,7 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
 {
        struct module *mod;
 
-       mutex_lock(&module_mutex);
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (within(addr, mod->module_init, mod->init_size) ||
                    within(addr, mod->module_core, mod->core_size)) {
@@ -2256,12 +2278,12 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
                                strlcpy(modname, mod->name, MODULE_NAME_LEN);
                        if (name)
                                strlcpy(name, sym, KSYM_NAME_LEN);
-                       mutex_unlock(&module_mutex);
+                       preempt_enable();
                        return 0;
                }
        }
 out:
-       mutex_unlock(&module_mutex);
+       preempt_enable();
        return -ERANGE;
 }
 
@@ -2270,7 +2292,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
 {
        struct module *mod;
 
-       mutex_lock(&module_mutex);
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (symnum < mod->num_symtab) {
                        *value = mod->symtab[symnum].st_value;
@@ -2279,12 +2301,12 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
                                KSYM_NAME_LEN);
                        strlcpy(module_name, mod->name, MODULE_NAME_LEN);
                        *exported = is_exported(name, mod);
-                       mutex_unlock(&module_mutex);
+                       preempt_enable();
                        return 0;
                }
                symnum -= mod->num_symtab;
        }
-       mutex_unlock(&module_mutex);
+       preempt_enable();
        return -ERANGE;
 }
 
@@ -2307,6 +2329,7 @@ unsigned long module_kallsyms_lookup_name(const char *name)
        unsigned long ret = 0;
 
        /* Don't lock: we're in enough trouble already. */
+       preempt_disable();
        if ((colon = strchr(name, ':')) != NULL) {
                *colon = '\0';
                if ((mod = find_module(name)) != NULL)
@@ -2317,6 +2340,7 @@ unsigned long module_kallsyms_lookup_name(const char *name)
                        if ((ret = mod_find_symname(mod, name)) != 0)
                                break;
        }
+       preempt_enable();
        return ret;
 }
 #endif /* CONFIG_KALLSYMS */
@@ -2570,3 +2594,18 @@ EXPORT_SYMBOL(module_remove_driver);
 void struct_module(struct module *mod) { return; }
 EXPORT_SYMBOL(struct_module);
 #endif
+
+#ifdef CONFIG_MARKERS
+void module_update_markers(struct module *probe_module, int *refcount)
+{
+       struct module *mod;
+
+       mutex_lock(&module_mutex);
+       list_for_each_entry(mod, &modules, list)
+               if (!mod->taints)
+                       marker_update_probe_range(mod->markers,
+                               mod->markers + mod->num_markers,
+                               probe_module, refcount);
+       mutex_unlock(&module_mutex);
+}
+#endif