[MIPS] make mips_nmi_setup() static
[safe/jmp/linux-2.6] / kernel / module.c
index 2a892b2..8d6cccc 100644 (file)
@@ -1,4 +1,4 @@
-/* Rewritten by Rusty Russell, on the backs of many others...
+/*
    Copyright (C) 2002 Richard Henderson
    Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
 
    Copyright (C) 2002 Richard Henderson
    Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.
 
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/moduleloader.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/moduleloader.h>
 #include <linux/init.h>
+#include <linux/kallsyms.h>
+#include <linux/sysfs.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/err.h>
 #include <linux/vermagic.h>
 #include <linux/notifier.h>
 #include <linux/err.h>
 #include <linux/vermagic.h>
 #include <linux/notifier.h>
+#include <linux/sched.h>
 #include <linux/stop_machine.h>
 #include <linux/device.h>
 #include <linux/string.h>
 #include <linux/stop_machine.h>
 #include <linux/device.h>
 #include <linux/string.h>
-#include <linux/sched.h>
+#include <linux/mutex.h>
+#include <linux/unwind.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
-#include <asm/semaphore.h>
 #include <asm/cacheflush.h>
 #include <asm/cacheflush.h>
+#include <linux/license.h>
+#include <asm/sections.h>
 
 #if 0
 #define DEBUGP printk
 
 #if 0
 #define DEBUGP printk
 /* If this is set, the section belongs in the init part of the module */
 #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
 
 /* If this is set, the section belongs in the init part of the module */
 #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
 
-/* Protects module list */
-static DEFINE_SPINLOCK(modlist_lock);
-
-/* List of modules, protected by module_mutex AND modlist_lock */
-static DECLARE_MUTEX(module_mutex);
+/* List of modules, protected by module_mutex or preempt_disable
+ * (add/delete uses stop_machine). */
+static DEFINE_MUTEX(module_mutex);
 static LIST_HEAD(modules);
 
 static LIST_HEAD(modules);
 
-static DECLARE_MUTEX(notify_mutex);
-static struct notifier_block * module_notify_list;
+/* Waiting for a module to finish initializing? */
+static DECLARE_WAIT_QUEUE_HEAD(module_wq);
+
+static BLOCKING_NOTIFIER_HEAD(module_notify_list);
 
 int register_module_notifier(struct notifier_block * nb)
 {
 
 int register_module_notifier(struct notifier_block * nb)
 {
-       int err;
-       down(&notify_mutex);
-       err = notifier_chain_register(&module_notify_list, nb);
-       up(&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)
 {
 }
 EXPORT_SYMBOL(register_module_notifier);
 
 int unregister_module_notifier(struct notifier_block * nb)
 {
-       int err;
-       down(&notify_mutex);
-       err = notifier_chain_unregister(&module_notify_list, nb);
-       up(&notify_mutex);
-       return err;
+       return blocking_notifier_chain_unregister(&module_notify_list, nb);
 }
 EXPORT_SYMBOL(unregister_module_notifier);
 
 }
 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)
 static inline int strong_try_module_get(struct module *mod)
 {
        if (mod && mod->state == MODULE_STATE_COMING)
+               return -EBUSY;
+       if (try_module_get(mod))
                return 0;
                return 0;
-       return try_module_get(mod);
+       else
+               return -ENOENT;
+}
+
+static inline void add_taint_module(struct module *mod, unsigned flag)
+{
+       add_taint(flag);
+       mod->taints |= flag;
 }
 
 }
 
-/* A thread that wants to hold a reference to a module only while it
- * is running can call ths to safely exit.
- * nfsd and lockd use this.
+/*
+ * A thread that wants to hold a reference to a module only while it
+ * is running can call this to safely exit.  nfsd and lockd use this.
  */
 void __module_put_and_exit(struct module *mod, long code)
 {
  */
 void __module_put_and_exit(struct module *mod, long code)
 {
@@ -104,7 +110,7 @@ void __module_put_and_exit(struct module *mod, long code)
        do_exit(code);
 }
 EXPORT_SYMBOL(__module_put_and_exit);
        do_exit(code);
 }
 EXPORT_SYMBOL(__module_put_and_exit);
-       
+
 /* Find a module section: 0 means not found. */
 static unsigned int find_sec(Elf_Ehdr *hdr,
                             Elf_Shdr *sechdrs,
 /* Find a module section: 0 means not found. */
 static unsigned int find_sec(Elf_Ehdr *hdr,
                             Elf_Shdr *sechdrs,
@@ -126,13 +132,24 @@ extern const struct kernel_symbol __start___ksymtab[];
 extern const struct kernel_symbol __stop___ksymtab[];
 extern const struct kernel_symbol __start___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab[];
 extern const struct kernel_symbol __start___ksymtab_gpl[];
 extern const struct kernel_symbol __stop___ksymtab_gpl[];
+extern const struct kernel_symbol __start___ksymtab_gpl_future[];
+extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
+extern const struct kernel_symbol __start___ksymtab_unused[];
+extern const struct kernel_symbol __stop___ksymtab_unused[];
+extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
+extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
+extern const struct kernel_symbol __start___ksymtab_gpl_future[];
+extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
 extern const unsigned long __start___kcrctab[];
 extern const unsigned long __start___kcrctab_gpl[];
 extern const unsigned long __start___kcrctab[];
 extern const unsigned long __start___kcrctab_gpl[];
+extern const unsigned long __start___kcrctab_gpl_future[];
+extern const unsigned long __start___kcrctab_unused[];
+extern const unsigned long __start___kcrctab_unused_gpl[];
 
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
 #else
 
 #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 */
 #endif
 
 /* lookup symbol in given range of kernel_symbols */
@@ -147,6 +164,17 @@ static const struct kernel_symbol *lookup_symbol(const char *name,
        return NULL;
 }
 
        return NULL;
 }
 
+static void printk_unused_warning(const char *name)
+{
+       printk(KERN_WARNING "Symbol %s is marked as UNUSED, "
+               "however this module is using it.\n", name);
+       printk(KERN_WARNING "This symbol will go away in the future.\n");
+       printk(KERN_WARNING "Please evalute if this is the right api to use, "
+               "and if it really is, submit a report the linux kernel "
+               "mailinglist together with submitting your code for "
+               "inclusion.\n");
+}
+
 /* Find a symbol, return value, crc and module which owns it */
 static unsigned long __find_symbol(const char *name,
                                   struct module **owner,
 /* Find a symbol, return value, crc and module which owns it */
 static unsigned long __find_symbol(const char *name,
                                   struct module **owner,
@@ -156,7 +184,7 @@ static unsigned long __find_symbol(const char *name,
        struct module *mod;
        const struct kernel_symbol *ks;
 
        struct module *mod;
        const struct kernel_symbol *ks;
 
-       /* Core kernel first. */ 
+       /* Core kernel first. */
        *owner = NULL;
        ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
        if (ks) {
        *owner = NULL;
        ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);
        if (ks) {
@@ -172,8 +200,43 @@ static unsigned long __find_symbol(const char *name,
                        return ks->value;
                }
        }
                        return ks->value;
                }
        }
+       ks = lookup_symbol(name, __start___ksymtab_gpl_future,
+                                __stop___ksymtab_gpl_future);
+       if (ks) {
+               if (!gplok) {
+                       printk(KERN_WARNING "Symbol %s is being used "
+                              "by a non-GPL module, which will not "
+                              "be allowed in the future\n", name);
+                       printk(KERN_WARNING "Please see the file "
+                              "Documentation/feature-removal-schedule.txt "
+                              "in the kernel source tree for more "
+                              "details.\n");
+               }
+               *crc = symversion(__start___kcrctab_gpl_future,
+                                 (ks - __start___ksymtab_gpl_future));
+               return ks->value;
+       }
 
 
-       /* Now try modules. */ 
+       ks = lookup_symbol(name, __start___ksymtab_unused,
+                                __stop___ksymtab_unused);
+       if (ks) {
+               printk_unused_warning(name);
+               *crc = symversion(__start___kcrctab_unused,
+                                 (ks - __start___ksymtab_unused));
+               return ks->value;
+       }
+
+       if (gplok)
+               ks = lookup_symbol(name, __start___ksymtab_unused_gpl,
+                                __stop___ksymtab_unused_gpl);
+       if (ks) {
+               printk_unused_warning(name);
+               *crc = symversion(__start___kcrctab_unused_gpl,
+                                 (ks - __start___ksymtab_unused_gpl));
+               return ks->value;
+       }
+
+       /* Now try modules. */
        list_for_each_entry(mod, &modules, list) {
                *owner = mod;
                ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
        list_for_each_entry(mod, &modules, list) {
                *owner = mod;
                ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
@@ -191,27 +254,43 @@ static unsigned long __find_symbol(const char *name,
                                return ks->value;
                        }
                }
                                return ks->value;
                        }
                }
-       }
-       DEBUGP("Failed to find symbol %s\n", name);
-       return 0;
-}
-
-/* Find a symbol in this elf symbol table */
-static unsigned long find_local_symbol(Elf_Shdr *sechdrs,
-                                      unsigned int symindex,
-                                      const char *strtab,
-                                      const char *name)
-{
-       unsigned int i;
-       Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
+               ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms);
+               if (ks) {
+                       printk_unused_warning(name);
+                       *crc = symversion(mod->unused_crcs, (ks - mod->unused_syms));
+                       return ks->value;
+               }
 
 
-       /* Search (defined) internal symbols first. */
-       for (i = 1; i < sechdrs[symindex].sh_size/sizeof(*sym); i++) {
-               if (sym[i].st_shndx != SHN_UNDEF
-                   && strcmp(name, strtab + sym[i].st_name) == 0)
-                       return sym[i].st_value;
+               if (gplok) {
+                       ks = lookup_symbol(name, mod->unused_gpl_syms,
+                                          mod->unused_gpl_syms + mod->num_unused_gpl_syms);
+                       if (ks) {
+                               printk_unused_warning(name);
+                               *crc = symversion(mod->unused_gpl_crcs,
+                                                 (ks - mod->unused_gpl_syms));
+                               return ks->value;
+                       }
+               }
+               ks = lookup_symbol(name, mod->gpl_future_syms,
+                                  (mod->gpl_future_syms +
+                                   mod->num_gpl_future_syms));
+               if (ks) {
+                       if (!gplok) {
+                               printk(KERN_WARNING "Symbol %s is being used "
+                                      "by a non-GPL module, which will not "
+                                      "be allowed in the future\n", name);
+                               printk(KERN_WARNING "Please see the file "
+                                      "Documentation/feature-removal-schedule.txt "
+                                      "in the kernel source tree for more "
+                                      "details.\n");
+                       }
+                       *crc = symversion(mod->gpl_future_crcs,
+                                         (ks - mod->gpl_future_syms));
+                       return ks->value;
+               }
        }
        }
