module: fix sysfs cleanup for !CONFIG_SYSFS
[pandora-kernel.git] / kernel / module.c
index cb40a4e..a64b26c 100644 (file)
@@ -110,6 +110,18 @@ int unregister_module_notifier(struct notifier_block * nb)
 }
 EXPORT_SYMBOL(unregister_module_notifier);
 
+struct load_info {
+       Elf_Ehdr *hdr;
+       unsigned long len;
+       Elf_Shdr *sechdrs;
+       char *secstrings, *args, *strtab;
+       unsigned long *strmap;
+       unsigned long symoffs, stroffs;
+       struct {
+               unsigned int sym, str, mod, vers, info, pcpu;
+       } index;
+};
+
 /* 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)
@@ -392,7 +404,8 @@ static int percpu_modalloc(struct module *mod,
        mod->percpu = __alloc_reserved_percpu(size, align);
        if (!mod->percpu) {
                printk(KERN_WARNING
-                      "Could not allocate %lu bytes percpu data\n", size);
+                      "%s: Could not allocate %lu bytes percpu data\n",
+                      mod->name, size);
                return -ENOMEM;
        }
        mod->percpu_size = size;
@@ -1113,8 +1126,9 @@ static const struct kernel_symbol *resolve_symbol_wait(Elf_Shdr *sechdrs,
  * /sys/module/foo/sections stuff
  * J. Corbet <corbet@lwn.net>
  */
-#if defined(CONFIG_KALLSYMS) && defined(CONFIG_SYSFS)
+#ifdef CONFIG_SYSFS
 
