]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - kernel/module.c
vxlan: add ipv6 route short circuit support
[karo-tx-linux.git] / kernel / module.c
index cab4bce49c23dbe3779d02db8259dda28b7b4258..206915830d2993bc54124b0fecf09abadac08a0f 100644 (file)
@@ -455,7 +455,7 @@ const struct kernel_symbol *find_symbol(const char *name,
 EXPORT_SYMBOL_GPL(find_symbol);
 
 /* Search for module by name: must hold module_mutex. */
-static struct module *find_module_all(const char *name,
+static struct module *find_module_all(const char *name, size_t len,
                                      bool even_unformed)
 {
        struct module *mod;
@@ -463,7 +463,7 @@ static struct module *find_module_all(const char *name,
        list_for_each_entry(mod, &modules, list) {
                if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
                        continue;
-               if (strcmp(mod->name, name) == 0)
+               if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
                        return mod;
        }
        return NULL;
@@ -471,7 +471,7 @@ static struct module *find_module_all(const char *name,
 
 struct module *find_module(const char *name)
 {
-       return find_module_all(name, false);
+       return find_module_all(name, strlen(name), false);
 }
 EXPORT_SYMBOL_GPL(find_module);
 
@@ -482,23 +482,28 @@ static inline void __percpu *mod_percpu(struct module *mod)
        return mod->percpu;
 }
 
-static int percpu_modalloc(struct module *mod,
-                          unsigned long size, unsigned long align)
+static int percpu_modalloc(struct module *mod, struct load_info *info)
 {
+       Elf_Shdr *pcpusec = &info->sechdrs[info->index.pcpu];
+       unsigned long align = pcpusec->sh_addralign;
+
+       if (!pcpusec->sh_size)
+               return 0;
+
        if (align > PAGE_SIZE) {
                printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n",
                       mod->name, align, PAGE_SIZE);
                align = PAGE_SIZE;
        }
 
-       mod->percpu = __alloc_reserved_percpu(size, align);
+       mod->percpu = __alloc_reserved_percpu(pcpusec->sh_size, align);
        if (!mod->percpu) {
                printk(KERN_WARNING
                       "%s: Could not allocate %lu bytes percpu data\n",
-                      mod->name, size);
+                      mod->name, (unsigned long)pcpusec->sh_size);
                return -ENOMEM;
        }
-       mod->percpu_size = size;
+       mod->percpu_size = pcpusec->sh_size;
        return 0;
 }
 
@@ -563,10 +568,12 @@ static inline void __percpu *mod_percpu(struct module *mod)
 {
        return NULL;
 }
-static inline int percpu_modalloc(struct module *mod,
-                                 unsigned long size, unsigned long align)
+static int percpu_modalloc(struct module *mod, struct load_info *info)
 {
-       return -ENOMEM;
+       /* UP modules shouldn't have this section: ENOMEM isn't quite right */
+       if (info->sechdrs[info->index.pcpu].sh_size != 0)
+               return -ENOMEM;
+       return 0;
 }
 static inline void percpu_modfree(struct module *mod)
 {
@@ -2927,7 +2934,6 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
 {
        /* Module within temporary copy. */
        struct module *mod;
-       Elf_Shdr *pcpusec;
        int err;
 
        mod = setup_load_info(info, flags);
@@ -2942,17 +2948,10 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
        err = module_frob_arch_sections(info->hdr, info->sechdrs,
                                        info->secstrings, mod);
        if (err < 0)
-               goto out;
+               return ERR_PTR(err);
 
-       pcpusec = &info->sechdrs[info->index.pcpu];
-       if (pcpusec->sh_size) {
-               /* We have a special allocation for this section. */
-               err = percpu_modalloc(mod,
-                                     pcpusec->sh_size, pcpusec->sh_addralign);
-               if (err)
-                       goto out;
-               pcpusec->sh_flags &= ~(unsigned long)SHF_ALLOC;
-       }
+       /* We will do a special allocation for per-cpu sections later. */
+       info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC;
 
        /* Determine total sizes, and put offsets in sh_entsize.  For now
           this is done generically; there doesn't appear to be any
@@ -2963,17 +2962,12 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)
        /* Allocate and move to the final place */
        err = move_module(mod, info);
        if (err)
-               goto free_percpu;
+               return ERR_PTR(err);
 
        /* Module has been copied to its final place now: return it. */
        mod = (void *)info->sechdrs[info->index.mod].sh_addr;
        kmemleak_load_module(mod, info);
        return mod;
-
-free_percpu:
-       percpu_modfree(mod);
-out:
-       return ERR_PTR(err);
 }
 
 /* mod is no longer valid after this! */
@@ -3014,7 +3008,7 @@ static bool finished_loading(const char *name)
        bool ret;
 
        mutex_lock(&module_mutex);
-       mod = find_module_all(name, true);
+       mod = find_module_all(name, strlen(name), true);
        ret = !mod || mod->state == MODULE_STATE_LIVE
                || mod->state == MODULE_STATE_GOING;
        mutex_unlock(&module_mutex);
@@ -3152,7 +3146,8 @@ static int add_unformed_module(struct module *mod)
 
 again:
        mutex_lock(&module_mutex);
-       if ((old = find_module_all(mod->name, true)) != NULL) {
+       old = find_module_all(mod->name, strlen(mod->name), true);
+       if (old != NULL) {
                if (old->state == MODULE_STATE_COMING
                    || old->state == MODULE_STATE_UNFORMED) {
                        /* Wait in case it fails to load. */
@@ -3198,6 +3193,17 @@ out:
        return err;
 }
 
+static int unknown_module_param_cb(char *param, char *val, const char *modname)
+{
+       /* Check for magic 'dyndbg' arg */ 
+       int ret = ddebug_dyndbg_module_param_cb(param, val, modname);
+       if (ret != 0) {
+               printk(KERN_WARNING "%s: unknown parameter '%s' ignored\n",
+                      modname, param);
+       }
+       return 0;
+}
+
 /* Allocate and load the module: note that size of section 0 is always
    zero, and we rely on this for optional sections. */
 static int load_module(struct load_info *info, const char __user *uargs,
@@ -3237,6 +3243,11 @@ static int load_module(struct load_info *info, const char __user *uargs,
        }
 #endif
 
+       /* To avoid stressing percpu allocator, do this once we're unique. */
+       err = percpu_modalloc(mod, info);
+       if (err)
+               goto unlink_mod;
+
        /* Now module is in final location, initialize linked lists, etc. */
        err = module_unload_init(mod);
        if (err)
@@ -3284,7 +3295,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
 
        /* Module is ready to execute: parsing args may do that. */
        err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp,
-                        -32768, 32767, &ddebug_dyndbg_module_param_cb);
+                        -32768, 32767, unknown_module_param_cb);
        if (err < 0)
                goto bug_cleanup;
 
@@ -3563,10 +3574,8 @@ unsigned long module_kallsyms_lookup_name(const char *name)
        /* 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 ((mod = find_module_all(name, colon - name, false)) != NULL)
                        ret = mod_find_symname(mod, colon+1);
-               *colon = ':';
        } else {
                list_for_each_entry_rcu(mod, &modules, list) {
                        if (mod->state == MODULE_STATE_UNFORMED)