-       return 0;
+       DEBUGP("Failed to find symbol %s\n", name);
+       return -ENOENT;
 }
 
 /* Search for module by name: must hold module_mutex. */
 }
 
 /* Search for module by name: must hold module_mutex. */
@@ -236,14 +315,14 @@ static int split_block(unsigned int i, unsigned short size)
 {
        /* Reallocation required? */
        if (pcpu_num_used + 1 > pcpu_num_allocated) {
 {
        /* Reallocation required? */
        if (pcpu_num_used + 1 > pcpu_num_allocated) {
-               int *new = kmalloc(sizeof(new[0]) * pcpu_num_allocated*2,
-                                  GFP_KERNEL);
+               int *new;
+
+               new = krealloc(pcpu_size, sizeof(new[0])*pcpu_num_allocated*2,
+                              GFP_KERNEL);
                if (!new)
                        return 0;
 
                if (!new)
                        return 0;
 
-               memcpy(new, pcpu_size, sizeof(new[0])*pcpu_num_allocated);
                pcpu_num_allocated *= 2;
                pcpu_num_allocated *= 2;
-               kfree(pcpu_size);
                pcpu_size = new;
        }
 
                pcpu_size = new;
        }
 
@@ -264,9 +343,6 @@ static inline unsigned int block_size(int val)
        return 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)
 {
 static void *percpu_modalloc(unsigned long size, unsigned long align,
                             const char *name)
 {
@@ -274,10 +350,10 @@ static void *percpu_modalloc(unsigned long size, unsigned long align,
        unsigned int i;
        void *ptr;
 
        unsigned int i;
        void *ptr;
 
-       if (align > SMP_CACHE_BYTES) {
-               printk(KERN_WARNING "%s: per-cpu alignment %li > %i\n",
-                      name, align, SMP_CACHE_BYTES);
-               align = SMP_CACHE_BYTES;
+       if (align > PAGE_SIZE) {
+               printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n",
+                      name, align, PAGE_SIZE);
+               align = PAGE_SIZE;
        }
 
        ptr = __per_cpu_start;
        }
 
        ptr = __per_cpu_start;
@@ -351,6 +427,14 @@ static unsigned int find_pcpusec(Elf_Ehdr *hdr,
        return find_sec(hdr, sechdrs, secstrings, ".data.percpu");
 }
 
        return find_sec(hdr, sechdrs, secstrings, ".data.percpu");
 }
 
+static void percpu_modcopy(void *pcpudest, const void *from, unsigned long size)
+{
+       int cpu;
+
+       for_each_possible_cpu(cpu)
+               memcpy(pcpudest + per_cpu_offset(cpu), from, size);
+}
+
 static int percpu_modinit(void)
 {
        pcpu_num_used = 2;
 static int percpu_modinit(void)
 {
        pcpu_num_used = 2;
@@ -358,7 +442,7 @@ static int percpu_modinit(void)
        pcpu_size = kmalloc(sizeof(pcpu_size[0]) * pcpu_num_allocated,
                            GFP_KERNEL);
        /* Static in-kernel percpu data (used). */
        pcpu_size = kmalloc(sizeof(pcpu_size[0]) * pcpu_num_allocated,
                            GFP_KERNEL);
        /* Static in-kernel percpu data (used). */
-       pcpu_size[0] = -ALIGN(__per_cpu_end-__per_cpu_start, SMP_CACHE_BYTES);
+       pcpu_size[0] = -(__per_cpu_end-__per_cpu_start);
        /* Free room. */
        pcpu_size[1] = PERCPU_ENOUGH_ROOM + pcpu_size[0];
        if (pcpu_size[1] < 0) {
        /* Free room. */
        pcpu_size[1] = PERCPU_ENOUGH_ROOM + pcpu_size[0];
        if (pcpu_size[1] < 0) {
@@ -367,7 +451,7 @@ static int percpu_modinit(void)
        }
 
        return 0;
        }
 
        return 0;
-}      
+}
 __initcall(percpu_modinit);
 #else /* ... !CONFIG_SMP */
 static inline void *percpu_modalloc(unsigned long size, unsigned long align,
 __initcall(percpu_modinit);
 #else /* ... !CONFIG_SMP */
 static inline void *percpu_modalloc(unsigned long size, unsigned long align,
@@ -393,7 +477,6 @@ static inline void percpu_modcopy(void *pcpudst, const void *src,
 }
 #endif /* CONFIG_SMP */
 
 }
 #endif /* CONFIG_SMP */
 
-#ifdef CONFIG_MODULE_UNLOAD
 #define MODINFO_ATTR(field)    \
 static void setup_modinfo_##field(struct module *mod, const char *s)  \
 {                                                                     \
 #define MODINFO_ATTR(field)    \
 static void setup_modinfo_##field(struct module *mod, const char *s)  \
 {                                                                     \
@@ -410,12 +493,11 @@ static int modinfo_##field##_exists(struct module *mod)               \
 }                                                                     \
 static void free_modinfo_##field(struct module *mod)                  \
 {                                                                     \
 }                                                                     \
 static void free_modinfo_##field(struct module *mod)                  \
 {                                                                     \
-        kfree(mod->field);                                            \
-        mod->field = NULL;                                            \
+       kfree(mod->field);                                            \
+       mod->field = NULL;                                            \
 }                                                                     \
 static struct module_attribute modinfo_##field = {                    \
 }                                                                     \
 static struct module_attribute modinfo_##field = {                    \
-       .attr = { .name = __stringify(field), .mode = 0444,           \
-                 .owner = THIS_MODULE },                             \
+       .attr = { .name = __stringify(field), .mode = 0444 },         \
        .show = show_modinfo_##field,                                 \
        .setup = setup_modinfo_##field,                               \
        .test = modinfo_##field##_exists,                             \
        .show = show_modinfo_##field,                                 \
        .setup = setup_modinfo_##field,                               \
        .test = modinfo_##field##_exists,                             \
@@ -425,12 +507,9 @@ static struct module_attribute modinfo_##field = {                    \
 MODINFO_ATTR(version);
 MODINFO_ATTR(srcversion);
 
 MODINFO_ATTR(version);
 MODINFO_ATTR(srcversion);
 
-static struct module_attribute *modinfo_attrs[] = {
-       &modinfo_version,
-       &modinfo_srcversion,
-       NULL,
-};
+static char last_unloaded_module[MODULE_NAME_LEN+1];
 
 
+#ifdef CONFIG_MODULE_UNLOAD
 /* Init the unload section of the module. */
 static void module_unload_init(struct module *mod)
 {
 /* Init the unload section of the module. */
 static void module_unload_init(struct module *mod)
 {
@@ -471,9 +550,21 @@ static int already_uses(struct module *a, struct module *b)
 static int use_module(struct module *a, struct module *b)
 {
        struct module_use *use;
 static int use_module(struct module *a, struct module *b)
 {
        struct module_use *use;
+       int no_warn, err;
+
        if (b == NULL || already_uses(a, b)) return 1;
 
        if (b == NULL || already_uses(a, b)) return 1;
 
-       if (!strong_try_module_get(b))
+       /* If we're interrupted or time out, we fail. */
+       if (wait_event_interruptible_timeout(
+                   module_wq, (err = strong_try_module_get(b)) != -EBUSY,
+                   30 * HZ) <= 0) {
+               printk("%s: gave up waiting for init of module %s.\n",
+                      a->name, b->name);
+               return 0;
+       }
+
+       /* If strong_try_module_get() returned a different error, we fail. */
+       if (err)
                return 0;
 
        DEBUGP("Allocating new usage for %s.\n", a->name);
                return 0;
 
        DEBUGP("Allocating new usage for %s.\n", a->name);
@@ -486,6 +577,7 @@ static int use_module(struct module *a, struct module *b)
 
        use->module_which_uses = a;
        list_add(&use->list, &b->modules_which_use_me);
 
        use->module_which_uses = a;
        list_add(&use->list, &b->modules_which_use_me);
+       no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name);
        return 1;
 }
 
        return 1;
 }
 
@@ -503,6 +595,7 @@ static void module_unload_free(struct module *mod)
                                module_put(i);
                                list_del(&use->list);
                                kfree(use);
                                module_put(i);
                                list_del(&use->list);
                                kfree(use);
+                               sysfs_remove_link(i->holders_dir, mod->name);
                                /* There can be at most one match. */
                                break;
                        }
                                /* There can be at most one match. */
                                break;
                        }
@@ -570,8 +663,8 @@ static void free_module(struct module *mod);
 
 static void wait_for_zero_refcount(struct module *mod)
 {
 
 static void wait_for_zero_refcount(struct module *mod)
 {
-       /* Since we might sleep for some time, drop the semaphore first */
-       up(&module_mutex);
+       /* Since we might sleep for some time, release the mutex first */
+       mutex_unlock(&module_mutex);
        for (;;) {
                DEBUGP("Looking at refcount...\n");
                set_current_state(TASK_UNINTERRUPTIBLE);
        for (;;) {
                DEBUGP("Looking at refcount...\n");
                set_current_state(TASK_UNINTERRUPTIBLE);
@@ -580,7 +673,7 @@ static void wait_for_zero_refcount(struct module *mod)
                schedule();
        }
        current->state = TASK_RUNNING;
                schedule();
        }
        current->state = TASK_RUNNING;
-       down(&module_mutex);
+       mutex_lock(&module_mutex);
 }
 
 asmlinkage long
 }
 
 asmlinkage long
@@ -597,7 +690,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
                return -EFAULT;
        name[MODULE_NAME_LEN-1] = '\0';
 
                return -EFAULT;
        name[MODULE_NAME_LEN-1] = '\0';
 
-       if (down_interruptible(&module_mutex) != 0)
+       if (mutex_lock_interruptible(&module_mutex) != 0)
                return -EINTR;
 
        mod = find_module(name);
                return -EINTR;
 
        mod = find_module(name);
@@ -622,8 +715,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
        }
 
        /* If it has an init func, it must have an exit func to unload */
        }
 
        /* If it has an init func, it must have an exit func to unload */
