Merge git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild
[pandora-kernel.git] / kernel / module.c
index ddfe45a..10e5b87 100644 (file)
 #include <linux/string.h>
 #include <linux/sched.h>
 #include <linux/mutex.h>
+#include <linux/unwind.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 #include <asm/cacheflush.h>
+#include <linux/license.h>
 
 #if 0
 #define DEBUGP printk
@@ -64,26 +66,17 @@ static DEFINE_SPINLOCK(modlist_lock);
 static DEFINE_MUTEX(module_mutex);
 static LIST_HEAD(modules);
 
-static DEFINE_MUTEX(notify_mutex);
-static struct notifier_block * module_notify_list;
+static BLOCKING_NOTIFIER_HEAD(module_notify_list);
 
 int register_module_notifier(struct notifier_block * nb)
 {
-       int err;
-       mutex_lock(&notify_mutex);
-       err = notifier_chain_register(&module_notify_list, nb);
-       mutex_unlock(&notify_mutex);
-       return err;
+       return blocking_notifier_chain_register(&module_notify_list, nb);
 }
 EXPORT_SYMBOL(register_module_notifier);
 
 int unregister_module_notifier(struct notifier_block * nb)
 {
-       int err;
-       mutex_lock(&notify_mutex);
-       err = notifier_chain_unregister(&module_notify_list, nb);
-       mutex_unlock(&notify_mutex);
-       return err;
+       return blocking_notifier_chain_unregister(&module_notify_list, nb);
 }
 EXPORT_SYMBOL(unregister_module_notifier);
 
@@ -136,7 +129,7 @@ extern const unsigned long __start___kcrctab_gpl_future[];
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
 #else
-#define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL)
+#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
 #endif
 
 /* lookup symbol in given range of kernel_symbols */
@@ -714,14 +707,14 @@ EXPORT_SYMBOL(__symbol_put);
 
 void symbol_put_addr(void *addr)
 {
-       unsigned long flags;
+       struct module *modaddr;
 
-       spin_lock_irqsave(&modlist_lock, flags);
-       if (!kernel_text_address((unsigned long)addr))
-               BUG();
+       if (core_kernel_text((unsigned long)addr))
+               return;
 
-       module_put(module_text_address((unsigned long)addr));
-       spin_unlock_irqrestore(&modlist_lock, flags);
+       if (!(modaddr = module_text_address((unsigned long)addr)))
+               BUG();
+       module_put(modaddr);
 }
 EXPORT_SYMBOL_GPL(symbol_put_addr);
 
@@ -1060,6 +1053,8 @@ static void free_module(struct module *mod)
        remove_sect_attrs(mod);
        mod_kobject_remove(mod);
 
+       unwind_remove_table(mod->unwind_info, 0);
+
        /* Arch-specific cleanup. */
        module_arch_cleanup(mod);
 
@@ -1257,15 +1252,6 @@ static void layout_sections(struct module *mod,
        }
 }
 
-static inline int license_is_gpl_compatible(const char *license)
-{
-       return (strcmp(license, "GPL") == 0
-               || strcmp(license, "GPL v2") == 0
-               || strcmp(license, "GPL and additional rights") == 0
-               || strcmp(license, "Dual BSD/GPL") == 0
-               || strcmp(license, "Dual MPL/GPL") == 0);
-}
-
 static void set_license(struct module *mod, const char *license)
 {
        if (!license)
@@ -1334,7 +1320,7 @@ int is_exported(const char *name, const struct module *mod)
        if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
                return 1;
        else
-               if (lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
+               if (mod && lookup_symbol(name, mod->syms, mod->syms + mod->num_syms))
                        return 1;
                else
                        return 0;
@@ -1420,7 +1406,7 @@ static struct module *load_module(void __user *umod,
        unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
                exportindex, modindex, obsparmindex, infoindex, gplindex,
                crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
-               gplfuturecrcindex;
+               gplfuturecrcindex, unwindex = 0;
        struct module *mod;
        long err = 0;
        void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1510,6 +1496,9 @@ static struct module *load_module(void __user *umod,
        versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
        infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");
        pcpuindex = find_pcpusec(hdr, sechdrs, secstrings);
+#ifdef ARCH_UNWIND_SECTION_NAME
+       unwindex = find_sec(hdr, sechdrs, secstrings, ARCH_UNWIND_SECTION_NAME);
+#endif
 
        /* Don't keep modinfo section */
        sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
@@ -1518,6 +1507,8 @@ static struct module *load_module(void __user *umod,
        sechdrs[symindex].sh_flags |= SHF_ALLOC;
        sechdrs[strindex].sh_flags |= SHF_ALLOC;
 #endif
+       if (unwindex)
+               sechdrs[unwindex].sh_flags |= SHF_ALLOC;
 
        /* Check module struct version now, before we try to use module. */
        if (!check_modstruct_version(sechdrs, versindex, mod)) {
@@ -1746,6 +1737,11 @@ static struct module *load_module(void __user *umod,
                goto arch_cleanup;
        add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
 
+       /* Size of section 0 is 0, so this works well if no unwind info. */
+       mod->unwind_info = unwind_add_table(mod,
+                                           (void *)sechdrs[unwindex].sh_addr,
+                                           sechdrs[unwindex].sh_size);
+
        /* Get rid of temporary copy */
        vfree(hdr);
 
@@ -1816,9 +1812,8 @@ sys_init_module(void __user *umod,
        /* Drop lock so they can recurse */
        mutex_unlock(&module_mutex);
 
-       mutex_lock(&notify_mutex);
-       notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod);
-       mutex_unlock(&notify_mutex);
+       blocking_notifier_call_chain(&module_notify_list,
+                       MODULE_STATE_COMING, mod);
 
        /* Start the module */
        if (mod->init != NULL)
@@ -1845,6 +1840,7 @@ sys_init_module(void __user *umod,
        mod->state = MODULE_STATE_LIVE;
        /* Drop initial reference. */
        module_put(mod);
+       unwind_remove_table(mod->unwind_info, 1);
        module_free(mod, mod->module_init);
        mod->module_init = NULL;
        mod->init_size = 0;