[PATCH] I2O: Bugfixes to get I2O working again
[pandora-kernel.git] / kernel / module.c
index 77764f2..bbe0486 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/device.h>
 #include <linux/string.h>
 #include <linux/sched.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 #include <asm/cacheflush.h>
 static DEFINE_SPINLOCK(modlist_lock);
 
 /* List of modules, protected by module_mutex AND modlist_lock */
-static DECLARE_MUTEX(module_mutex);
+static DEFINE_MUTEX(module_mutex);
 static LIST_HEAD(modules);
 
-static DECLARE_MUTEX(notify_mutex);
-static struct notifier_block * module_notify_list;
+static BLOCKING_NOTIFIER_HEAD(module_notify_list);
 
 int register_module_notifier(struct notifier_block * nb)
 {
-       int err;
-       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)
 {
-       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);
 
@@ -135,7 +127,7 @@ extern const unsigned long __start___kcrctab_gpl_future[];
 #ifndef CONFIG_MODVERSIONS
 #define symversion(base, idx) NULL
 #else
-#define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL)
+#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
 #endif
 
 /* lookup symbol in given range of kernel_symbols */
@@ -232,24 +224,6 @@ static unsigned long __find_symbol(const char *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;
-
-       /* 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;
-       }
-       return 0;
-}
-
 /* Search for module by name: must hold module_mutex. */
 static struct module *find_module(const char *name)
 {
@@ -601,7 +575,7 @@ static void free_module(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);
+       mutex_unlock(&module_mutex);
        for (;;) {
                DEBUGP("Looking at refcount...\n");
                set_current_state(TASK_UNINTERRUPTIBLE);
@@ -610,7 +584,7 @@ static void wait_for_zero_refcount(struct module *mod)
                schedule();
        }
        current->state = TASK_RUNNING;
-       down(&module_mutex);
+       mutex_lock(&module_mutex);
 }
 
 asmlinkage long
@@ -627,7 +601,7 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
                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);
@@ -676,14 +650,14 @@ sys_delete_module(const char __user *name_user, unsigned int flags)
 
        /* Final destruction now noone is using it. */
        if (mod->exit != NULL) {
-               up(&module_mutex);
+               mutex_unlock(&module_mutex);
                mod->exit();
-               down(&module_mutex);
+               mutex_lock(&module_mutex);
        }
        free_module(mod);
 
  out:
-       up(&module_mutex);
+       mutex_unlock(&module_mutex);
        return ret;
 }
 
@@ -731,14 +705,14 @@ EXPORT_SYMBOL(__symbol_put);
 
 void symbol_put_addr(void *addr)
 {
-       unsigned long flags;
+       struct module *modaddr;
 
-       spin_lock_irqsave(&modlist_lock, flags);
-       if (!kernel_text_address((unsigned long)addr))
-               BUG();
+       if (core_kernel_text((unsigned long)addr))
+               return;
 
-       module_put(module_text_address((unsigned long)addr));
-       spin_unlock_irqrestore(&modlist_lock, flags);
+       if (!(modaddr = module_text_address((unsigned long)addr)))
+               BUG();
+       module_put(modaddr);
 }
 EXPORT_SYMBOL_GPL(symbol_put_addr);
 
@@ -784,139 +758,6 @@ static struct module_attribute *modinfo_attrs[] = {
        NULL,
 };
 
-#ifdef CONFIG_OBSOLETE_MODPARM
-/* Bounds checking done below */
-static int obsparm_copy_string(const char *val, struct kernel_param *kp)
-{
-       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;
-
-       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];
-       }
-
-       ret = parse_args(name, args, kp, num, NULL);
- out:
-       kfree(kp);
-       return ret;
-}
-#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 const char vermagic[] = VERMAGIC_STRING;
 
 #ifdef CONFIG_MODVERSIONS
@@ -1413,6 +1254,7 @@ static inline int license_is_gpl_compatible(const char *license)
                || strcmp(license, "GPL v2") == 0
                || strcmp(license, "GPL and additional rights") == 0
                || strcmp(license, "Dual BSD/GPL") == 0
+               || strcmp(license, "Dual MIT/GPL") == 0
                || strcmp(license, "Dual MPL/GPL") == 0);
 }
 
@@ -1571,7 +1413,6 @@ static struct module *load_module(void __user *umod,
                exportindex, modindex, obsparmindex, infoindex, gplindex,
                crcindex, gplcrcindex, versindex, pcpuindex, gplfutureindex,
                gplfuturecrcindex;
-       long arglen;
        struct module *mod;
        long err = 0;
        void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
@@ -1690,23 +1531,11 @@ static struct module *load_module(void __user *umod,
        }
 
        /* 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;
        }
-       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;
@@ -1886,27 +1715,17 @@ static struct module *load_module(void __user *umod,
        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);
+
+       /* 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)
                goto arch_cleanup;
 
@@ -1972,13 +1791,13 @@ sys_init_module(void __user *umod,
                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)) {
-               up(&module_mutex);
+               mutex_unlock(&module_mutex);
                return PTR_ERR(mod);
        }
 
@@ -1987,11 +1806,10 @@ sys_init_module(void __user *umod,
        stop_machine_run(__link_module, mod, NR_CPUS);
 
        /* 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)
@@ -2006,15 +1824,15 @@ sys_init_module(void __user *umod,
                               mod->name);
                else {
                        module_put(mod);
-                       down(&module_mutex);
+                       mutex_lock(&module_mutex);
                        free_module(mod);
-                       up(&module_mutex);
+                       mutex_unlock(&module_mutex);
                }
                return ret;
        }
 
        /* Now it's a first class citizen! */
-       down(&module_mutex);
+       mutex_lock(&module_mutex);
        mod->state = MODULE_STATE_LIVE;
        /* Drop initial reference. */
        module_put(mod);
@@ -2022,7 +1840,7 @@ sys_init_module(void __user *umod,
        mod->module_init = NULL;
        mod->init_size = 0;
        mod->init_text_size = 0;
-       up(&module_mutex);
+       mutex_unlock(&module_mutex);
 
        return 0;
 }
@@ -2112,7 +1930,7 @@ struct module *module_get_kallsym(unsigned int symnum,
 {
        struct module *mod;
 
-       down(&module_mutex);
+       mutex_lock(&module_mutex);
        list_for_each_entry(mod, &modules, list) {
                if (symnum < mod->num_symtab) {
                        *value = mod->symtab[symnum].st_value;
@@ -2120,12 +1938,12 @@ struct module *module_get_kallsym(unsigned int symnum,
                        strncpy(namebuf,
                                mod->strtab + mod->symtab[symnum].st_name,
                                127);
-                       up(&module_mutex);
+                       mutex_unlock(&module_mutex);
                        return mod;
                }
                symnum -= mod->num_symtab;
        }
-       up(&module_mutex);
+       mutex_unlock(&module_mutex);
        return NULL;
 }
 
@@ -2168,7 +1986,7 @@ static void *m_start(struct seq_file *m, loff_t *pos)
        struct list_head *i;
        loff_t n = 0;
 
-       down(&module_mutex);
+       mutex_lock(&module_mutex);
        list_for_each(i, &modules) {
                if (n++ == *pos)
                        break;
@@ -2189,7 +2007,7 @@ static void *m_next(struct seq_file *m, void *p, loff_t *pos)
 
 static void m_stop(struct seq_file *m, void *p)
 {
-       up(&module_mutex);
+       mutex_unlock(&module_mutex);
 }
 
 static int m_show(struct seq_file *m, void *p)