-       if ((mod->init != NULL && mod->exit == NULL)
-           || mod->unsafe) {
+       if (mod->init && !mod->exit) {
                forced = try_force_unload(flags);
                if (!forced) {
                        /* This module can't be removed */
                forced = try_force_unload(flags);
                if (!forced) {
                        /* This module can't be removed */
@@ -646,14 +738,16 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
 
        /* Final destruction now noone is using it. */
        if (mod->exit != NULL) {
 
        /* Final destruction now noone is using it. */
        if (mod->exit != NULL) {
-               up(&module_mutex);
+               mutex_unlock(&module_mutex);
                mod->exit();
                mod->exit();
-               down(&module_mutex);
+               mutex_lock(&module_mutex);
        }
        }
+       /* Store the name of the last unloaded module for diagnostic purposes */
+       strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
        free_module(mod);
 
  out:
        free_module(mod);
 
  out:
-       up(&module_mutex);
+       mutex_unlock(&module_mutex);
        return ret;
 }
 
        return ret;
 }
 
@@ -671,11 +765,6 @@ static void print_unload_info(struct seq_file *m, struct module *mod)
                seq_printf(m, "%s,", use->module_which_uses->name);
        }
 
                seq_printf(m, "%s,", use->module_which_uses->name);
        }
 
-       if (mod->unsafe) {
-               printed_something = 1;
-               seq_printf(m, "[unsafe],");
-       }
-
        if (mod->init != NULL && mod->exit == NULL) {
                printed_something = 1;
                seq_printf(m, "[permanent],");
        if (mod->init != NULL && mod->exit == NULL) {
                printed_something = 1;
                seq_printf(m, "[permanent],");
@@ -688,42 +777,53 @@ static void print_unload_info(struct seq_file *m, struct module *mod)
 void __symbol_put(const char *symbol)
 {
        struct module *owner;
 void __symbol_put(const char *symbol)
 {
        struct module *owner;
-       unsigned long flags;
        const unsigned long *crc;
 
        const unsigned long *crc;
 
-       spin_lock_irqsave(&modlist_lock, flags);
-       if (!__find_symbol(symbol, &owner, &crc, 1))
+       preempt_disable();
+       if (IS_ERR_VALUE(__find_symbol(symbol, &owner, &crc, 1)))
                BUG();
        module_put(owner);
                BUG();
        module_put(owner);
-       spin_unlock_irqrestore(&modlist_lock, flags);
+       preempt_enable();
 }
 EXPORT_SYMBOL(__symbol_put);
 
 void symbol_put_addr(void *addr)
 {
 }
 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);
 
 static ssize_t show_refcnt(struct module_attribute *mattr,
                           struct module *mod, char *buffer)
 {
 }
 EXPORT_SYMBOL_GPL(symbol_put_addr);
 
 static ssize_t show_refcnt(struct module_attribute *mattr,
                           struct module *mod, char *buffer)
 {
-       /* sysfs holds a reference */
-       return sprintf(buffer, "%u\n", module_refcount(mod)-1);
+       return sprintf(buffer, "%u\n", module_refcount(mod));
 }
 
 static struct module_attribute refcnt = {
 }
 
 static struct module_attribute refcnt = {
-       .attr = { .name = "refcnt", .mode = 0444, .owner = THIS_MODULE },
+       .attr = { .name = "refcnt", .mode = 0444 },
        .show = show_refcnt,
 };
 
        .show = show_refcnt,
 };
 
+void module_put(struct module *module)
+{
+       if (module) {
+               unsigned int cpu = get_cpu();
+               local_dec(&module->ref[cpu].count);
+               /* Maybe they're waiting for us to drop reference? */
+               if (unlikely(!module_is_live(module)))
+                       wake_up_process(module->waiter);
+               put_cpu();
+       }
+}
+EXPORT_SYMBOL(module_put);
+
 #else /* !CONFIG_MODULE_UNLOAD */
 static void print_unload_info(struct seq_file *m, struct module *mod)
 {
 #else /* !CONFIG_MODULE_UNLOAD */
 static void print_unload_info(struct seq_file *m, struct module *mod)
 {
@@ -737,7 +837,7 @@ static inline void module_unload_free(struct module *mod)
 
 static inline int use_module(struct module *a, struct module *b)
 {
 
 static inline int use_module(struct module *a, struct module *b)
 {
-       return strong_try_module_get(b);
+       return strong_try_module_get(b) == 0;
 }
 
 static inline void module_unload_init(struct module *mod)
 }
 
 static inline void module_unload_init(struct module *mod)
@@ -745,138 +845,39 @@ static inline void module_unload_init(struct module *mod)
 }
 #endif /* CONFIG_MODULE_UNLOAD */
 
 }
 #endif /* CONFIG_MODULE_UNLOAD */
 
-#ifdef CONFIG_OBSOLETE_MODPARM
-/* Bounds checking done below */
-static int obsparm_copy_string(const char *val, struct kernel_param *kp)
+static ssize_t show_initstate(struct module_attribute *mattr,
+                          struct module *mod, char *buffer)
 {
 {
-       strcpy(kp->arg, val);
-       return 0;
-}
-
-static int set_obsolete(const char *val, struct kernel_param *kp)
-{
-       unsigned int min, max;
-       unsigned int size, maxsize;
-       int dummy;
-       char *endp;
-       const char *p;
-       struct obsolete_modparm *obsparm = kp->arg;
-
-       if (!val) {
-               printk(KERN_ERR "Parameter %s needs an argument\n", kp->name);
-               return -EINVAL;
-       }
-
-       /* type is: [min[-max]]{b,h,i,l,s} */
-       p = obsparm->type;
-       min = simple_strtol(p, &endp, 10);
-       if (endp == obsparm->type)
-               min = max = 1;
-       else if (*endp == '-') {
-               p = endp+1;
-               max = simple_strtol(p, &endp, 10);
-       } else
-               max = min;
-       switch (*endp) {
-       case 'b':
-               return param_array(kp->name, val, min, max, obsparm->addr,
-                                  1, param_set_byte, &dummy);
-       case 'h':
-               return param_array(kp->name, val, min, max, obsparm->addr,
-                                  sizeof(short), param_set_short, &dummy);
-       case 'i':
-               return param_array(kp->name, val, min, max, obsparm->addr,
-                                  sizeof(int), param_set_int, &dummy);
-       case 'l':
-               return param_array(kp->name, val, min, max, obsparm->addr,
-                                  sizeof(long), param_set_long, &dummy);
-       case 's':
-               return param_array(kp->name, val, min, max, obsparm->addr,
-                                  sizeof(char *), param_set_charp, &dummy);
-
-       case 'c':
-               /* Undocumented: 1-5c50 means 1-5 strings of up to 49 chars,
-                  and the decl is "char xxx[5][50];" */
-               p = endp+1;
-               maxsize = simple_strtol(p, &endp, 10);
-               /* We check lengths here (yes, this is a hack). */
-               p = val;
-               while (p[size = strcspn(p, ",")]) {
-                       if (size >= maxsize) 
-                               goto oversize;
-                       p += size+1;
-               }
-               if (size >= maxsize) 
-                       goto oversize;
-               return param_array(kp->name, val, min, max, obsparm->addr,
-                                  maxsize, obsparm_copy_string, &dummy);
-       }
-       printk(KERN_ERR "Unknown obsolete parameter type %s\n", obsparm->type);
-       return -EINVAL;
- oversize:
-       printk(KERN_ERR
-              "Parameter %s doesn't fit in %u chars.\n", kp->name, maxsize);
-       return -EINVAL;
-}
-
-static int obsolete_params(const char *name,
-                          char *args,
-                          struct obsolete_modparm obsparm[],
-                          unsigned int num,
-                          Elf_Shdr *sechdrs,
-                          unsigned int symindex,
-                          const char *strtab)
-{
-       struct kernel_param *kp;
-       unsigned int i;
-       int ret;
-
-       kp = kmalloc(sizeof(kp[0]) * num, GFP_KERNEL);
-       if (!kp)
-               return -ENOMEM;
+       const char *state = "unknown";
 
 
-       for (i = 0; i < num; i++) {
-               char sym_name[128 + sizeof(MODULE_SYMBOL_PREFIX)];
-
-               snprintf(sym_name, sizeof(sym_name), "%s%s",
-                        MODULE_SYMBOL_PREFIX, obsparm[i].name);
-
-               kp[i].name = obsparm[i].name;
-               kp[i].perm = 000;
-               kp[i].set = set_obsolete;
-               kp[i].get = NULL;
-               obsparm[i].addr
-                       = (void *)find_local_symbol(sechdrs, symindex, strtab,
-                                                   sym_name);
-               if (!obsparm[i].addr) {
-                       printk("%s: falsely claims to have parameter %s\n",
-                              name, obsparm[i].name);
-                       ret = -EINVAL;
-                       goto out;
-               }
-               kp[i].arg = &obsparm[i];
+       switch (mod->state) {
+       case MODULE_STATE_LIVE:
+               state = "live";
+               break;
+       case MODULE_STATE_COMING:
+               state = "coming";
+               break;
+       case MODULE_STATE_GOING:
+               state = "going";
+               break;
        }
        }
-
-       ret = parse_args(name, args, kp, num, NULL);
- out:
-       kfree(kp);
-       return ret;
+       return sprintf(buffer, "%s\n", state);
 }
 }
-#else
-static int obsolete_params(const char *name,
-                          char *args,
-                          struct obsolete_modparm obsparm[],
-                          unsigned int num,
-                          Elf_Shdr *sechdrs,
-                          unsigned int symindex,
-                          const char *strtab)
-{
-       if (num != 0)
-               printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
-                      name);
-       return 0;
-}
-#endif /* CONFIG_OBSOLETE_MODPARM */
+
+static struct module_attribute initstate = {
+       .attr = { .name = "initstate", .mode = 0444 },
+       .show = show_initstate,
+};
+
+static struct module_attribute *modinfo_attrs[] = {
+       &modinfo_version,
+       &modinfo_srcversion,
+       &initstate,
+#ifdef CONFIG_MODULE_UNLOAD
+       &refcnt,
+#endif
+       NULL,
+};
 
 static const char vermagic[] = VERMAGIC_STRING;
 
 
 static const char vermagic[] = VERMAGIC_STRING;
 
@@ -911,11 +912,10 @@ static int check_version(Elf_Shdr *sechdrs,
                return 0;
        }
        /* Not in module's version table.  OK, but that taints the kernel. */
                return 0;
        }
        /* Not in module's version table.  OK, but that taints the kernel. */
-       if (!(tainted & TAINT_FORCED_MODULE)) {
+       if (!(tainted & TAINT_FORCED_MODULE))
                printk("%s: no version for \"%s\" found: kernel tainted.\n",
                       mod->name, symname);
                printk("%s: no version for \"%s\" found: kernel tainted.\n",
                       mod->name, symname);
-               add_taint(TAINT_FORCED_MODULE);
-       }
+       add_taint_module(mod, TAINT_FORCED_MODULE);
        return 1;
 }
 
        return 1;
 }
 