+#ifdef CONFIG_KALLSYMS
 static inline bool sect_empty(const Elf_Shdr *sect)
 {
        return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0;
@@ -1151,8 +1165,7 @@ static void free_sect_attrs(struct module_sect_attrs *sect_attrs)
        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, const struct load_info *info)
 {
        unsigned int nloaded = 0, i, size[2];
        struct module_sect_attrs *sect_attrs;
@@ -1160,8 +1173,8 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
        struct attribute **gattr;
 
        /* Count loaded sections and allocate structures */
-       for (i = 0; i < nsect; i++)
-               if (!sect_empty(&sechdrs[i]))
+       for (i = 0; i < info->hdr->e_shnum; i++)
+               if (!sect_empty(&info->sechdrs[i]))
                        nloaded++;
        size[0] = ALIGN(sizeof(*sect_attrs)
                        + nloaded * sizeof(sect_attrs->attrs[0]),
@@ -1178,11 +1191,12 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
        sect_attrs->nsections = 0;
        sattr = &sect_attrs->attrs[0];
        gattr = &sect_attrs->grp.attrs[0];
-       for (i = 0; i < nsect; i++) {
-               if (sect_empty(&sechdrs[i]))
+       for (i = 0; i < info->hdr->e_shnum; i++) {
+               Elf_Shdr *sec = &info->sechdrs[i];
+               if (sect_empty(sec))
                        continue;
-               sattr->address = sechdrs[i].sh_addr;
-               sattr->name = kstrdup(secstrings + sechdrs[i].sh_name,
+               sattr->address = sec->sh_addr;
+               sattr->name = kstrdup(info->secstrings + sec->sh_name,
                                        GFP_KERNEL);
                if (sattr->name == NULL)
                        goto out;
@@ -1250,8 +1264,7 @@ static void free_notes_attrs(struct module_notes_attrs *notes_attrs,
        kfree(notes_attrs);
 }
 
-static void add_notes_attrs(struct module *mod, unsigned int nsect,
-                           char *secstrings, Elf_Shdr *sechdrs)
+static void add_notes_attrs(struct module *mod, const struct load_info *info)
 {
        unsigned int notes, loaded, i;
        struct module_notes_attrs *notes_attrs;
@@ -1263,9 +1276,9 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect,
 
        /* Count notes sections and allocate structures.  */
        notes = 0;
-       for (i = 0; i < nsect; i++)
-               if (!sect_empty(&sechdrs[i]) &&
-                   (sechdrs[i].sh_type == SHT_NOTE))
+       for (i = 0; i < info->hdr->e_shnum; i++)
+               if (!sect_empty(&info->sechdrs[i]) &&
+                   (info->sechdrs[i].sh_type == SHT_NOTE))
                        ++notes;
 
        if (notes == 0)
@@ -1279,15 +1292,15 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect,
 
        notes_attrs->notes = notes;
        nattr = &notes_attrs->attrs[0];
-       for (loaded = i = 0; i < nsect; ++i) {
-               if (sect_empty(&sechdrs[i]))
+       for (loaded = i = 0; i < info->hdr->e_shnum; ++i) {
+               if (sect_empty(&info->sechdrs[i]))
                        continue;
-               if (sechdrs[i].sh_type == SHT_NOTE) {
+               if (info->sechdrs[i].sh_type == SHT_NOTE) {
                        sysfs_bin_attr_init(nattr);
                        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->size = info->sechdrs[i].sh_size;
+                       nattr->private = (void *) info->sechdrs[i].sh_addr;
                        nattr->read = module_notes_read;
                        ++nattr;
                }
@@ -1318,8 +1331,8 @@ static void remove_notes_attrs(struct module *mod)
 
 #else
 
-static inline void add_sect_attrs(struct module *mod, unsigned int nsect,
-               char *sectstrings, Elf_Shdr *sechdrs)
+static inline void add_sect_attrs(struct module *mod,
+                                 const struct load_info *info)
 {
 }
 
@@ -1327,17 +1340,16 @@ static inline void remove_sect_attrs(struct module *mod)
 {
 }
 
-static inline void add_notes_attrs(struct module *mod, unsigned int nsect,
-                                  char *sectstrings, Elf_Shdr *sechdrs)
+static inline void add_notes_attrs(struct module *mod,
+                                  const struct load_info *info)
 {
 }
 
 static inline void remove_notes_attrs(struct module *mod)
 {
 }
-#endif
+#endif /* CONFIG_KALLSYMS */
 
-#ifdef CONFIG_SYSFS
 static void add_usage_links(struct module *mod)
 {
 #ifdef CONFIG_MODULE_UNLOAD
@@ -1442,6 +1454,7 @@ out:
 }
 
 static int mod_sysfs_setup(struct module *mod,
+                          const struct load_info *info,
                           struct kernel_param *kparam,
                           unsigned int num_params)
 {
@@ -1466,6 +1479,8 @@ static int mod_sysfs_setup(struct module *mod,
                goto out_unreg_param;
 
        add_usage_links(mod);
+       add_sect_attrs(mod, info);
+       add_notes_attrs(mod, info);
 
        kobject_uevent(&mod->mkobj.kobj, KOBJ_ADD);
        return 0;
@@ -1482,33 +1497,26 @@ out:
 
 static void mod_sysfs_fini(struct module *mod)
 {
+       remove_notes_attrs(mod);
+       remove_sect_attrs(mod);
        kobject_put(&mod->mkobj.kobj);
 }
 
-#else /* CONFIG_SYSFS */
+#else /* !CONFIG_SYSFS */
 
-static inline int mod_sysfs_init(struct module *mod)
-{
-       return 0;
-}
-
-static inline int mod_sysfs_setup(struct module *mod,
+static int mod_sysfs_setup(struct module *mod,
+                          const struct load_info *info,
                           struct kernel_param *kparam,
                           unsigned int num_params)
 {
        return 0;
 }
 
-static inline int module_add_modinfo_attrs(struct module *mod)
-{
-       return 0;
-}
-
-static inline void module_remove_modinfo_attrs(struct module *mod)
+static void mod_sysfs_fini(struct module *mod)
 {
 }
 
-static void mod_sysfs_fini(struct module *mod)
+static void module_remove_modinfo_attrs(struct module *mod)
 {
 }
 
@@ -1518,7 +1526,7 @@ static void del_usage_links(struct module *mod)
 
 #endif /* CONFIG_SYSFS */
 
-static void mod_kobject_remove(struct module *mod)
+static void mod_sysfs_teardown(struct module *mod)
 {
        del_usage_links(mod);
        module_remove_modinfo_attrs(mod);
@@ -1548,9 +1556,7 @@ static void free_module(struct module *mod)
        mutex_lock(&module_mutex);
        stop_machine(__unlink_module, mod, NULL);
        mutex_unlock(&module_mutex);
-       remove_notes_attrs(mod);
-       remove_sect_attrs(mod);
-       mod_kobject_remove(mod);
+       mod_sysfs_teardown(mod);
 
        /* Remove dynamic debug info */
        ddebug_remove_module(mod->name);
@@ -1909,11 +1915,10 @@ static int is_exported(const char *name, unsigned long value,
 }
 
 /* As per nm */
-static char elf_type(const Elf_Sym *sym,
-                    Elf_Shdr *sechdrs,
-                    const char *secstrings,
-                    struct module *mod)
+static char elf_type(const Elf_Sym *sym, const struct load_info *info)
 {
+       const Elf_Shdr *sechdrs = info->sechdrs;
+
        if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
                if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT)
                        return 'v';
@@ -1943,8 +1948,10 @@ static char elf_type(const Elf_Sym *sym,
                else
                        return 'b';
        }
-       if (strstarts(secstrings + sechdrs[sym->st_shndx].sh_name, ".debug"))
+       if (strstarts(info->secstrings + sechdrs[sym->st_shndx].sh_name,
+                     ".debug")) {
                return 'n';
+       }
        return '?';
 }
 
@@ -2021,45 +2028,39 @@ static unsigned long layout_symtab(struct module *mod,
        return symoffs;
 }
 
-static void add_kallsyms(struct module *mod,
-                        Elf_Shdr *sechdrs,
-                        unsigned int shnum,
-                        unsigned int symindex,
-                        unsigned int strindex,
-                        unsigned long symoffs,
-                        unsigned long stroffs,
-                        const char *secstrings,
-                        unsigned long *strmap)
+static void add_kallsyms(struct module *mod, struct load_info *info)
 {
        unsigned int i, ndst;
        const Elf_Sym *src;
        Elf_Sym *dst;
        char *s;
+       Elf_Shdr *symsec = &info->sechdrs[info->index.sym];
 
-       mod->symtab = (void *)sechdrs[symindex].sh_addr;
-       mod->num_symtab = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
-       mod->strtab = (void *)sechdrs[strindex].sh_addr;
+       mod->symtab = (void *)symsec->sh_addr;
+       mod->num_symtab = symsec->sh_size / sizeof(Elf_Sym);
+       /* Make sure we get permanent strtab: don't use info->strtab. */
+       mod->strtab = (void *)info->sechdrs[info->index.str].sh_addr;
 
        /* Set types up while we still have access to sections. */
        for (i = 0; i < mod->num_symtab; i++)
-               mod->symtab[i].st_info
-                       = elf_type(&mod->symtab[i], sechdrs, secstrings, mod);
+               mod->symtab[i].st_info = elf_type(&mod->symtab[i], info);
 
-       mod->core_symtab = dst = mod->module_core + symoffs;
+       mod->core_symtab = dst = mod->module_core + info->symoffs;
        src = mod->symtab;
        *dst = *src;
        for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) {
-               if (!is_core_symbol(src, sechdrs, shnum))
+               if (!is_core_symbol(src, info->sechdrs, info->hdr->e_shnum))
                        continue;
                dst[ndst] = *src;
-               dst[ndst].st_name = bitmap_weight(strmap, dst[ndst].st_name);
+               dst[ndst].st_name = bitmap_weight(info->strmap,
+                                                 dst[ndst].st_name);
                ++ndst;
        }
        mod->core_num_syms = ndst;
 
-       mod->core_strtab = s = mod->module_core + stroffs;
-       for (*s = 0, i = 1; i < sechdrs[strindex].sh_size; ++i)
-               if (test_bit(i, strmap))
+       mod->core_strtab = s = mod->module_core + info->stroffs;
+       for (*s = 0, i = 1; i < info->sechdrs[info->index.str].sh_size; ++i)
+               if (test_bit(i, info->strmap))
                        *++s = mod->strtab[i];
 }
 #else
@@ -2075,15 +2076,7 @@ static inline unsigned long layout_symtab(struct module *mod,
        return 0;
 }
 
-static inline void add_kallsyms(struct module *mod,
-                               Elf_Shdr *sechdrs,
-                               unsigned int shnum,
-                               unsigned int symindex,
-                               unsigned int strindex,
-                               unsigned long symoffs,
-                               unsigned long stroffs,
-                               const char *secstrings,
-                               const unsigned long *strmap)
+static void add_kallsyms(struct module *mod, struct load_info *info)
 {
 }
 #endif /* CONFIG_KALLSYMS */
@@ -2148,17 +2141,10 @@ static inline void kmemleak_load_module(struct module *mod, Elf_Ehdr *hdr,
 }
 #endif
 
-struct load_info {
-       Elf_Ehdr *hdr;
-       unsigned long len;
-       Elf_Shdr *sechdrs;
-       char *secstrings, *args, *strtab;
-       struct {
-               unsigned int sym, str, mod, vers, info, pcpu;
-       } index;
-};
-
-static int copy_and_check(struct load_info *info, const void __user *umod, unsigned long len)
+/* Sets info->hdr, info->len and info->args. */
+static int copy_and_check(struct load_info *info,
+                         const void __user *umod, unsigned long len,
+                         const char __user *uargs)
 {
        int err;
        Elf_Ehdr *hdr;
@@ -2190,6 +2176,14 @@ static int copy_and_check(struct load_info *info, const void __user *umod, unsig
                err = -ENOEXEC;
                goto free_hdr;
        }
+
+       /* Now copy in args */
+       info->args = strndup_user(uargs, ~0UL >> 1);
+       if (IS_ERR(info->args)) {
+               err = PTR_ERR(info->args);
+               goto free_hdr;
+       }
+
        info->hdr = hdr;
        info->len = len;
        return 0;
@@ -2199,6 +2193,47 @@ free_hdr:
        return err;
 }
 
+static void free_copy(struct load_info *info)
+{
+       kfree(info->args);
+       vfree(info->hdr);
+}
+
+static int rewrite_section_headers(struct load_info *info)
+{
+       unsigned int i;
+
+       /* This should always be true, but let's be sure. */
+       info->sechdrs[0].sh_addr = 0;
+
+       for (i = 1; i < info->hdr->e_shnum; i++) {
+               Elf_Shdr *shdr = &info->sechdrs[i];
+               if (shdr->sh_type != SHT_NOBITS
+                   && info->len < shdr->sh_offset + shdr->sh_size) {
+                       printk(KERN_ERR "Module len %lu truncated\n",
+                              info->len);
+                       return -ENOEXEC;
+               }
+
+               /* Mark all sections sh_addr with their address in the
+                  temporary image. */
+               shdr->sh_addr = (size_t)info->hdr + shdr->sh_offset;
+
+#ifndef CONFIG_MODULE_UNLOAD
+               /* Don't load .exit sections */
+               if (strstarts(info->secstrings+shdr->sh_name, ".exit"))
+                       shdr->sh_flags &= ~(unsigned long)SHF_ALLOC;
+#endif
+       }
+
+       /* Track but don't keep modinfo and version sections. */
+       info->index.vers = find_sec(info->hdr, info->sechdrs, info->secstrings, "__versions");
+       info->index.info = find_sec(info->hdr, info->sechdrs, info->secstrings, ".modinfo");
+       info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
+       info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
+       return 0;
+}
+
 /*
  * Set up our basic convenience variables (pointers to section headers,
  * search for module section index etc), and do some basic section
@@ -2210,33 +2245,27 @@ free_hdr:
 static struct module *setup_load_info(struct load_info *info)
 {
        unsigned int i;
+       int err;
        struct module *mod;
 
        /* Set up the convenience variables */
        info->sechdrs = (void *)info->hdr + info->hdr->e_shoff;
-       info->secstrings = (void *)info->hdr + info->sechdrs[info->hdr->e_shstrndx].sh_offset;
-       info->sechdrs[0].sh_addr = 0;
+       info->secstrings = (void *)info->hdr
+               + info->sechdrs[info->hdr->e_shstrndx].sh_offset;
 
-       for (i = 1; i < info->hdr->e_shnum; i++) {
-               if (info->sechdrs[i].sh_type != SHT_NOBITS
-                   && info->len < info->sechdrs[i].sh_offset + info->sechdrs[i].sh_size)
-                       goto truncated;
-
-               /* Mark all sections sh_addr with their address in the
-                  temporary image. */
-               info->sechdrs[i].sh_addr = (size_t)info->hdr + info->sechdrs[i].sh_offset;
+       err = rewrite_section_headers(info);
+       if (err)
+               return ERR_PTR(err);
 
-               /* Internal symbols and strings. */
+       /* Find internal symbols and strings. */
+       for (i = 1; i < info->hdr->e_shnum; i++) {
                if (info->sechdrs[i].sh_type == SHT_SYMTAB) {
                        info->index.sym = i;
                        info->index.str = info->sechdrs[i].sh_link;
-                       info->strtab = (char *)info->hdr + info->sechdrs[info->index.str].sh_offset;
+                       info->strtab = (char *)info->hdr
+                               + info->sechdrs[info->index.str].sh_offset;
+                       break;
                }
-#ifndef CONFIG_MODULE_UNLOAD
-               /* Don't load .exit sections */
-               if (strstarts(info->secstrings+info->sechdrs[i].sh_name, ".exit"))
-                       info->sechdrs[i].sh_flags &= ~(unsigned long)SHF_ALLOC;
-#endif
        }
 
        info->index.mod = find_sec(info->hdr, info->sechdrs, info->secstrings,
@@ -2254,23 +2283,13 @@ static struct module *setup_load_info(struct load_info *info)
                return ERR_PTR(-ENOEXEC);
        }
 
-       info->index.vers = find_sec(info->hdr, info->sechdrs, info->secstrings, "__versions");
-       info->index.info = find_sec(info->hdr, info->sechdrs, info->secstrings, ".modinfo");
        info->index.pcpu = find_pcpusec(info->hdr, info->sechdrs, info->secstrings);
 
-       /* Don't keep modinfo and version sections. */
-       info->sechdrs[info->index.info].sh_flags &= ~(unsigned long)SHF_ALLOC;
-       info->sechdrs[info->index.vers].sh_flags &= ~(unsigned long)SHF_ALLOC;
-
        /* Check module struct version now, before we try to use module. */
        if (!check_modstruct_version(info->sechdrs, info->index.vers, mod))
                return ERR_PTR(-ENOEXEC);
 
        return mod;
-
- truncated:
-       printk(KERN_ERR "Module len %lu truncated\n", info->len);
-       return ERR_PTR(-ENOEXEC);
 }
 
 static int check_modinfo(struct module *mod,
@@ -2373,9 +2392,9 @@ static void find_module_sections(struct module *mod, Elf_Ehdr *hdr,
                       mod->name);
 }
 
-static struct module *move_module(struct module *mod,
-                                 Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
-                                 const char *secstrings, unsigned modindex)
+static int move_module(struct module *mod,
+                      Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
+                      const char *secstrings, unsigned modindex)
 {
        int i;
        void *ptr;
@@ -2389,7 +2408,7 @@ static struct module *move_module(struct module *mod,
         */
        kmemleak_not_leak(ptr);
        if (!ptr)
-               return ERR_PTR(-ENOMEM);
+               return -ENOMEM;
 
        memset(ptr, 0, mod->core_size);
        mod->module_core = ptr;
@@ -2404,7 +2423,7 @@ static struct module *move_module(struct module *mod,
        kmemleak_ignore(ptr);
        if (!ptr && mod->init_size) {
                module_free(mod, mod->module_core);
-               return ERR_PTR(-ENOMEM);
+               return -ENOMEM;
        }
        memset(ptr, 0, mod->init_size);
        mod->module_init = ptr;
@@ -2431,10 +2450,8 @@ static struct module *move_module(struct module *mod,
                DEBUGP("\t0x%lx %s\n",
                       sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name);
        }
-       /* Module has been moved. */
-       mod = (void *)sechdrs[modindex].sh_addr;
-       kmemleak_load_module(mod, hdr, sechdrs, secstrings);
-       return mod;
+
+       return 0;
 }
 
 static int check_module_license_and_versions(struct module *mod,
@@ -2491,87 +2508,107 @@ static void flush_module_icache(const struct module *mod)
        set_fs(old_fs);
 }
 
-/* Allocate and load the module: note that size of section 0 is always
-   zero, and we rely on this for optional sections. */
-static noinline struct module *load_module(void __user *umod,
-                                 unsigned long len,
-                                 const char __user *uargs)
+static struct module *layout_and_allocate(struct load_info *info)
 {
-       struct load_info info = { NULL, };
+       /* Module within temporary copy. */
        struct module *mod;
-       long err;
-       unsigned long symoffs, stroffs, *strmap;
-       void __percpu *percpu;
-       struct _ddebug *debug = NULL;
-       unsigned int num_debug = 0;
+       int err;
 
-       DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
-              umod, len, uargs);
+       mod = setup_load_info(info);
+       if (IS_ERR(mod))
+               return mod;
 
-       err = copy_and_check(&info, umod, len);
+       err = check_modinfo(mod, info->sechdrs, info->index.info, info->index.vers);
        if (err)
                return ERR_PTR(err);
 
-       mod = setup_load_info(&info);
-       if (IS_ERR(mod)) {
-               err = PTR_ERR(mod);
-               goto free_hdr;
-       }
-
-       err = check_modinfo(mod, info.sechdrs, info.index.info, info.index.vers);
-       if (err)
-               goto free_hdr;
-
-       /* Now copy in args */
-       info.args = strndup_user(uargs, ~0UL >> 1);
-       if (IS_ERR(info.args)) {
-               err = PTR_ERR(info.args);
-               goto free_hdr;
-       }
-
-       strmap = kzalloc(BITS_TO_LONGS(info.sechdrs[info.index.str].sh_size)
-                        * sizeof(long), GFP_KERNEL);
-       if (!strmap) {
-               err = -ENOMEM;
-               goto free_mod;
-       }
-
-       mod->state = MODULE_STATE_COMING;
-
        /* Allow arches to frob section contents and sizes.  */
-       err = module_frob_arch_sections(info.hdr, info.sechdrs, info.secstrings, mod);
+       err = module_frob_arch_sections(info->hdr, info->sechdrs, info->secstrings, mod);
        if (err < 0)
-               goto free_mod;
+               goto free_args;
 
-       if (info.index.pcpu) {
+       if (info->index.pcpu) {
                /* We have a special allocation for this section. */
-               err = percpu_modalloc(mod, info.sechdrs[info.index.pcpu].sh_size,
-                                     info.sechdrs[info.index.pcpu].sh_addralign);
+               err = percpu_modalloc(mod, info->sechdrs[info->index.pcpu].sh_size,
+                                     info->sechdrs[info->index.pcpu].sh_addralign);
                if (err)
-                       goto free_mod;
-               info.sechdrs[info.index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC;
+                       goto free_args;
+               info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC;
        }
-       /* Keep this around for failure path. */
-       percpu = mod_percpu(mod);
 
        /* Determine total sizes, and put offsets in sh_entsize.  For now
           this is done generically; there doesn't appear to be any
           special cases for the architectures. */
-       layout_sections(mod, info.hdr, info.sechdrs, info.secstrings);
-       symoffs = layout_symtab(mod, info.sechdrs, info.index.sym, info.index.str, info.hdr,
-                               info.secstrings, &stroffs, strmap);
+       layout_sections(mod, info->hdr, info->sechdrs, info->secstrings);
+
+       info->strmap = kzalloc(BITS_TO_LONGS(info->sechdrs[info->index.str].sh_size)
+                        * sizeof(long), GFP_KERNEL);
+       if (!info->strmap) {
+               err = -ENOMEM;
+               goto free_percpu;
+       }
+       info->symoffs = layout_symtab(mod, info->sechdrs, info->index.sym, info->index.str, info->hdr,
+                               info->secstrings, &info->stroffs, info->strmap);
 
        /* Allocate and move to the final place */
-       mod = move_module(mod, info.hdr, info.sechdrs, info.secstrings, info.index.mod);
+       err = move_module(mod, info->hdr, info->sechdrs, info->secstrings, info->index.mod);
+       if (err)
+               goto free_strmap;
+
+       /* 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->hdr, info->sechdrs, info->secstrings);
+       return mod;
+
+free_strmap:
+       kfree(info->strmap);
+free_percpu:
+       percpu_modfree(mod);
+free_args:
+       kfree(info->args);
+       return ERR_PTR(err);
+}
+
+/* mod is no longer valid after this! */
+static void module_deallocate(struct module *mod, struct load_info *info)
+{
+       kfree(info->strmap);
+       percpu_modfree(mod);
+       module_free(mod, mod->module_init);
+       module_free(mod, mod->module_core);
+}
+
+/* Allocate and load the module: note that size of section 0 is always
+   zero, and we rely on this for optional sections. */
+static noinline struct module *load_module(void __user *umod,
+                                 unsigned long len,
+                                 const char __user *uargs)
+{
+       struct load_info info = { NULL, };
+       struct module *mod;
+       long err;
+       struct _ddebug *debug = NULL;
+       unsigned int num_debug = 0;
+
+       DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
+              umod, len, uargs);
+
+       /* Copy in the blobs from userspace, check they are vaguely sane. */
+       err = copy_and_check(&info, umod, len, uargs);
+       if (err)
+               return ERR_PTR(err);
+
+       /* Figure out module layout, and allocate all the memory. */
+       mod = layout_and_allocate(&info);
        if (IS_ERR(mod)) {
                err = PTR_ERR(mod);
-               goto free_percpu;
+               goto free_copy;
        }
 
        /* Now we've moved module, initialize linked lists, etc. */
        err = module_unload_init(mod);
        if (err)
-               goto free_init;
+               goto free_module;
 
        /* Now we've got everything in the final locations, we can
         * find optional sections. */
@@ -2588,11 +2625,11 @@ static noinline struct module *load_module(void __user *umod,
        err = simplify_symbols(info.sechdrs, info.index.sym, info.strtab, info.index.vers, info.index.pcpu,
                               mod);
        if (err < 0)
-               goto cleanup;
+               goto free_modinfo;
 
        err = apply_relocations(mod, info.hdr, info.sechdrs, info.index.sym, info.index.str);
        if (err < 0)
-               goto cleanup;
+               goto free_modinfo;
 
        /* Set up and sort exception table */
        mod->extable = section_objs(info.hdr, info.sechdrs, info.secstrings, "__ex_table",
@@ -2603,10 +2640,7 @@ static noinline struct module *load_module(void __user *umod,
        percpu_modcopy(mod, (void *)info.sechdrs[info.index.pcpu].sh_addr,
                       info.sechdrs[info.index.pcpu].sh_size);
 
-       add_kallsyms(mod, info.sechdrs, info.hdr->e_shnum, info.index.sym, info.index.str,
-                    symoffs, stroffs, info.secstrings, strmap);
-       kfree(strmap);
-       strmap = NULL;
+       add_kallsyms(mod, &info);
 
        if (!mod->taints)
                debug = section_objs(info.hdr, info.sechdrs, info.secstrings, "__verbose",
@@ -2614,12 +2648,14 @@ static noinline struct module *load_module(void __user *umod,
 
        err = module_finalize(info.hdr, info.sechdrs, mod);
        if (err < 0)
-               goto cleanup;
+               goto free_modinfo;
 
        flush_module_icache(mod);
 
        mod->args = info.args;
 
+       mod->state = MODULE_STATE_COMING;
+
        /* 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.
@@ -2648,15 +2684,13 @@ static noinline struct module *load_module(void __user *umod,
        if (err < 0)
                goto unlink;
 
-       err = mod_sysfs_setup(mod, mod->kp, mod->num_kp);
+       err = mod_sysfs_setup(mod, &info, mod->kp, mod->num_kp);
        if (err < 0)
                goto unlink;
 
-       add_sect_attrs(mod, info.hdr->e_shnum, info.secstrings, info.sechdrs);
-       add_notes_attrs(mod, info.hdr->e_shnum, info.secstrings, info.sechdrs);
-
-       /* Get rid of temporary copy */
-       vfree(info.hdr);
+       /* Get rid of temporary copy and strmap. */
+       kfree(info.strmap);
+       free_copy(&info);
 
        trace_module_load(mod);
 
@@ -2673,21 +2707,14 @@ static noinline struct module *load_module(void __user *umod,
        mutex_unlock(&module_mutex);
        synchronize_sched();
        module_arch_cleanup(mod);
cleanup:
free_modinfo:
        free_modinfo(mod);
  free_unload:
        module_unload_free(mod);
- free_init:
-       module_free(mod, mod->module_init);
-       module_free(mod, mod->module_core);
-       /* mod will be freed with core. Don't access it beyond this line! */
- free_percpu:
-       free_percpu(percpu);
- free_mod:
-       kfree(info.args);
-       kfree(strmap);
- free_hdr:
-       vfree(info.hdr);
+ free_module:
+       module_deallocate(mod, &info);
+ free_copy:
+       free_copy(&info);
        return ERR_PTR(err);
 }