sched: cache hot buddy
[sfrench/cifs-2.6.git] / kernel / module.c
index bd60278ee7035945d1db4dfaed0f26b3c4a457e8..5d437bffd8dc7a4219fe471eab6a8699ed08e3df 100644 (file)
@@ -46,6 +46,7 @@
 #include <asm/semaphore.h>
 #include <asm/cacheflush.h>
 #include <linux/license.h>
+#include <asm/sections.h>
 
 #if 0
 #define DEBUGP printk
@@ -290,7 +291,7 @@ static unsigned long __find_symbol(const char *name,
                }
        }
        DEBUGP("Failed to find symbol %s\n", name);
-       return 0;
+       return -ENOENT;
 }
 
 /* Search for module by name: must hold module_mutex. */
@@ -343,9 +344,6 @@ static inline unsigned int block_size(int val)
        return val;
 }
 
-/* Created by linker magic */
-extern char __per_cpu_start[], __per_cpu_end[];
-
 static void *percpu_modalloc(unsigned long size, unsigned long align,
                             const char *name)
 {
@@ -783,7 +781,7 @@ void __symbol_put(const char *symbol)
        const unsigned long *crc;
 
        preempt_disable();
-       if (!__find_symbol(symbol, &owner, &crc, 1))
+       if (IS_ERR_VALUE(__find_symbol(symbol, &owner, &crc, 1)))
                BUG();
        module_put(owner);
        preempt_enable();
@@ -929,7 +927,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
        const unsigned long *crc;
        struct module *owner;
 
-       if (!__find_symbol("struct_module", &owner, &crc, 1))
+       if (IS_ERR_VALUE(__find_symbol("struct_module",
+                                               &owner, &crc, 1)))
                BUG();
        return check_version(sechdrs, versindex, "struct_module", mod,
                             crc);
@@ -978,22 +977,21 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
 
        ret = __find_symbol(name, &owner, &crc,
                        !(mod->taints & TAINT_PROPRIETARY_MODULE));
-       if (ret) {
+       if (!IS_ERR_VALUE(ret)) {
                /* 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;
+                       ret = -EINVAL;
        }
        return ret;
 }
 
-
 /*
  * /sys/module/foo/sections stuff
  * J. Corbet <corbet@lwn.net>
  */
-#ifdef CONFIG_KALLSYMS
+#if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS)
 static ssize_t module_sect_show(struct module_attribute *mattr,
                                struct module *mod, char *buf)
 {
@@ -1189,7 +1187,7 @@ static inline void add_notes_attrs(struct module *mod, unsigned int nsect,
 static inline void remove_notes_attrs(struct module *mod)
 {
 }
-#endif /* CONFIG_KALLSYMS */
+#endif
 
 #ifdef CONFIG_SYSFS
 int module_add_modinfo_attrs(struct module *mod)
@@ -1232,9 +1230,7 @@ void module_remove_modinfo_attrs(struct module *mod)
        }
        kfree(mod->modinfo_attrs);
 }
-#endif
 
-#ifdef CONFIG_SYSFS
 int mod_sysfs_init(struct module *mod)
 {
        int err;
@@ -1371,7 +1367,9 @@ void *__symbol_get(const char *symbol)
 
        preempt_disable();
        value = __find_symbol(symbol, &owner, &crc, 1);
-       if (value && strong_try_module_get(owner) != 0)
+       if (IS_ERR_VALUE(value))
+               value = 0;
+       else if (strong_try_module_get(owner))
                value = 0;
        preempt_enable();
 
@@ -1391,14 +1389,16 @@ static int verify_export_symbols(struct module *mod)
        const unsigned long *crc;
 
        for (i = 0; i < mod->num_syms; i++)
-               if (__find_symbol(mod->syms[i].name, &owner, &crc, 1)) {
+               if (!IS_ERR_VALUE(__find_symbol(mod->syms[i].name,
+                                                       &owner, &crc, 1))) {
                        name = mod->syms[i].name;
                        ret = -ENOEXEC;
                        goto dup;
                }
 
        for (i = 0; i < mod->num_gpl_syms; i++)
-               if (__find_symbol(mod->gpl_syms[i].name, &owner, &crc, 1)) {
+               if (!IS_ERR_VALUE(__find_symbol(mod->gpl_syms[i].name,
+                                                       &owner, &crc, 1))) {
                        name = mod->gpl_syms[i].name;
                        ret = -ENOEXEC;
                        goto dup;
@@ -1448,7 +1448,7 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
                                           strtab + sym[i].st_name, mod);
 
                        /* Ok if resolved.  */
-                       if (sym[i].st_value != 0)
+                       if (!IS_ERR_VALUE(sym[i].st_value))
                                break;
                        /* Ok if weak.  */
                        if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
@@ -1933,8 +1933,15 @@ static struct module *load_module(void __user *umod,
        /* Set up license info based on the info section */
        set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
 
+       /*
+        * ndiswrapper is under GPL by itself, but loads proprietary modules.
+        * Don't use add_taint_module(), as it would prevent ndiswrapper from
+        * using GPL-only symbols it needs.
+        */
        if (strcmp(mod->name, "ndiswrapper") == 0)
-               add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
+               add_taint(TAINT_PROPRIETARY_MODULE);
+
+       /* driverloader was caught wrongly pretending to be under GPL */
        if (strcmp(mod->name, "driverloader") == 0)
                add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
 
@@ -2035,7 +2042,7 @@ static struct module *load_module(void __user *umod,
 #ifdef CONFIG_MARKERS
        if (!mod->taints)
                marker_update_probe_range(mod->markers,
-                       mod->markers + mod->num_markers, NULL, NULL);
+                       mod->markers + mod->num_markers);
 #endif
        err = module_finalize(hdr, sechdrs, mod);
        if (err < 0)
@@ -2171,10 +2178,20 @@ sys_init_module(void __user *umod,
                wake_up(&module_wq);
                return ret;
        }
+       if (ret > 0) {
+               printk(KERN_WARNING "%s: '%s'->init suspiciously returned %d, "
+                                   "it should follow 0/-E convention\n"
+                      KERN_WARNING "%s: loading module anyway...\n",
+                      __func__, mod->name, ret,
+                      __func__);
+               dump_stack();
+       }
 
-       /* Now it's a first class citizen! */
-       mutex_lock(&module_mutex);
+       /* Now it's a first class citizen!  Wake up anyone waiting for it. */
        mod->state = MODULE_STATE_LIVE;
+       wake_up(&module_wq);
+
+       mutex_lock(&module_mutex);
        /* Drop initial reference. */
        module_put(mod);
        unwind_remove_table(mod->unwind_info, 1);
@@ -2183,7 +2200,6 @@ sys_init_module(void __user *umod,
        mod->init_size = 0;
        mod->init_text_size = 0;
        mutex_unlock(&module_mutex);
-       wake_up(&module_wq);
 
        return 0;
 }
@@ -2250,7 +2266,7 @@ static const char *get_ksymbol(struct module *mod,
 
 /* For kallsyms to ask for address resolution.  NULL means not found.  Careful
  * not to lock to avoid deadlock on oopses, simply disable preemption. */
-char *module_address_lookup(unsigned long addr,
+const char *module_address_lookup(unsigned long addr,
                            unsigned long *size,
                            unsigned long *offset,
                            char **modname,
@@ -2275,7 +2291,7 @@ char *module_address_lookup(unsigned long addr,
                ret = namebuf;
        }
        preempt_enable();
-       return (char *)ret;
+       return ret;
 }
 
 int lookup_module_symbol_name(unsigned long addr, char *symname)
@@ -2561,7 +2577,7 @@ EXPORT_SYMBOL(struct_module);
 #endif
 
 #ifdef CONFIG_MARKERS
-void module_update_markers(struct module *probe_module, int *refcount)
+void module_update_markers(void)
 {
        struct module *mod;
 
@@ -2569,8 +2585,7 @@ void module_update_markers(struct module *probe_module, int *refcount)
        list_for_each_entry(mod, &modules, list)
                if (!mod->taints)
                        marker_update_probe_range(mod->markers,
-                               mod->markers + mod->num_markers,
-                               probe_module, refcount);
+                               mod->markers + mod->num_markers);
        mutex_unlock(&module_mutex);
 }
 #endif