@@ -926,7 +926,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
        const unsigned long *crc;
        struct module *owner;
 
        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);
                BUG();
        return check_version(sechdrs, versindex, "struct_module", mod,
                             crc);
@@ -973,22 +974,23 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
        unsigned long ret;
        const unsigned long *crc;
 
        unsigned long ret;
        const unsigned long *crc;
 
-       ret = __find_symbol(name, &owner, &crc, mod->license_gplok);
-       if (ret) {
-               /* use_module can fail due to OOM, or module unloading */
+       ret = __find_symbol(name, &owner, &crc,
+                       !(mod->taints & TAINT_PROPRIETARY_MODULE));
+       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))
                if (!check_version(sechdrs, versindex, name, mod, crc) ||
                    !use_module(mod, owner))
-                       ret = 0;
+                       ret = -EINVAL;
        }
        return ret;
 }
 
        }
        return ret;
 }
 
-
 /*
  * /sys/module/foo/sections stuff
  * J. Corbet <corbet@lwn.net>
  */
 /*
  * /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)
 {
 static ssize_t module_sect_show(struct module_attribute *mattr,
                                struct module *mod, char *buf)
 {
@@ -997,6 +999,15 @@ static ssize_t module_sect_show(struct module_attribute *mattr,
        return sprintf(buf, "0x%lx\n", sattr->address);
 }
 
        return sprintf(buf, "0x%lx\n", sattr->address);
 }
 
+static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
+{
+       int section;
+
+       for (section = 0; section < sect_attrs->nsections; section++)
+               kfree(sect_attrs->attrs[section].name);
+       kfree(sect_attrs);
+}
+
 static void add_sect_attrs(struct module *mod, unsigned int nsect,
                char *secstrings, Elf_Shdr *sechdrs)
 {
 static void add_sect_attrs(struct module *mod, unsigned int nsect,
                char *secstrings, Elf_Shdr *sechdrs)
 {
@@ -1004,7 +1015,7 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
        struct module_sect_attrs *sect_attrs;
        struct module_sect_attr *sattr;
        struct attribute **gattr;
        struct module_sect_attrs *sect_attrs;
        struct module_sect_attr *sattr;
        struct attribute **gattr;
-       
+
        /* Count loaded sections and allocate structures */
        for (i = 0; i < nsect; i++)
                if (sechdrs[i].sh_flags & SHF_ALLOC)
        /* Count loaded sections and allocate structures */
        for (i = 0; i < nsect; i++)
                if (sechdrs[i].sh_flags & SHF_ALLOC)
@@ -1013,25 +1024,29 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
                        + nloaded * sizeof(sect_attrs->attrs[0]),
                        sizeof(sect_attrs->grp.attrs[0]));
        size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.attrs[0]);
                        + nloaded * sizeof(sect_attrs->attrs[0]),
                        sizeof(sect_attrs->grp.attrs[0]));
        size[1] = (nloaded + 1) * sizeof(sect_attrs->grp.attrs[0]);
-       if (! (sect_attrs = kmalloc(size[0] + size[1], GFP_KERNEL)))
+       sect_attrs = kzalloc(size[0] + size[1], GFP_KERNEL);
+       if (sect_attrs == NULL)
                return;
 
        /* Setup section attributes. */
        sect_attrs->grp.name = "sections";
        sect_attrs->grp.attrs = (void *)sect_attrs + size[0];
 
                return;
 
        /* Setup section attributes. */
        sect_attrs->grp.name = "sections";
        sect_attrs->grp.attrs = (void *)sect_attrs + size[0];
 
+       sect_attrs->nsections = 0;
        sattr = &sect_attrs->attrs[0];
        gattr = &sect_attrs->grp.attrs[0];
        for (i = 0; i < nsect; i++) {
                if (! (sechdrs[i].sh_flags & SHF_ALLOC))
                        continue;
                sattr->address = sechdrs[i].sh_addr;
        sattr = &sect_attrs->attrs[0];
        gattr = &sect_attrs->grp.attrs[0];
        for (i = 0; i < nsect; i++) {
                if (! (sechdrs[i].sh_flags & SHF_ALLOC))
                        continue;
                sattr->address = sechdrs[i].sh_addr;
-               strlcpy(sattr->name, secstrings + sechdrs[i].sh_name,
-                       MODULE_SECT_NAME_LEN);
+               sattr->name = kstrdup(secstrings + sechdrs[i].sh_name,
+                                       GFP_KERNEL);
+               if (sattr->name == NULL)
+                       goto out;
+               sect_attrs->nsections++;
                sattr->mattr.show = module_sect_show;
                sattr->mattr.store = NULL;
                sattr->mattr.attr.name = sattr->name;
                sattr->mattr.show = module_sect_show;
                sattr->mattr.store = NULL;
                sattr->mattr.attr.name = sattr->name;
-               sattr->mattr.attr.owner = mod;
                sattr->mattr.attr.mode = S_IRUGO;
                *(gattr++) = &(sattr++)->mattr.attr;
        }
                sattr->mattr.attr.mode = S_IRUGO;
                *(gattr++) = &(sattr++)->mattr.attr;
        }
@@ -1043,7 +1058,7 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
        mod->sect_attrs = sect_attrs;
        return;
   out:
        mod->sect_attrs = sect_attrs;
        return;
   out:
-       kfree(sect_attrs);
+       free_sect_attrs(sect_attrs);
 }
 
 static void remove_sect_attrs(struct module *mod)
 }
 
 static void remove_sect_attrs(struct module *mod)
@@ -1053,117 +1068,253 @@ static void remove_sect_attrs(struct module *mod)
                                   &mod->sect_attrs->grp);
                /* We are positive that no one is using any sect attrs
                 * at this point.  Deallocate immediately. */
                                   &mod->sect_attrs->grp);
                /* We are positive that no one is using any sect attrs
                 * at this point.  Deallocate immediately. */
-               kfree(mod->sect_attrs);
+               free_sect_attrs(mod->sect_attrs);
                mod->sect_attrs = NULL;
        }
 }
 
                mod->sect_attrs = NULL;
        }
 }
 
+/*
+ * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
+ */
 
 
-#else
-static inline void add_sect_attrs(struct module *mod, unsigned int nsect,
-               char *sectstrings, Elf_Shdr *sechdrs)
+struct module_notes_attrs {
+       struct kobject *dir;
+       unsigned int notes;
+       struct bin_attribute attrs[0];
+};
+
+static ssize_t module_notes_read(struct kobject *kobj,
+                                struct bin_attribute *bin_attr,
+                                char *buf, loff_t pos, size_t count)
 {
 {
+       /*
+        * The caller checked the pos and count against our size.
+        */
+       memcpy(buf, bin_attr->private + pos, count);
+       return count;
 }
 
 }
 
-static inline void remove_sect_attrs(struct module *mod)
+static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
+                            unsigned int i)
+{
+       if (notes_attrs->dir) {
+               while (i-- > 0)
+                       sysfs_remove_bin_file(notes_attrs->dir,
+                                             &notes_attrs->attrs[i]);
+               kobject_del(notes_attrs->dir);
+       }
+       kfree(notes_attrs);
+}
+
+static void add_notes_attrs(struct module *mod, unsigned int nsect,
+                           char *secstrings, Elf_Shdr *sechdrs)
+{
+       unsigned int notes, loaded, i;
+       struct module_notes_attrs *notes_attrs;
+       struct bin_attribute *nattr;
+
+       /* Count notes sections and allocate structures.  */
+       notes = 0;
+       for (i = 0; i < nsect; i++)
+               if ((sechdrs[i].sh_flags & SHF_ALLOC) &&
+                   (sechdrs[i].sh_type == SHT_NOTE))
+                       ++notes;
+
+       if (notes == 0)
+               return;
+
+       notes_attrs = kzalloc(sizeof(*notes_attrs)
+                             + notes * sizeof(notes_attrs->attrs[0]),
+                             GFP_KERNEL);
+       if (notes_attrs == NULL)
+               return;
+
+       notes_attrs->notes = notes;
+       nattr = &notes_attrs->attrs[0];
+       for (loaded = i = 0; i < nsect; ++i) {
+               if (!(sechdrs[i].sh_flags & SHF_ALLOC))
+                       continue;
+               if (sechdrs[i].sh_type == SHT_NOTE) {
+                       nattr->attr.name = mod->sect_attrs->attrs[loaded].name;
+                       nattr->attr.mode = S_IRUGO;
+                       nattr->size = sechdrs[i].sh_size;
+                       nattr->private = (void *) sechdrs[i].sh_addr;
+                       nattr->read = module_notes_read;
+                       ++nattr;
+               }
+               ++loaded;
+       }
+
+       notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj);
+       if (!notes_attrs->dir)
+               goto out;
+
+       for (i = 0; i < notes; ++i)
+               if (sysfs_create_bin_file(notes_attrs->dir,
+                                         &notes_attrs->attrs[i]))
+                       goto out;
+
+       mod->notes_attrs = notes_attrs;
+       return;
+
+  out:
+       free_notes_attrs(notes_attrs, i);
+}
+
+static void remove_notes_attrs(struct module *mod)
 {
 {
+       if (mod->notes_attrs)
+               free_notes_attrs(mod->notes_attrs, mod->notes_attrs->notes);
 }
 }
-#endif /* CONFIG_KALLSYMS */
 
 
+#else
 
 
-#ifdef CONFIG_MODULE_UNLOAD
-static inline int module_add_refcnt_attr(struct module *mod)
+static inline void add_sect_attrs(struct module *mod, unsigned int nsect,
+               char *sectstrings, Elf_Shdr *sechdrs)
 {
 {
-       return sysfs_create_file(&mod->mkobj.kobj, &refcnt.attr);
 }
 }
-static void module_remove_refcnt_attr(struct module *mod)
+
+static inline void remove_sect_attrs(struct module *mod)
 {
 {
-       return sysfs_remove_file(&mod->mkobj.kobj, &refcnt.attr);
 }
 }
-#else
-static inline int module_add_refcnt_attr(struct module *mod)
+
+static inline void add_notes_attrs(struct module *mod, unsigned int nsect,
+                                  char *sectstrings, Elf_Shdr *sechdrs)
 {
 {
-       return 0;
 }
 }
-static void module_remove_refcnt_attr(struct module *mod)
+
+static inline void remove_notes_attrs(struct module *mod)
 {
 }
 #endif
 
 {
 }
 #endif
 
