smp: Convert smplocks to raw_spinlocks
[linux-3.10.git] / kernel / module.c
index 215aaab..12afc5a 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/rculist.h>
 #include <asm/uaccess.h>
 #include <asm/cacheflush.h>
+#include <asm/mmu_context.h>
 #include <linux/license.h>
 #include <asm/sections.h>
 #include <linux/tracepoint.h>
 #include <linux/percpu.h>
 #include <linux/kmemleak.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/module.h>
+
+EXPORT_TRACEPOINT_SYMBOL(module_get);
+
 #if 0
 #define DEBUGP printk
 #else
@@ -364,8 +370,6 @@ EXPORT_SYMBOL_GPL(find_module);
 
 #ifdef CONFIG_SMP
 
-#ifdef CONFIG_HAVE_DYNAMIC_PER_CPU_AREA
-
 static void *percpu_modalloc(unsigned long size, unsigned long align,
                             const char *name)
 {
@@ -389,154 +393,6 @@ static void percpu_modfree(void *freeme)
        free_percpu(freeme);
 }
 
-#else /* ... !CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
-
-/* Number of blocks used and allocated. */
-static unsigned int pcpu_num_used, pcpu_num_allocated;
-/* Size of each block.  -ve means used. */
-static int *pcpu_size;
-
-static int split_block(unsigned int i, unsigned short size)
-{
-       /* Reallocation required? */
-       if (pcpu_num_used + 1 > pcpu_num_allocated) {
-               int *new;
-
-               new = krealloc(pcpu_size, sizeof(new[0])*pcpu_num_allocated*2,
-                              GFP_KERNEL);
-               if (!new)
-                       return 0;
-
-               pcpu_num_allocated *= 2;
-               pcpu_size = new;
-       }
-
-       /* Insert a new subblock */
-       memmove(&pcpu_size[i+1], &pcpu_size[i],
-               sizeof(pcpu_size[0]) * (pcpu_num_used - i));
-       pcpu_num_used++;
-
-       pcpu_size[i+1] -= size;
-       pcpu_size[i] = size;
-       return 1;
-}
-
-static inline unsigned int block_size(int val)
-{
-       if (val < 0)
-               return -val;
-       return val;
-}
-
-static void *percpu_modalloc(unsigned long size, unsigned long align,
-                            const char *name)
-{
-       unsigned long extra;
-       unsigned int i;
-       void *ptr;
-       int cpu;
-
-       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;
-       for (i = 0; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) {
-               /* Extra for alignment requirement. */
-               extra = ALIGN((unsigned long)ptr, align) - (unsigned long)ptr;
-               BUG_ON(i == 0 && extra != 0);
-
-               if (pcpu_size[i] < 0 || pcpu_size[i] < extra + size)
-                       continue;
-
-               /* Transfer extra to previous block. */
-               if (pcpu_size[i-1] < 0)
-                       pcpu_size[i-1] -= extra;
-               else
-                       pcpu_size[i-1] += extra;
-               pcpu_size[i] -= extra;
-               ptr += extra;
-
-               /* Split block if warranted */
-               if (pcpu_size[i] - size > sizeof(unsigned long))
-                       if (!split_block(i, size))
-                               return NULL;
-
-               /* add the per-cpu scanning areas */
-               for_each_possible_cpu(cpu)
-                       kmemleak_alloc(ptr + per_cpu_offset(cpu), size, 0,
-                                      GFP_KERNEL);
-
-               /* Mark allocated */
-               pcpu_size[i] = -pcpu_size[i];
-               return ptr;
-       }
-
-       printk(KERN_WARNING "Could not allocate %lu bytes percpu data\n",
-              size);
-       return NULL;
-}
-
-static void percpu_modfree(void *freeme)
-{
-       unsigned int i;
-       void *ptr = __per_cpu_start + block_size(pcpu_size[0]);
-       int cpu;
-
-       /* First entry is core kernel percpu data. */
-       for (i = 1; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) {
-               if (ptr == freeme) {
-                       pcpu_size[i] = -pcpu_size[i];
-                       goto free;
-               }
-       }
-       BUG();
-
- free:
-       /* remove the per-cpu scanning areas */
-       for_each_possible_cpu(cpu)
-               kmemleak_free(freeme + per_cpu_offset(cpu));
-
-       /* Merge with previous? */
-       if (pcpu_size[i-1] >= 0) {
-               pcpu_size[i-1] += pcpu_size[i];
-               pcpu_num_used--;
-               memmove(&pcpu_size[i], &pcpu_size[i+1],
-                       (pcpu_num_used - i) * sizeof(pcpu_size[0]));
-               i--;
-       }
-       /* Merge with next? */
-       if (i+1 < pcpu_num_used && pcpu_size[i+1] >= 0) {
-               pcpu_size[i] += pcpu_size[i+1];
-               pcpu_num_used--;
-               memmove(&pcpu_size[i+1], &pcpu_size[i+2],
-                       (pcpu_num_used - (i+1)) * sizeof(pcpu_size[0]));
-       }
-}
-
-static int percpu_modinit(void)
-{
-       pcpu_num_used = 2;
-       pcpu_num_allocated = 2;
-       pcpu_size = kmalloc(sizeof(pcpu_size[0]) * pcpu_num_allocated,
-                           GFP_KERNEL);
-       /* Static in-kernel percpu data (used). */
-       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) {
-               printk(KERN_ERR "No per-cpu room for modules.\n");
-               pcpu_num_used = 1;
-       }
-
-       return 0;
-}
-__initcall(percpu_modinit);
-
-#endif /* CONFIG_HAVE_DYNAMIC_PER_CPU_AREA */
-
 static unsigned int find_pcpusec(Elf_Ehdr *hdr,
                                 Elf_Shdr *sechdrs,
                                 const char *secstrings)
