Merge branch 'for-linus' of git://git390.osdl.marist.edu/pub/scm/linux-2.6
[pandora-kernel.git] / kernel / module.c
index db0ead0..3202c99 100644 (file)
@@ -20,6 +20,7 @@
 #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>
@@ -104,7 +105,7 @@ void __module_put_and_exit(struct module *mod, long code)
        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,
@@ -178,7 +179,7 @@ static unsigned long __find_symbol(const char *name,
        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) {
@@ -230,7 +231,7 @@ static unsigned long __find_symbol(const char *name,
                return ks->value;
        }
 
-       /* Now try modules. */ 
+       /* Now try modules. */
        list_for_each_entry(mod, &modules, list) {
                *owner = mod;
                ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);
@@ -284,7 +285,7 @@ static unsigned long __find_symbol(const char *name,
                }
        }
        DEBUGP("Failed to find symbol %s\n", name);
-       return 0;
+       return 0;
 }
 
 /* Search for module by name: must hold module_mutex. */
@@ -440,7 +441,7 @@ static int percpu_modinit(void)
        }
 
        return 0;
-}      
+}
 __initcall(percpu_modinit);
 #else /* ... !CONFIG_SMP */
 static inline void *percpu_modalloc(unsigned long size, unsigned long align,
@@ -482,8 +483,8 @@ static int modinfo_##field##_exists(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 = {                    \
        .attr = { .name = __stringify(field), .mode = 0444 },         \
@@ -692,8 +693,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 ((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 */
@@ -741,11 +741,6 @@ static void print_unload_info(struct seq_file *m, struct module *mod)
                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],");
@@ -995,7 +990,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;
-       
+
        /* Count loaded sections and allocate structures */
        for (i = 0; i < nsect; i++)
                if (sechdrs[i].sh_flags & SHF_ALLOC)
@@ -1053,6 +1048,100 @@ static void remove_sect_attrs(struct module *mod)
        }
 }
 
+/*
+ * /sys/module/foo/notes/.section.name gives contents of SHT_NOTE sections.
+ */
+
+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 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_add_dir(&mod->mkobj.kobj, "notes");
+       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);
+}
+
 #else
 
 static inline void add_sect_attrs(struct module *mod, unsigned int nsect,
@@ -1063,6 +1152,15 @@ static inline void add_sect_attrs(struct module *mod, unsigned int nsect,
 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 remove_notes_attrs(struct module *mod)
+{
+}
 #endif /* CONFIG_KALLSYMS */
 
 #ifdef CONFIG_SYSFS
@@ -1197,6 +1295,7 @@ 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);
 
@@ -1249,14 +1348,14 @@ static int verify_export_symbols(struct module *mod)
        const unsigned long *crc;
 
        for (i = 0; i < mod->num_syms; i++)
-               if (__find_symbol(mod->syms[i].name, &owner, &crc, 1)) {
+               if (__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++)
-               if (__find_symbol(mod->gpl_syms[i].name, &owner, &crc, 1)) {
+               if (__find_symbol(mod->gpl_syms[i].name, &owner, &crc, 1)) {
                        name = mod->gpl_syms[i].name;
                        ret = -ENOEXEC;
                        goto dup;
@@ -1574,6 +1673,8 @@ static struct module *load_module(void __user *umod,
        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 */
@@ -1782,7 +1883,8 @@ static struct module *load_module(void __user *umod,
        module_unload_init(mod);
 
        /* Initialize kobject, so we can reference it. */
-       if (mod_sysfs_init(mod) != 0)
+       err = mod_sysfs_init(mod);
+       if (err)
                goto cleanup;
 
        /* Set up license info based on the info section */
@@ -1829,7 +1931,7 @@ static struct module *load_module(void __user *umod,
                mod->unused_crcs = (void *)sechdrs[unusedgplcrcindex].sh_addr;
 
 #ifdef CONFIG_MODVERSIONS
-       if ((mod->num_syms && !crcindex) || 
+       if ((mod->num_syms && !crcindex) ||
            (mod->num_gpl_syms && !gplcrcindex) ||
            (mod->num_gpl_future_syms && !gplfuturecrcindex) ||
            (mod->num_unused_syms && !unusedcrcindex) ||
@@ -1839,6 +1941,9 @@ static struct module *load_module(void __user *umod,
                add_taint_module(mod, TAINT_FORCED_MODULE);
        }
 #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++) {
@@ -1861,6 +1966,11 @@ static struct module *load_module(void __user *umod,
                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);
@@ -1879,6 +1989,11 @@ static struct module *load_module(void __user *umod,
 
        add_kallsyms(mod, sechdrs, symindex, strindex, secstrings);
 
+#ifdef CONFIG_MARKERS
+       if (!mod->taints)
+               marker_update_probe_range(mod->markers,
+                       mod->markers + mod->num_markers, NULL, NULL);
+#endif
        err = module_finalize(hdr, sechdrs, mod);
        if (err < 0)
                goto cleanup;
@@ -1916,7 +2031,7 @@ static struct module *load_module(void __user *umod,
        if (err < 0)
                goto arch_cleanup;
 
-       err = mod_sysfs_setup(mod, 
+       err = mod_sysfs_setup(mod,
                              (struct kernel_param *)
                              sechdrs[setupindex].sh_addr,
                              sechdrs[setupindex].sh_size
@@ -1924,11 +2039,12 @@ static struct module *load_module(void __user *umod,
        if (err < 0)
                goto arch_cleanup;
        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);
+                                           (void *)sechdrs[unwindex].sh_addr,
+                                           sechdrs[unwindex].sh_size);
 
        /* Get rid of temporary copy */
        vfree(hdr);
@@ -2011,15 +2127,10 @@ sys_init_module(void __user *umod,
                    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);
-                       mutex_lock(&module_mutex);
-                       free_module(mod);
-                       mutex_unlock(&module_mutex);
-               }
+               module_put(mod);
+               mutex_lock(&module_mutex);
+               free_module(mod);
+               mutex_unlock(&module_mutex);
                return ret;
        }
 
@@ -2050,7 +2161,7 @@ static inline int within(unsigned long addr, void *start, unsigned long size)
  */
 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] == '.');
 }
 
@@ -2065,11 +2176,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;
-       else 
+       else
                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;
@@ -2311,7 +2422,7 @@ const struct exception_table_entry *search_module_extables(unsigned long addr)
        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);
@@ -2321,7 +2432,7 @@ const struct exception_table_entry *search_module_extables(unsigned long addr)
        preempt_enable();
 
        /* 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;
 }
 
@@ -2474,3 +2585,18 @@ EXPORT_SYMBOL(module_remove_driver);
 void struct_module(struct module *mod) { return; }
 EXPORT_SYMBOL(struct_module);
 #endif
+
+#ifdef CONFIG_MARKERS
+void module_update_markers(struct module *probe_module, int *refcount)
+{
+       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,
+                               probe_module, refcount);
+       mutex_unlock(&module_mutex);
+}
+#endif