-#ifdef CONFIG_MODULE_UNLOAD
-static int module_add_modinfo_attrs(struct module *mod)
+#ifdef CONFIG_SYSFS
+int module_add_modinfo_attrs(struct module *mod)
 {
        struct module_attribute *attr;
 {
        struct module_attribute *attr;
+       struct module_attribute *temp_attr;
        int error = 0;
        int i;
 
        int error = 0;
        int i;
 
+       mod->modinfo_attrs = kzalloc((sizeof(struct module_attribute) *
+                                       (ARRAY_SIZE(modinfo_attrs) + 1)),
+                                       GFP_KERNEL);
+       if (!mod->modinfo_attrs)
+               return -ENOMEM;
+
+       temp_attr = mod->modinfo_attrs;
        for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
                if (!attr->test ||
        for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
                if (!attr->test ||
-                   (attr->test && attr->test(mod)))
-                       error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr);
+                   (attr->test && attr->test(mod))) {
+                       memcpy(temp_attr, attr, sizeof(*temp_attr));
+                       error = sysfs_create_file(&mod->mkobj.kobj,&temp_attr->attr);
+                       ++temp_attr;
+               }
        }
        return error;
 }
 
        }
        return error;
 }
 
-static void module_remove_modinfo_attrs(struct module *mod)
+void module_remove_modinfo_attrs(struct module *mod)
 {
        struct module_attribute *attr;
        int i;
 
 {
        struct module_attribute *attr;
        int i;
 
-       for (i = 0; (attr = modinfo_attrs[i]); i++) {
+       for (i = 0; (attr = &mod->modinfo_attrs[i]); i++) {
+               /* pick a field to test for end of list */
+               if (!attr->attr.name)
+                       break;
                sysfs_remove_file(&mod->mkobj.kobj,&attr->attr);
                sysfs_remove_file(&mod->mkobj.kobj,&attr->attr);
-               attr->free(mod);
+               if (attr->free)
+                       attr->free(mod);
        }
        }
+       kfree(mod->modinfo_attrs);
 }
 }
-#endif
 
 
-static int mod_sysfs_setup(struct module *mod,
-                          struct kernel_param *kparam,
-                          unsigned int num_params)
+int mod_sysfs_init(struct module *mod)
 {
        int err;
 {
        int err;
+       struct kobject *kobj;
 
 
-       memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
-       err = kobject_set_name(&mod->mkobj.kobj, "%s", mod->name);
-       if (err)
+       if (!module_sysfs_initialized) {
+               printk(KERN_ERR "%s: module sysfs not initialized\n",
+                      mod->name);
+               err = -EINVAL;
                goto out;
                goto out;
-       kobj_set_kset_s(&mod->mkobj, module_subsys);
-       mod->mkobj.mod = mod;
-       err = kobject_register(&mod->mkobj.kobj);
-       if (err)
+       }
+
+       kobj = kset_find_obj(module_kset, mod->name);
+       if (kobj) {
+               printk(KERN_ERR "%s: module is already loaded\n", mod->name);
+               kobject_put(kobj);
+               err = -EINVAL;
                goto out;
                goto out;
+       }
+
+       mod->mkobj.mod = mod;
 
 
-       err = module_add_refcnt_attr(mod);
+       memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj));
+       mod->mkobj.kobj.kset = module_kset;
+       err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL,
+                                  "%s", mod->name);
        if (err)
        if (err)
+               kobject_put(&mod->mkobj.kobj);
+
+       /* delay uevent until full sysfs population */
+out:
+       return err;
+}
+
+int mod_sysfs_setup(struct module *mod,
+                          struct kernel_param *kparam,
+                          unsigned int num_params)
+{
+       int err;
+
+       mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
+       if (!mod->holders_dir) {
+               err = -ENOMEM;
                goto out_unreg;
                goto out_unreg;
+       }
 
        err = module_param_sysfs_setup(mod, kparam, num_params);
        if (err)
 
        err = module_param_sysfs_setup(mod, kparam, num_params);
        if (err)
-               goto out_unreg;
+               goto out_unreg_holders;
 
 
-#ifdef CONFIG_MODULE_UNLOAD
        err = module_add_modinfo_attrs(mod);
        if (err)
        err = module_add_modinfo_attrs(mod);
        if (err)
-               goto out_unreg;
-#endif
+               goto out_unreg_param;
 
 
+       kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);
        return 0;
 
        return 0;
 
+out_unreg_param:
+       module_param_sysfs_remove(mod);
+out_unreg_holders:
+       kobject_put(mod->holders_dir);
 out_unreg:
 out_unreg:
-       kobject_unregister(&mod->mkobj.kobj);
-out:
+       kobject_put(&mod->mkobj.kobj);
        return err;
 }
        return err;
 }
+#endif
 
 static void mod_kobject_remove(struct module *mod)
 {
 
 static void mod_kobject_remove(struct module *mod)
 {
-#ifdef CONFIG_MODULE_UNLOAD
        module_remove_modinfo_attrs(mod);
        module_remove_modinfo_attrs(mod);
-#endif
-       module_remove_refcnt_attr(mod);
        module_param_sysfs_remove(mod);
        module_param_sysfs_remove(mod);
+       kobject_put(mod->mkobj.drivers_dir);
+       kobject_put(mod->holders_dir);
+       kobject_put(&mod->mkobj.kobj);
+}
 
 
-       kobject_unregister(&mod->mkobj.kobj);
+/*
+ * link the module with the whole machine is stopped with interrupts off
+ * - this defends against kallsyms not taking locks
+ */
+static int __link_module(void *_mod)
+{
+       struct module *mod = _mod;
+       list_add(&mod->list, &modules);
+       return 0;
 }
 
 /*
 }
 
 /*
@@ -1177,14 +1328,17 @@ static int __unlink_module(void *_mod)
        return 0;
 }
 
        return 0;
 }
 
-/* Free a module, remove from lists, etc (must hold module mutex). */
+/* Free a module, remove from lists, etc (must hold module_mutex). */
 static void free_module(struct module *mod)
 {
        /* Delete from various lists */
        stop_machine_run(__unlink_module, mod, NR_CPUS);
 static void free_module(struct module *mod)
 {
        /* Delete from various lists */
        stop_machine_run(__unlink_module, mod, NR_CPUS);
+       remove_notes_attrs(mod);
        remove_sect_attrs(mod);
        mod_kobject_remove(mod);
 
        remove_sect_attrs(mod);
        mod_kobject_remove(mod);
 
+       unwind_remove_table(mod->unwind_info, 0);
+
        /* Arch-specific cleanup. */
        module_arch_cleanup(mod);
 
        /* Arch-specific cleanup. */
        module_arch_cleanup(mod);
 
@@ -1197,6 +1351,9 @@ static void free_module(struct module *mod)
        if (mod->percpu)
                percpu_modfree(mod->percpu);
 
        if (mod->percpu)
                percpu_modfree(mod->percpu);
 
+       /* Free lock-classes: */
+       lockdep_free_key_range(mod->module_core, mod->core_size);
+
        /* Finally, free the core (containing the module structure) */
        module_free(mod, mod->module_core);
 }
        /* Finally, free the core (containing the module structure) */
        module_free(mod, mod->module_core);
 }
@@ -1204,14 +1361,16 @@ static void free_module(struct module *mod)
 void *__symbol_get(const char *symbol)
 {
        struct module *owner;
 void *__symbol_get(const char *symbol)
 {
        struct module *owner;
-       unsigned long value, flags;
+       unsigned long value;
        const unsigned long *crc;
 
        const unsigned long *crc;
 
-       spin_lock_irqsave(&modlist_lock, flags);
+       preempt_disable();
        value = __find_symbol(symbol, &owner, &crc, 1);
        value = __find_symbol(symbol, &owner, &crc, 1);
-       if (value && !strong_try_module_get(owner))
+       if (IS_ERR_VALUE(value))
+               value = 0;
+       else if (strong_try_module_get(owner))
                value = 0;
                value = 0;
-       spin_unlock_irqrestore(&modlist_lock, flags);
+       preempt_enable();
 
        return (void *)value;
 }
 
        return (void *)value;
 }
@@ -1219,7 +1378,7 @@ EXPORT_SYMBOL_GPL(__symbol_get);
 
 /*
  * Ensure that an exported symbol [global namespace] does not already exist
 
 /*
  * Ensure that an exported symbol [global namespace] does not already exist
- * in the Kernel or in some other modules exported symbol table.
+ * in the kernel or in some other module's exported symbol table.
  */
 static int verify_export_symbols(struct module *mod)
 {
  */
 static int verify_export_symbols(struct module *mod)
 {
@@ -1229,14 +1388,16 @@ static int verify_export_symbols(struct module *mod)
        const unsigned long *crc;
 
        for (i = 0; i < mod->num_syms; i++)
        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++)
                        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;
                        name = mod->gpl_syms[i].name;
                        ret = -ENOEXEC;
                        goto dup;
@@ -1250,7 +1411,7 @@ dup:
        return ret;
 }
 
        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,
 static int simplify_symbols(Elf_Shdr *sechdrs,
                            unsigned int symindex,
                            const char *strtab,
@@ -1286,7 +1447,7 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
                                           strtab + sym[i].st_name, mod);
 
                        /* Ok if resolved.  */
                                           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)
                                break;
                        /* Ok if weak.  */
                        if (ELF_ST_BIND(sym[i].st_info) == STB_WEAK)
@@ -1382,25 +1543,16 @@ 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)
                license = "unspecified";
 
 static void set_license(struct module *mod, const char *license)
 {
        if (!license)
                license = "unspecified";
 
-       mod->license_gplok = license_is_gpl_compatible(license);
-       if (!mod->license_gplok && !(tainted & TAINT_PROPRIETARY_MODULE)) {
-               printk(KERN_WARNING "%s: module license '%s' taints kernel.\n",
-                      mod->name, license);
-               add_taint(TAINT_PROPRIETARY_MODULE);
+       if (!license_is_gpl_compatible(license)) {
+               if (!(tainted & TAINT_PROPRIETARY_MODULE))
+                       printk(KERN_WARNING "%s: module license '%s' taints "
+                               "kernel.\n", mod->name, license);
+               add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
        }
 }
 
        }
 }
 
@@ -1438,7 +1590,6 @@ static char *get_modinfo(Elf_Shdr *sechdrs,
        return NULL;
 }
 
        return NULL;
 }
 