@@ -909,16 +765,18 @@ void __symbol_put(const char *symbol)
 }
 EXPORT_SYMBOL(__symbol_put);
 
+/* Note this assumes addr is a function, which it currently always is. */
 void symbol_put_addr(void *addr)
 {
        struct module *modaddr;
+       unsigned long a = (unsigned long)dereference_function_descriptor(addr);
 
-       if (core_kernel_text((unsigned long)addr))
+       if (core_kernel_text(a))
                return;
 
        /* module_text_address is safe here: we're supposed to have reference
         * to module from symbol_get, so it can't go away. */
-       modaddr = __module_text_address((unsigned long)addr);
+       modaddr = __module_text_address(a);
        BUG_ON(!modaddr);
        module_put(modaddr);
 }
@@ -940,6 +798,8 @@ void module_put(struct module *module)
        if (module) {
                unsigned int cpu = get_cpu();
                local_dec(__module_ref_addr(module, cpu));
+               trace_module_put(module, _RET_IP_,
+                                local_read(__module_ref_addr(module, cpu)));
                /* Maybe they're waiting for us to drop reference? */
                if (unlikely(!module_is_live(module)))
                        wake_up_process(module->waiter);
@@ -1068,7 +928,8 @@ static inline int check_modstruct_version(Elf_Shdr *sechdrs,
 {
        const unsigned long *crc;
 
-       if (!find_symbol("module_layout", NULL, &crc, true, false))
+       if (!find_symbol(MODULE_SYMBOL_PREFIX "module_layout", NULL,
+                        &crc, true, false))
                BUG();
        return check_version(sechdrs, versindex, "module_layout", mod, crc);
 }
@@ -1176,7 +1037,8 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
 
        /* Count loaded sections and allocate structures */
        for (i = 0; i < nsect; i++)
-               if (sechdrs[i].sh_flags & SHF_ALLOC)
+               if (sechdrs[i].sh_flags & SHF_ALLOC
+                   && sechdrs[i].sh_size)
                        nloaded++;
        size[0] = ALIGN(sizeof(*sect_attrs)
                        + nloaded * sizeof(sect_attrs->attrs[0]),
@@ -1196,6 +1058,8 @@ static void add_sect_attrs(struct module *mod, unsigned int nsect,
        for (i = 0; i < nsect; i++) {
                if (! (sechdrs[i].sh_flags & SHF_ALLOC))
                        continue;
+               if (!sechdrs[i].sh_size)
+                       continue;
                sattr->address = sechdrs[i].sh_addr;
                sattr->name = kstrdup(secstrings + sechdrs[i].sh_name,
                                        GFP_KERNEL);
@@ -1271,6 +1135,10 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect,
        struct module_notes_attrs *notes_attrs;
        struct bin_attribute *nattr;
 
+       /* failed to create section attributes, so can't create notes */
+       if (!mod->sect_attrs)
+               return;
+
        /* Count notes sections and allocate structures.  */
        notes = 0;
        for (i = 0; i < nsect; i++)
@@ -1490,6 +1358,8 @@ static int __unlink_module(void *_mod)
 /* Free a module, remove from lists, etc (must hold module_mutex). */
 static void free_module(struct module *mod)
 {
+       trace_module_free(mod);
+
        /* Delete from various lists */
        stop_machine(__unlink_module, mod, NULL);
        remove_notes_attrs(mod);
@@ -1519,6 +1389,10 @@ static void free_module(struct module *mod)
 
        /* Finally, free the core (containing the module structure) */
        module_free(mod, mod->module_core);
+
+#ifdef CONFIG_MPU
+       update_protections(current->mm);
+#endif
 }
 
 void *__symbol_get(const char *symbol)
@@ -1776,6 +1650,17 @@ static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
        }
 }
 
+static void free_modinfo(struct module *mod)
+{
+       struct module_attribute *attr;
+       int i;
+
+       for (i = 0; (attr = modinfo_attrs[i]); i++) {
+               if (attr->free)
+                       attr->free(mod);
+       }
+}
+
 #ifdef CONFIG_KALLSYMS
 
 /* lookup symbol in given range of kernel_symbols */
@@ -1841,13 +1726,93 @@ static char elf_type(const Elf_Sym *sym,
        return '?';
 }
 
+static bool is_core_symbol(const Elf_Sym *src, const Elf_Shdr *sechdrs,
+                           unsigned int shnum)
+{
+       const Elf_Shdr *sec;
+
+       if (src->st_shndx == SHN_UNDEF
+           || src->st_shndx >= shnum
+           || !src->st_name)
+               return false;
+
+       sec = sechdrs + src->st_shndx;
+       if (!(sec->sh_flags & SHF_ALLOC)
+#ifndef CONFIG_KALLSYMS_ALL
+           || !(sec->sh_flags & SHF_EXECINSTR)
+#endif
+           || (sec->sh_entsize & INIT_OFFSET_MASK))
+               return false;
+
+       return true;
+}
+
+static unsigned long layout_symtab(struct module *mod,
+                                  Elf_Shdr *sechdrs,
+                                  unsigned int symindex,
+                                  unsigned int strindex,
+                                  const Elf_Ehdr *hdr,
+                                  const char *secstrings,
+                                  unsigned long *pstroffs,
+                                  unsigned long *strmap)
+{
+       unsigned long symoffs;
+       Elf_Shdr *symsect = sechdrs + symindex;
+       Elf_Shdr *strsect = sechdrs + strindex;
+       const Elf_Sym *src;
+       const char *strtab;
+       unsigned int i, nsrc, ndst;
+
+       /* Put symbol section at end of init part of module. */
+       symsect->sh_flags |= SHF_ALLOC;
+       symsect->sh_entsize = get_offset(mod, &mod->init_size, symsect,
+                                        symindex) | INIT_OFFSET_MASK;
+       DEBUGP("\t%s\n", secstrings + symsect->sh_name);
+
+       src = (void *)hdr + symsect->sh_offset;
+       nsrc = symsect->sh_size / sizeof(*src);
+       strtab = (void *)hdr + strsect->sh_offset;
+       for (ndst = i = 1; i < nsrc; ++i, ++src)
+               if (is_core_symbol(src, sechdrs, hdr->e_shnum)) {
+                       unsigned int j = src->st_name;
+
+                       while(!__test_and_set_bit(j, strmap) && strtab[j])
+                               ++j;
+                       ++ndst;
+               }
+
+       /* Append room for core symbols at end of core part. */
+       symoffs = ALIGN(mod->core_size, symsect->sh_addralign ?: 1);
+       mod->core_size = symoffs + ndst * sizeof(Elf_Sym);
+
+       /* Put string table section at end of init part of module. */
+       strsect->sh_flags |= SHF_ALLOC;
+       strsect->sh_entsize = get_offset(mod, &mod->init_size, strsect,
+                                        strindex) | INIT_OFFSET_MASK;
+       DEBUGP("\t%s\n", secstrings + strsect->sh_name);
+
+       /* Append room for core symbols' strings at end of core part. */
+       *pstroffs = mod->core_size;
+       __set_bit(0, strmap);
+       mod->core_size += bitmap_weight(strmap, strsect->sh_size);
+
+       return symoffs;
+}
+
 static void add_kallsyms(struct module *mod,
                         Elf_Shdr *sechdrs,
+                        unsigned int shnum,
                         unsigned int symindex,
                         unsigned int strindex,
-                        const char *secstrings)
+                        unsigned long symoffs,
+                        unsigned long stroffs,
+                        const char *secstrings,
+                        unsigned long *strmap)
 {
-       unsigned int i;
+       unsigned int i, ndst;
+       const Elf_Sym *src;
+       Elf_Sym *dst;
+       char *s;
 
        mod->symtab = (void *)sechdrs[symindex].sh_addr;
        mod->num_symtab = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
@@ -1857,13 +1822,46 @@ static void add_kallsyms(struct module *mod,
        for (i = 0; i < mod->num_symtab; i++)
                mod->symtab[i].st_info
                        = elf_type(&mod->symtab[i], sechdrs, secstrings, mod);
+
+       mod->core_symtab = dst = mod->module_core + symoffs;
+       src = mod->symtab;
+       *dst = *src;
+       for (ndst = i = 1; i < mod->num_symtab; ++i, ++src) {
+               if (!is_core_symbol(src, sechdrs, shnum))
+                       continue;
+               dst[ndst] = *src;
+               dst[ndst].st_name = bitmap_weight(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))
+                       *++s = mod->strtab[i];
 }
 #else
+static inline unsigned long layout_symtab(struct module *mod,
+                                         Elf_Shdr *sechdrs,
+                                         unsigned int symindex,
+                                         unsigned int strindex,
+                                         const Elf_Ehdr *hdr,
+                                         const char *secstrings,
+                                         unsigned long *pstroffs,
+                                         unsigned long *strmap)
+{
+       return 0;
+}
+
 static inline void add_kallsyms(struct module *mod,
                                Elf_Shdr *sechdrs,
+                               unsigned int shnum,
                                unsigned int symindex,
                                unsigned int strindex,
-                               const char *secstrings)
+                               unsigned long symoffs,
+                               unsigned long stroffs,
+                               const char *secstrings,
+                               const unsigned long *strmap)
 {
 }
 #endif /* CONFIG_KALLSYMS */
@@ -1938,6 +1936,8 @@ static noinline struct module *load_module(void __user *umod,
        struct module *mod;
        long err = 0;
        void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
+       unsigned long symoffs, stroffs, *strmap;
+
        mm_segment_t old_fs;
 
        DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n",
@@ -2019,11 +2019,6 @@ static noinline struct module *load_module(void __user *umod,
        /* Don't keep modinfo and version sections. */
        sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
        sechdrs[versindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
-#ifdef CONFIG_KALLSYMS
-       /* Keep symbol and string tables for decoding later. */
-       sechdrs[symindex].sh_flags |= SHF_ALLOC;
-       sechdrs[strindex].sh_flags |= SHF_ALLOC;
-#endif
 
        /* Check module struct version now, before we try to use module. */
        if (!check_modstruct_version(sechdrs, versindex, mod)) {
@@ -2059,6 +2054,13 @@ static noinline struct module *load_module(void __user *umod,
                goto free_hdr;
        }
 
+       strmap = kzalloc(BITS_TO_LONGS(sechdrs[strindex].sh_size)
+                        * sizeof(long), GFP_KERNEL);
+       if (!strmap) {
+               err = -ENOMEM;
+               goto free_mod;
+       }
+
        if (find_module(mod->name)) {
                err = -EEXIST;
                goto free_mod;
@@ -2088,6 +2090,8 @@ static noinline struct module *load_module(void __user *umod,
           this is done generically; there doesn't appear to be any
           special cases for the architectures. */
        layout_sections(mod, hdr, sechdrs, secstrings);
+       symoffs = layout_symtab(mod, sechdrs, symindex, strindex, hdr,
+                               secstrings, &stroffs, strmap);
 
        /* Do the allocs. */
        ptr = module_alloc_update_bounds(mod->core_size);
@@ -2216,11 +2220,11 @@ static noinline struct module *load_module(void __user *umod,
        mod->unused_gpl_crcs = section_addr(hdr, sechdrs, secstrings,
                                            "__kcrctab_unused_gpl");
 #endif
-
-#ifdef CONFIG_MARKERS
-       mod->markers = section_objs(hdr, sechdrs, secstrings, "__markers",
-                                   sizeof(*mod->markers), &mod->num_markers);
+#ifdef CONFIG_CONSTRUCTORS
+       mod->ctors = section_objs(hdr, sechdrs, secstrings, ".ctors",
+                                 sizeof(*mod->ctors), &mod->num_ctors);
 #endif
+
 #ifdef CONFIG_TRACEPOINTS
        mod->tracepoints = section_objs(hdr, sechdrs, secstrings,
                                        "__tracepoints",
@@ -2292,7 +2296,10 @@ static noinline struct module *load_module(void __user *umod,
        percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr,
                       sechdrs[pcpuindex].sh_size);
 
-       add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
+       add_kallsyms(mod, sechdrs, hdr->e_shnum, symindex, strindex,
+                    symoffs, stroffs, secstrings, strmap);
+       kfree(strmap);
+       strmap = NULL;
 
        if (!mod->taints) {
                struct _ddebug *debug;
@@ -2353,6 +2360,8 @@ static noinline struct module *load_module(void __user *umod,
        /* Get rid of temporary copy */
        vfree(hdr);
 
+       trace_module_load(mod);
+
        /* Done! */
        return mod;
 
@@ -2362,13 +2371,14 @@ static noinline struct module *load_module(void __user *umod,
        synchronize_sched();
        module_arch_cleanup(mod);
  cleanup:
+       free_modinfo(mod);
        kobject_del(&mod->mkobj.kobj);
        kobject_put(&mod->mkobj.kobj);
  free_unload:
        module_unload_free(mod);
 #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
- free_init:
        percpu_modfree(mod->refptr);
+ free_init:
 #endif
        module_free(mod, mod->module_init);
  free_core:
@@ -2379,6 +2389,7 @@ static noinline struct module *load_module(void __user *umod,
                percpu_modfree(percpu);
  free_mod:
        kfree(args);
+       kfree(strmap);
  free_hdr:
        vfree(hdr);
        return ERR_PTR(err);
@@ -2389,6 +2400,17 @@ static noinline struct module *load_module(void __user *umod,
        goto free_hdr;
 }
 
+/* Call module constructors. */
+static void do_mod_ctors(struct module *mod)
+{
+#ifdef CONFIG_CONSTRUCTORS
+       unsigned long i;
+
+       for (i = 0; i < mod->num_ctors; i++)
+               mod->ctors[i]();
+#endif
+}
+
 /* This is where the real work happens */
 SYSCALL_DEFINE3(init_module, void __user *, umod,
                unsigned long, len, const char __user *, uargs)
@@ -2417,6 +2439,7 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
        blocking_notifier_call_chain(&module_notify_list,
                        MODULE_STATE_COMING, mod);
 
+       do_mod_ctors(mod);
        /* Start the module */
        if (mod->init != NULL)
                ret = do_one_initcall(mod->init);
@@ -2435,9 +2458,9 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
                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",
+               printk(KERN_WARNING
+"%s: '%s'->init suspiciously returned %d, it should follow 0/-E convention\n"
+"%s: loading module anyway...\n",
                       __func__, mod->name, ret,
                       __func__);
                dump_stack();
@@ -2456,6 +2479,11 @@ SYSCALL_DEFINE3(init_module, void __user *, umod,
        /* Drop initial reference. */
        module_put(mod);
        trim_init_extable(mod);
+#ifdef CONFIG_KALLSYMS
+       mod->num_symtab = mod->core_num_syms;
+       mod->symtab = mod->core_symtab;
+       mod->strtab = mod->core_strtab;
+#endif
        module_free(mod, mod->module_init);
        mod->module_init = NULL;
        mod->init_size = 0;
@@ -2917,27 +2945,12 @@ void module_layout(struct module *mod,
                   struct modversion_info *ver,
                   struct kernel_param *kp,
                   struct kernel_symbol *ks,
-                  struct marker *marker,
                   struct tracepoint *tp)
 {
 }
 EXPORT_SYMBOL(module_layout);
 #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
-
 #ifdef CONFIG_TRACEPOINTS
 void module_update_tracepoints(void)
 {