-#ifdef CONFIG_MODULE_UNLOAD
 static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
                          unsigned int infoindex)
 {
 static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
                          unsigned int infoindex)
 {
@@ -1453,15 +1604,14 @@ static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
                                                attr->attr.name));
        }
 }
                                                attr->attr.name));
        }
 }
-#endif
 
 #ifdef CONFIG_KALLSYMS
 
 #ifdef CONFIG_KALLSYMS
-int is_exported(const char *name, const struct module *mod)
+static int is_exported(const char *name, const struct module *mod)
 {
        if (!mod && lookup_symbol(name, __start___ksymtab, __stop___ksymtab))
                return 1;
        else
 {
        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;
                        return 1;
                else
                        return 0;
@@ -1544,10 +1694,29 @@ static struct module *load_module(void __user *umod,
        Elf_Ehdr *hdr;
        Elf_Shdr *sechdrs;
        char *secstrings, *args, *modmagic, *strtab = NULL;
        Elf_Ehdr *hdr;
        Elf_Shdr *sechdrs;
        char *secstrings, *args, *modmagic, *strtab = NULL;
-       unsigned int i, symindex = 0, strindex = 0, setupindex, exindex,
-               exportindex, modindex, obsparmindex, infoindex, gplindex,
-               crcindex, gplcrcindex, versindex, pcpuindex;
-       long arglen;
+       unsigned int i;
+       unsigned int symindex = 0;
+       unsigned int strindex = 0;
+       unsigned int setupindex;
+       unsigned int exindex;
+       unsigned int exportindex;
+       unsigned int modindex;
+       unsigned int obsparmindex;
+       unsigned int infoindex;
+       unsigned int gplindex;
+       unsigned int crcindex;
+       unsigned int gplcrcindex;
+       unsigned int versindex;
+       unsigned int pcpuindex;
+       unsigned int gplfutureindex;
+       unsigned int gplfuturecrcindex;
+       unsigned int unwindex = 0;
+       unsigned int unusedindex;
+       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 */
        struct module *mod;
        long err = 0;
        void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1627,14 +1796,23 @@ static struct module *load_module(void __user *umod,
        /* Optional sections */
        exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
        gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
        /* Optional sections */
        exportindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab");
        gplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl");
+       gplfutureindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_gpl_future");
+       unusedindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused");
+       unusedgplindex = find_sec(hdr, sechdrs, secstrings, "__ksymtab_unused_gpl");
        crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
        gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
        crcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab");
        gplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl");
+       gplfuturecrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_gpl_future");
+       unusedcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused");
+       unusedgplcrcindex = find_sec(hdr, sechdrs, secstrings, "__kcrctab_unused_gpl");
        setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
        exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
        obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
        versindex = find_sec(hdr, sechdrs, secstrings, "__versions");
        infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo");
        pcpuindex = find_pcpusec(hdr, sechdrs, secstrings);
        setupindex = find_sec(hdr, sechdrs, secstrings, "__param");
        exindex = find_sec(hdr, sechdrs, secstrings, "__ex_table");
        obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm");
        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;
 
        /* Don't keep modinfo section */
        sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
@@ -1643,6 +1821,8 @@ static struct module *load_module(void __user *umod,
        sechdrs[symindex].sh_flags |= SHF_ALLOC;
        sechdrs[strindex].sh_flags |= SHF_ALLOC;
 #endif
        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)) {
 
        /* Check module struct version now, before we try to use module. */
        if (!check_modstruct_version(sechdrs, versindex, mod)) {
@@ -1653,7 +1833,7 @@ static struct module *load_module(void __user *umod,
        modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
        /* This is allowed: modprobe --force will invalidate it. */
        if (!modmagic) {
        modmagic = get_modinfo(sechdrs, infoindex, "vermagic");
        /* This is allowed: modprobe --force will invalidate it. */
        if (!modmagic) {
-               add_taint(TAINT_FORCED_MODULE);
+               add_taint_module(mod, TAINT_FORCED_MODULE);
                printk(KERN_WARNING "%s: no version magic, tainting kernel.\n",
                       mod->name);
        } else if (!same_magic(modmagic, vermagic)) {
                printk(KERN_WARNING "%s: no version magic, tainting kernel.\n",
                       mod->name);
        } else if (!same_magic(modmagic, vermagic)) {
@@ -1664,23 +1844,11 @@ static struct module *load_module(void __user *umod,
        }
 
        /* Now copy in args */
        }
 
        /* Now copy in args */
-       arglen = strlen_user(uargs);
-       if (!arglen) {
-               err = -EFAULT;
+       args = strndup_user(uargs, ~0UL >> 1);
+       if (IS_ERR(args)) {
+               err = PTR_ERR(args);
                goto free_hdr;
        }
                goto free_hdr;
        }
-       args = kmalloc(arglen, GFP_KERNEL);
-       if (!args) {
-               err = -ENOMEM;
-               goto free_hdr;
-       }
-       if (copy_from_user(args, uargs, arglen) != 0) {
-               err = -EFAULT;
-               goto free_mod;
-       }
-
-       /* Userspace could have altered the string after the strlen_user() */
-       args[arglen - 1] = '\0';
 
        if (find_module(mod->name)) {
                err = -EEXIST;
 
        if (find_module(mod->name)) {
                err = -EEXIST;
@@ -1756,18 +1924,28 @@ static struct module *load_module(void __user *umod,
        /* Now we've moved module, initialize linked lists, etc. */
        module_unload_init(mod);
 
        /* Now we've moved module, initialize linked lists, etc. */
        module_unload_init(mod);
 
+       /* add kobject, so we can reference it. */
+       err = mod_sysfs_init(mod);
+       if (err)
+               goto free_unload;
+
        /* Set up license info based on the info section */
        set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
 
        /* 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(TAINT_PROPRIETARY_MODULE);
        if (strcmp(mod->name, "ndiswrapper") == 0)
                add_taint(TAINT_PROPRIETARY_MODULE);
+
+       /* driverloader was caught wrongly pretending to be under GPL */
        if (strcmp(mod->name, "driverloader") == 0)
        if (strcmp(mod->name, "driverloader") == 0)
-               add_taint(TAINT_PROPRIETARY_MODULE);
+               add_taint_module(mod, TAINT_PROPRIETARY_MODULE);
 
 
-#ifdef CONFIG_MODULE_UNLOAD
        /* Set up MODINFO_ATTR fields */
        setup_modinfo(mod, sechdrs, infoindex);
        /* Set up MODINFO_ATTR fields */
        setup_modinfo(mod, sechdrs, infoindex);
-#endif
 
        /* Fix up syms, so that st_value is a pointer to location. */
        err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
 
        /* Fix up syms, so that st_value is a pointer to location. */
        err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
@@ -1784,15 +1962,37 @@ static struct module *load_module(void __user *umod,
        mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr;
        if (gplcrcindex)
                mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
        mod->gpl_syms = (void *)sechdrs[gplindex].sh_addr;
        if (gplcrcindex)
                mod->gpl_crcs = (void *)sechdrs[gplcrcindex].sh_addr;
+       mod->num_gpl_future_syms = sechdrs[gplfutureindex].sh_size /
+                                       sizeof(*mod->gpl_future_syms);
+       mod->num_unused_syms = sechdrs[unusedindex].sh_size /
+                                       sizeof(*mod->unused_syms);
+       mod->num_unused_gpl_syms = sechdrs[unusedgplindex].sh_size /
+                                       sizeof(*mod->unused_gpl_syms);
+       mod->gpl_future_syms = (void *)sechdrs[gplfutureindex].sh_addr;
+       if (gplfuturecrcindex)
+               mod->gpl_future_crcs = (void *)sechdrs[gplfuturecrcindex].sh_addr;
+
+       mod->unused_syms = (void *)sechdrs[unusedindex].sh_addr;
+       if (unusedcrcindex)
+               mod->unused_crcs = (void *)sechdrs[unusedcrcindex].sh_addr;
+       mod->unused_gpl_syms = (void *)sechdrs[unusedgplindex].sh_addr;
+       if (unusedgplcrcindex)
+               mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr;
 
 #ifdef CONFIG_MODVERSIONS
 
 #ifdef CONFIG_MODVERSIONS
-       if ((mod->num_syms && !crcindex) || 
-           (mod->num_gpl_syms && !gplcrcindex)) {
+       if ((mod->num_syms && !crcindex) ||
+           (mod->num_gpl_syms && !gplcrcindex) ||
+           (mod->num_gpl_future_syms && !gplfuturecrcindex) ||
+           (mod->num_unused_syms && !unusedcrcindex) ||
+           (mod->num_unused_gpl_syms && !unusedgplcrcindex)) {
                printk(KERN_WARNING "%s: No versions for exported symbols."
                       " Tainting kernel.\n", mod->name);
                printk(KERN_WARNING "%s: No versions for exported symbols."
                       " Tainting kernel.\n", mod->name);
-               add_taint(TAINT_FORCED_MODULE);
+               add_taint_module(mod, TAINT_FORCED_MODULE);
        }
 #endif
        }
 #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++) {
 
        /* Now do relocations. */
        for (i = 1; i < hdr->e_shnum; i++) {
@@ -1815,6 +2015,11 @@ static struct module *load_module(void __user *umod,
                if (err < 0)
                        goto cleanup;
        }
                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);
 
         /* Find duplicate symbols */
        err = verify_export_symbols(mod);
@@ -1833,6 +2038,11 @@ static struct module *load_module(void __user *umod,
 
        add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
 
 
        add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
 
+#ifdef CONFIG_MARKERS
+       if (!mod->taints)
+               marker_update_probe_range(mod->markers,
+                       mod->markers + mod->num_markers);
+#endif
        err = module_finalize(hdr, sechdrs, mod);
        if (err < 0)
                goto cleanup;
        err = module_finalize(hdr, sechdrs, mod);
        if (err < 0)
                goto cleanup;
@@ -1856,38 +2066,39 @@ static struct module *load_module(void __user *umod,
        set_fs(old_fs);
 
        mod->args = args;
        set_fs(old_fs);
 
        mod->args = args;
-       if (obsparmindex) {
-               err = obsolete_params(mod->name, mod->args,
-                                     (struct obsolete_modparm *)
-                                     sechdrs[obsparmindex].sh_addr,
-                                     sechdrs[obsparmindex].sh_size
-                                     / sizeof(struct obsolete_modparm),
-                                     sechdrs, symindex,
-                                     (char *)sechdrs[strindex].sh_addr);
-               if (setupindex)
-                       printk(KERN_WARNING "%s: Ignoring new-style "
-                              "parameters in presence of obsolete ones\n",
-                              mod->name);
-       } else {
-               /* Size of section 0 is 0, so this works well if no params */
-               err = parse_args(mod->name, mod->args,
-                                (struct kernel_param *)
-                                sechdrs[setupindex].sh_addr,
-                                sechdrs[setupindex].sh_size
-                                / sizeof(struct kernel_param),
-                                NULL);
-       }
+       if (obsparmindex)
+               printk(KERN_WARNING "%s: Ignoring obsolete parameters\n",
+                      mod->name);
+
+       /* Now sew it into the lists so we can get lockdep and oops
+         * info during argument parsing.  Noone should access us, since
+         * strong_try_module_get() will fail. */
+       stop_machine_run(__link_module, mod, NR_CPUS);
+
+       /* Size of section 0 is 0, so this works well if no params */
+       err = parse_args(mod->name, mod->args,
+                        (struct kernel_param *)
+                        sechdrs[setupindex].sh_addr,
+                        sechdrs[setupindex].sh_size
+                        / sizeof(struct kernel_param),
+                        NULL);
        if (err < 0)
        if (err < 0)
-               goto arch_cleanup;
+               goto unlink;
 
 
-       err = mod_sysfs_setup(mod, 
+       err = mod_sysfs_setup(mod,
                              (struct kernel_param *)
                              sechdrs[setupindex].sh_addr,
                              sechdrs[setupindex].sh_size
                              / sizeof(struct kernel_param));
        if (err < 0)
                              (struct kernel_param *)
                              sechdrs[setupindex].sh_addr,
                              sechdrs[setupindex].sh_size
                              / sizeof(struct kernel_param));
        if (err < 0)
-               goto arch_cleanup;
+               goto unlink;
        add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
        add_sect_attrs(mod, hdr->e_shnum, secstrings, sechdrs);
+       add_notes_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);
 
        /* Get rid of temporary copy */
        vfree(hdr);
@@ -1895,9 +2106,13 @@ static struct module *load_module(void __user *umod,
        /* Done! */
        return mod;
 
        /* Done! */
        return mod;
 
- arch_cleanup:
+ unlink:
+       stop_machine_run(__unlink_module, mod, NR_CPUS);
        module_arch_cleanup(mod);
  cleanup:
        module_arch_cleanup(mod);
  cleanup:
+       kobject_del(&mod->mkobj.kobj);
+       kobject_put(&mod->mkobj.kobj);
+ free_unload:
        module_unload_free(mod);
        module_free(mod, mod->module_init);
  free_core:
        module_unload_free(mod);
        module_free(mod, mod->module_init);
  free_core:
@@ -1917,17 +2132,6 @@ static struct module *load_module(void __user *umod,
        goto free_hdr;
 }
 
        goto free_hdr;
 }
 
-/*
- * link the module with the whole machine is stopped with interrupts off
- * - this defends against kallsyms not taking locks
- */
-static int __link_module(void *_mod)
-{
-       struct module *mod = _mod;
-       list_add(&mod->list, &modules);
-       return 0;
-}
-
 /* This is where the real work happens */
 asmlinkage long
 sys_init_module(void __user *umod,
 /* This is where the real work happens */
 asmlinkage long
 sys_init_module(void __user *umod,
@@ -1942,26 +2146,21 @@ sys_init_module(void __user *umod,
                return -EPERM;
 
        /* Only one module load at a time, please */
                return -EPERM;
 
        /* Only one module load at a time, please */
-       if (down_interruptible(&module_mutex) != 0)
+       if (mutex_lock_interruptible(&module_mutex) != 0)
                return -EINTR;
 
        /* Do all the hard work */
        mod = load_module(umod, len, uargs);
        if (IS_ERR(mod)) {
                return -EINTR;
 
        /* Do all the hard work */
        mod = load_module(umod, len, uargs);
        if (IS_ERR(mod)) {
-               up(&module_mutex);
+               mutex_unlock(&module_mutex);
                return PTR_ERR(mod);
        }
 
                return PTR_ERR(mod);
        }
 
-       /* Now sew it into the lists.  They won't access us, since
-           strong_try_module_get() will fail. */
-       stop_machine_run(__link_module, mod, NR_CPUS);
-
        /* Drop lock so they can recurse */
        /* Drop lock so they can recurse */
-       up(&module_mutex);
+       mutex_unlock(&module_mutex);
 
 
-       down(&notify_mutex);
-       notifier_call_chain(&module_notify_list, MODULE_STATE_COMING, mod);
-       up(&notify_mutex);
+       blocking_notifier_call_chain(&module_notify_list,
+                       MODULE_STATE_COMING, mod);
 
        /* Start the module */
        if (mod->init != NULL)
 
        /* Start the module */
        if (mod->init != NULL)
@@ -1971,28 +2170,35 @@ sys_init_module(void __user *umod,
                    buggy refcounters. */
                mod->state = MODULE_STATE_GOING;
                synchronize_sched();
                    buggy refcounters. */
                mod->state = MODULE_STATE_GOING;
                synchronize_sched();
-               if (mod->unsafe)
-                       printk(KERN_ERR "%s: module is now stuck!\n",
-                              mod->name);
-               else {
-                       module_put(mod);
-                       down(&module_mutex);
-                       free_module(mod);
-                       up(&module_mutex);
-               }
+               module_put(mod);
+               mutex_lock(&module_mutex);
+               free_module(mod);
+               mutex_unlock(&module_mutex);
+               wake_up(&module_wq);
                return ret;
        }
                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! */
-       down(&module_mutex);
+       /* Now it's a first class citizen!  Wake up anyone waiting for it. */
        mod->state = MODULE_STATE_LIVE;
        mod->state = MODULE_STATE_LIVE;
+       wake_up(&module_wq);
+
+       mutex_lock(&module_mutex);
        /* Drop initial reference. */
        module_put(mod);
        /* 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;
        mod->init_text_size = 0;
        module_free(mod, mod->module_init);
        mod->module_init = NULL;
        mod->init_size = 0;
        mod->init_text_size = 0;
-       up(&module_mutex);
+       mutex_unlock(&module_mutex);
 
        return 0;
 }
 
        return 0;
 }
@@ -2009,7 +2215,7 @@ static inline int within(unsigned long addr, void *start, unsigned long size)
  */
 static inline int is_arm_mapping_symbol(const char *str)
 {
  */
 static inline int is_arm_mapping_symbol(const char *str)
 {
-       return str[0] == '$' && strchr("atd", str[1]) 
+       return str[0] == '$' && strchr("atd", str[1])
               && (str[2] == '\0' || str[2] == '.');
 }
 
               && (str[2] == '\0' || str[2] == '.');
 }
 
@@ -2024,11 +2230,11 @@ static const char *get_ksymbol(struct module *mod,
        /* At worse, next value is at end of module */
        if (within(addr, mod->module_init, mod->init_size))
                nextval = (unsigned long)mod->module_init+mod->init_text_size;
        /* At worse, next value is at end of module */
        if (within(addr, mod->module_init, mod->init_size))
                nextval = (unsigned long)mod->module_init+mod->init_text_size;
-       else 
+       else
                nextval = (unsigned long)mod->module_core+mod->core_text_size;
 
        /* Scan for closest preceeding symbol, and next symbol. (ELF
                nextval = (unsigned long)mod->module_core+mod->core_text_size;
 
        /* Scan for closest preceeding symbol, and next symbol. (ELF
-           starts real symbols at 1). */
+          starts real symbols at 1). */
        for (i = 1; i < mod->num_symtab; i++) {
                if (mod->symtab[i].st_shndx == SHN_UNDEF)
                        continue;
        for (i = 1; i < mod->num_symtab; i++) {
                if (mod->symtab[i].st_shndx == SHN_UNDEF)
                        continue;
@@ -2050,53 +2256,114 @@ static const char *get_ksymbol(struct module *mod,
        if (!best)
                return NULL;
 
        if (!best)
                return NULL;
 
-       *size = nextval - mod->symtab[best].st_value;
-       *offset = addr - mod->symtab[best].st_value;
+       if (size)
+               *size = nextval - mod->symtab[best].st_value;
+       if (offset)
+               *offset = addr - mod->symtab[best].st_value;
        return mod->strtab + mod->symtab[best].st_name;
 }
 
        return mod->strtab + mod->symtab[best].st_name;
 }
 
-/* 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. */
+/* For kallsyms to ask for address resolution.  NULL means not found.  Careful
+ * not to lock to avoid deadlock on oopses, simply disable preemption. */
 const char *module_address_lookup(unsigned long addr,
 const char *module_address_lookup(unsigned long addr,
-                                 unsigned long *size,
-                                 unsigned long *offset,
-                                 char **modname)
+                           unsigned long *size,
+                           unsigned long *offset,
+                           char **modname,
+                           char *namebuf)
 {
        struct module *mod;
 {
        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)) {
        list_for_each_entry(mod, &modules, list) {
                if (within(addr, mod->module_init, mod->init_size)
                    || within(addr, mod->module_core, mod->core_size)) {
-                       *modname = mod->name;
-                       return get_ksymbol(mod, addr, size, offset);
+                       if (modname)
+                               *modname = mod->name;
+                       ret = get_ksymbol(mod, addr, size, offset);
+                       break;
                }
        }
                }
        }
-       return NULL;
+       /* Make a copy in here where it's safe */
+       if (ret) {
+               strncpy(namebuf, ret, KSYM_NAME_LEN - 1);
+               ret = namebuf;
+       }
+       preempt_enable();
+       return ret;
+}
+
+int lookup_module_symbol_name(unsigned long addr, char *symname)
+{
+       struct module *mod;
+
+       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)) {
+                       const char *sym;
+
+                       sym = get_ksymbol(mod, addr, NULL, NULL);
+                       if (!sym)
+                               goto out;
+                       strlcpy(symname, sym, KSYM_NAME_LEN);
+                       preempt_enable();
+                       return 0;
+               }
+       }
+out:
+       preempt_enable();
+       return -ERANGE;
+}
+
+int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
+                       unsigned long *offset, char *modname, char *name)
+{
+       struct module *mod;
+
+       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)) {
+                       const char *sym;
+
+                       sym = get_ksymbol(mod, addr, size, offset);
+                       if (!sym)
+                               goto out;
+                       if (modname)
+                               strlcpy(modname, mod->name, MODULE_NAME_LEN);
+                       if (name)
+                               strlcpy(name, sym, KSYM_NAME_LEN);
+                       preempt_enable();
+                       return 0;
+               }
+       }
+out:
+       preempt_enable();
+       return -ERANGE;
 }
 
 }
 
-struct module *module_get_kallsym(unsigned int symnum,
-                                 unsigned long *value,
-                                 char *type,
-                                 char namebuf[128])
+int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
+                       char *name, char *module_name, int *exported)
 {
        struct module *mod;
 
 {
        struct module *mod;
 
-       down(&module_mutex);
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (symnum < mod->num_symtab) {
                        *value = mod->symtab[symnum].st_value;
                        *type = mod->symtab[symnum].st_info;
        list_for_each_entry(mod, &modules, list) {
                if (symnum < mod->num_symtab) {
                        *value = mod->symtab[symnum].st_value;
                        *type = mod->symtab[symnum].st_info;
-                       strncpy(namebuf,
-                               mod->strtab + mod->symtab[symnum].st_name,
-                               127);
-                       up(&module_mutex);
-                       return mod;
+                       strlcpy(name, mod->strtab + mod->symtab[symnum].st_name,
+                               KSYM_NAME_LEN);
+                       strlcpy(module_name, mod->name, MODULE_NAME_LEN);
+                       *exported = is_exported(name, mod);
+                       preempt_enable();
+                       return 0;
                }
                symnum -= mod->num_symtab;
        }
                }
                symnum -= mod->num_symtab;
        }
-       up(&module_mutex);
-       return NULL;
+       preempt_enable();
+       return -ERANGE;
 }
 
 static unsigned long mod_find_symname(struct module *mod, const char *name)
 }
 
 static unsigned long mod_find_symname(struct module *mod, const char *name)
@@ -2118,6 +2385,7 @@ unsigned long module_kallsyms_lookup_name(const char *name)
        unsigned long ret = 0;
 
        /* Don't lock: we're in enough trouble already. */
        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)
        if ((colon = strchr(name, ':')) != NULL) {
                *colon = '\0';
                if ((mod = find_module(name)) != NULL)
@@ -2128,6 +2396,7 @@ unsigned long module_kallsyms_lookup_name(const char *name)
                        if ((ret = mod_find_symname(mod, name)) != 0)
                                break;
        }
                        if ((ret = mod_find_symname(mod, name)) != 0)
                                break;
        }
+       preempt_enable();
        return ret;
 }
 #endif /* CONFIG_KALLSYMS */
        return ret;
 }
 #endif /* CONFIG_KALLSYMS */
@@ -2135,36 +2404,56 @@ unsigned long module_kallsyms_lookup_name(const char *name)
 /* Called by the /proc file system to return a list of modules. */
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
 /* Called by the /proc file system to return a list of modules. */
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
-       struct list_head *i;
-       loff_t n = 0;
-
-       down(&module_mutex);
-       list_for_each(i, &modules) {
-               if (n++ == *pos)
-                       break;
-       }
-       if (i == &modules)
-               return NULL;
-       return i;
+       mutex_lock(&module_mutex);
+       return seq_list_start(&modules, *pos);
 }
 
 static void *m_next(struct seq_file *m, void *p, loff_t *pos)
 {
 }
 
 static void *m_next(struct seq_file *m, void *p, loff_t *pos)
 {
-       struct list_head *i = p;
-       (*pos)++;
-       if (i->next == &modules)
-               return NULL;
-       return i->next;
+       return seq_list_next(p, &modules, pos);
 }
 
 static void m_stop(struct seq_file *m, void *p)
 {
 }
 
 static void m_stop(struct seq_file *m, void *p)
 {
-       up(&module_mutex);
+       mutex_unlock(&module_mutex);
+}
+
+static char *module_flags(struct module *mod, char *buf)
+{
+       int bx = 0;
+
+       if (mod->taints ||
+           mod->state == MODULE_STATE_GOING ||
+           mod->state == MODULE_STATE_COMING) {
+               buf[bx++] = '(';
+               if (mod->taints & TAINT_PROPRIETARY_MODULE)
+                       buf[bx++] = 'P';
+               if (mod->taints & TAINT_FORCED_MODULE)
+                       buf[bx++] = 'F';
+               /*
+                * TAINT_FORCED_RMMOD: could be added.
+                * TAINT_UNSAFE_SMP, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
+                * apply to modules.
+                */
+
+               /* Show a - for module-is-being-unloaded */
+               if (mod->state == MODULE_STATE_GOING)
+                       buf[bx++] = '-';
+               /* Show a + for module-is-being-loaded */
+               if (mod->state == MODULE_STATE_COMING)
+                       buf[bx++] = '+';
+               buf[bx++] = ')';
+       }
+       buf[bx] = '\0';
+
+       return buf;
 }
 
 static int m_show(struct seq_file *m, void *p)
 {
        struct module *mod = list_entry(p, struct module, list);
 }
 
 static int m_show(struct seq_file *m, void *p)
 {
        struct module *mod = list_entry(p, struct module, list);
+       char buf[8];
+
        seq_printf(m, "%s %lu",
                   mod->name, mod->init_size + mod->core_size);
        print_unload_info(m, mod);
        seq_printf(m, "%s %lu",
                   mod->name, mod->init_size + mod->core_size);
        print_unload_info(m, mod);
@@ -2177,6 +2466,10 @@ static int m_show(struct seq_file *m, void *p)
        /* Used by oprofile and other similar tools. */
        seq_printf(m, " 0x%p", mod->module_core);
 
        /* Used by oprofile and other similar tools. */
        seq_printf(m, " 0x%p", mod->module_core);
 
+       /* Taints info */
+       if (mod->taints)
+               seq_printf(m, " %s", module_flags(mod, buf));
+
        seq_printf(m, "\n");
        return 0;
 }
        seq_printf(m, "\n");
        return 0;
 }
@@ -2186,7 +2479,7 @@ static int m_show(struct seq_file *m, void *p)
    Where refcount is a number or -, and deps is a comma-separated list
    of depends or -.
 */
    Where refcount is a number or -, and deps is a comma-separated list
    of depends or -.
 */
-struct seq_operations modules_op = {
+const struct seq_operations modules_op = {
        .start  = m_start,
        .next   = m_next,
        .stop   = m_stop,
        .start  = m_start,
        .next   = m_next,
        .stop   = m_stop,
@@ -2196,29 +2489,50 @@ struct seq_operations modules_op = {
 /* Given an address, look for it in the module exception tables. */
 const struct exception_table_entry *search_module_extables(unsigned long addr)
 {
 /* Given an address, look for it in the module exception tables. */
 const struct exception_table_entry *search_module_extables(unsigned long addr)
 {
-       unsigned long flags;
        const struct exception_table_entry *e = NULL;
        struct module *mod;
 
        const struct exception_table_entry *e = NULL;
        struct module *mod;
 
-       spin_lock_irqsave(&modlist_lock, flags);
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (mod->num_exentries == 0)
                        continue;
        list_for_each_entry(mod, &modules, list) {
                if (mod->num_exentries == 0)
                        continue;
-                               
+
                e = search_extable(mod->extable,
                                   mod->extable + mod->num_exentries - 1,
                                   addr);
                if (e)
                        break;
        }
                e = search_extable(mod->extable,
                                   mod->extable + mod->num_exentries - 1,
                                   addr);
                if (e)
                        break;
        }
-       spin_unlock_irqrestore(&modlist_lock, flags);
+       preempt_enable();
 
        /* Now, if we found one, we are running inside it now, hence
 
        /* Now, if we found one, we are running inside it now, hence
-           we cannot unload the module, hence no refcnt needed. */
+          we cannot unload the module, hence no refcnt needed. */
        return e;
 }
 
        return e;
 }
 
-/* Is this a valid kernel address?  We don't grab the lock: we are oopsing. */
+/*
+ * Is this a valid module address?
+ */
+int is_module_address(unsigned long addr)
+{
+       struct module *mod;
+
+       preempt_disable();
+
+       list_for_each_entry(mod, &modules, list) {
+               if (within(addr, mod->module_core, mod->core_size)) {
+                       preempt_enable();
+                       return 1;
+               }
+       }
+
+       preempt_enable();
+
+       return 0;
+}
+
+
+/* Is this a valid kernel address? */
 struct module *__module_text_address(unsigned long addr)
 {
        struct module *mod;
 struct module *__module_text_address(unsigned long addr)
 {
        struct module *mod;
@@ -2233,11 +2547,10 @@ struct module *__module_text_address(unsigned long addr)
 struct module *module_text_address(unsigned long addr)
 {
        struct module *mod;
 struct module *module_text_address(unsigned long addr)
 {
        struct module *mod;
-       unsigned long flags;
 
 
-       spin_lock_irqsave(&modlist_lock, flags);
+       preempt_disable();
        mod = __module_text_address(addr);
        mod = __module_text_address(addr);
-       spin_unlock_irqrestore(&modlist_lock, flags);
+       preempt_enable();
 
        return mod;
 }
 
        return mod;
 }
@@ -2246,33 +2559,32 @@ struct module *module_text_address(unsigned long addr)
 void print_modules(void)
 {
        struct module *mod;
 void print_modules(void)
 {
        struct module *mod;
+       char buf[8];
 
        printk("Modules linked in:");
        list_for_each_entry(mod, &modules, list)
 
        printk("Modules linked in:");
        list_for_each_entry(mod, &modules, list)
-               printk(" %s", mod->name);
+               printk(" %s%s", mod->name, module_flags(mod, buf));
+       if (last_unloaded_module[0])
+               printk(" [last unloaded: %s]", last_unloaded_module);
        printk("\n");
 }
 
        printk("\n");
 }
 
-void module_add_driver(struct module *mod, struct device_driver *drv)
-{
-       if (!mod || !drv)
-               return;
-
-       /* Don't check return code; this call is idempotent */
-       sysfs_create_link(&drv->kobj, &mod->mkobj.kobj, "module");
-}
-EXPORT_SYMBOL(module_add_driver);
-
-void module_remove_driver(struct device_driver *drv)
-{
-       if (!drv)
-               return;
-       sysfs_remove_link(&drv->kobj, "module");
-}
-EXPORT_SYMBOL(module_remove_driver);
-
 #ifdef CONFIG_MODVERSIONS
 /* Generate the signature for struct module here, too, for modversions. */
 void struct_module(struct module *mod) { return; }
 EXPORT_SYMBOL(struct_module);
 #endif
 #ifdef CONFIG_MODVERSIONS
 /* Generate the signature for struct module here, too, for modversions. */
 void struct_module(struct module *mod) { return; }
 EXPORT_SYMBOL(struct_module);
 #endif
+
+#ifdef CONFIG_MARKERS
+void module_update_markers(void)
+{
+       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);
+       mutex_unlock(&module_mutex);
+}
+#endif