]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/module.c
sysfs: fix /sys/module/*/holders after sysfs logic change
[linux-2.6-omap-h63xx.git] / kernel / module.c
index a389b423c279dcb6e5f2b94ffcf56e534b06875e..0ae811785c59dba901eb52d6476113a6e44e4789 100644 (file)
@@ -47,8 +47,6 @@
 #include <asm/cacheflush.h>
 #include <linux/license.h>
 
-extern int module_sysfs_initialized;
-
 #if 0
 #define DEBUGP printk
 #else
@@ -81,7 +79,8 @@ int unregister_module_notifier(struct notifier_block * nb)
 }
 EXPORT_SYMBOL(unregister_module_notifier);
 
-/* We require a truly strong try_module_get() */
+/* 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)
 {
        if (mod && mod->state == MODULE_STATE_COMING)
@@ -105,7 +104,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,
@@ -179,7 +178,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) {
@@ -231,7 +230,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);
@@ -285,7 +284,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. */
@@ -441,7 +440,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,
@@ -483,8 +482,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 },         \
@@ -952,7 +951,8 @@ static unsigned long resolve_symbol(Elf_Shdr *sechdrs,
        ret = __find_symbol(name, &owner, &crc,
                        !(mod->taints & TAINT_PROPRIETARY_MODULE));
        if (ret) {
-               /* use_module can fail due to OOM, or module unloading */
+               /* use_module can fail due to OOM,
+                  or module initialization or unloading */
                if (!check_version(sechdrs, versindex, name, mod, crc) ||
                    !use_module(mod, owner))
                        ret = 0;
@@ -990,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)
@@ -1120,7 +1120,7 @@ static void add_notes_attrs(struct module *mod, unsigned int nsect,
                ++loaded;
        }
 
-       notes_attrs->dir = kobject_add_dir(&mod->mkobj.kobj, "notes");
+       notes_attrs->dir = kobject_create_and_add("notes", &mod->mkobj.kobj);
        if (!notes_attrs->dir)
                goto out;
 
@@ -1221,11 +1221,14 @@ int mod_sysfs_init(struct module *mod)
        err = kobject_set_name(&mod->mkobj.kobj, "%s", mod->name);
        if (err)
                goto out;
-       kobj_set_kset_s(&mod->mkobj, module_subsys);
+       mod->mkobj.kobj.kset = module_kset;
+       mod->mkobj.kobj.ktype = &module_ktype;
        mod->mkobj.mod = mod;
 
        kobject_init(&mod->mkobj.kobj);
 
+       /* delay uevent until full sysfs population */
+       err = kobject_add(&mod->mkobj.kobj);
 out:
        return err;
 }
@@ -1236,12 +1239,7 @@ int mod_sysfs_setup(struct module *mod,
 {
        int err;
 
-       /* delay uevent until full sysfs population */
-       err = kobject_add(&mod->mkobj.kobj);
-       if (err)
-               goto out;
-
-       mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders");
+       mod->holders_dir = kobject_create_and_add("holders", &mod->mkobj.kobj);
        if (!mod->holders_dir) {
                err = -ENOMEM;
                goto out_unreg;
@@ -1265,7 +1263,6 @@ out_unreg_holders:
 out_unreg:
        kobject_del(&mod->mkobj.kobj);
        kobject_put(&mod->mkobj.kobj);
-out:
        return err;
 }
 #endif
@@ -1348,14 +1345,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;
@@ -1369,7 +1366,7 @@ dup:
        return ret;
 }
 
-/* Change all symbols so that sh_value encodes the pointer directly. */
+/* Change all symbols so that st_value encodes the pointer directly. */
 static int simplify_symbols(Elf_Shdr *sechdrs,
                            unsigned int symindex,
                            const char *strtab,
@@ -1673,6 +1670,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 */
@@ -1880,10 +1879,10 @@ static struct module *load_module(void __user *umod,
        /* Now we've moved module, initialize linked lists, etc. */
        module_unload_init(mod);
 
-       /* Initialize kobject, so we can reference it. */
+       /* add kobject, so we can reference it. */
        err = mod_sysfs_init(mod);
        if (err)
-               goto cleanup;
+               goto free_unload;
 
        /* Set up license info based on the info section */
        set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
@@ -1929,7 +1928,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) ||
@@ -1939,6 +1938,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++) {
@@ -1961,6 +1963,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);
@@ -1979,6 +1986,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;
@@ -2016,7 +2028,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
@@ -2028,8 +2040,8 @@ static struct module *load_module(void __user *umod,
 
        /* 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);
@@ -2040,6 +2052,9 @@ static struct module *load_module(void __user *umod,
  arch_cleanup:
        module_arch_cleanup(mod);
  cleanup:
+       kobject_del(&mod->mkobj.kobj);
+       kobject_put(&mod->mkobj.kobj);
+ free_unload:
        module_unload_free(mod);
        module_free(mod, mod->module_init);
  free_core:
@@ -2146,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] == '.');
 }
 
@@ -2161,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;
@@ -2197,29 +2212,34 @@ static const char *get_ksymbol(struct module *mod,
 /* For kallsyms to ask for address resolution.  NULL means not found.
    We don't lock, as this is used for oops resolution and races are a
    lesser concern. */
+/* FIXME: Risky: returns a pointer into a module w/o lock */
 const char *module_address_lookup(unsigned long addr,
                                  unsigned long *size,
                                  unsigned long *offset,
                                  char **modname)
 {
        struct module *mod;
+       const char *ret = NULL;
 
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (within(addr, mod->module_init, mod->init_size)
                    || within(addr, mod->module_core, mod->core_size)) {
                        if (modname)
                                *modname = mod->name;
-                       return get_ksymbol(mod, addr, size, offset);
+                       ret = get_ksymbol(mod, addr, size, offset);
+                       break;
                }
        }
-       return NULL;
+       preempt_enable();
+       return ret;
 }
 
 int lookup_module_symbol_name(unsigned long addr, char *symname)
 {
        struct module *mod;
 
-       mutex_lock(&module_mutex);
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (within(addr, mod->module_init, mod->init_size) ||
                    within(addr, mod->module_core, mod->core_size)) {
@@ -2229,12 +2249,12 @@ int lookup_module_symbol_name(unsigned long addr, char *symname)
                        if (!sym)
                                goto out;
                        strlcpy(symname, sym, KSYM_NAME_LEN);
-                       mutex_unlock(&module_mutex);
+                       preempt_enable();
                        return 0;
                }
        }
 out:
-       mutex_unlock(&module_mutex);
+       preempt_enable();
        return -ERANGE;
 }
 
@@ -2243,7 +2263,7 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
 {
        struct module *mod;
 
-       mutex_lock(&module_mutex);
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (within(addr, mod->module_init, mod->init_size) ||
                    within(addr, mod->module_core, mod->core_size)) {
@@ -2256,12 +2276,12 @@ int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size,
                                strlcpy(modname, mod->name, MODULE_NAME_LEN);
                        if (name)
                                strlcpy(name, sym, KSYM_NAME_LEN);
-                       mutex_unlock(&module_mutex);
+                       preempt_enable();
                        return 0;
                }
        }
 out:
-       mutex_unlock(&module_mutex);
+       preempt_enable();
        return -ERANGE;
 }
 
@@ -2270,7 +2290,7 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
 {
        struct module *mod;
 
-       mutex_lock(&module_mutex);
+       preempt_disable();
        list_for_each_entry(mod, &modules, list) {
                if (symnum < mod->num_symtab) {
                        *value = mod->symtab[symnum].st_value;
@@ -2279,12 +2299,12 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,
                                KSYM_NAME_LEN);
                        strlcpy(module_name, mod->name, MODULE_NAME_LEN);
                        *exported = is_exported(name, mod);
-                       mutex_unlock(&module_mutex);
+                       preempt_enable();
                        return 0;
                }
                symnum -= mod->num_symtab;
        }
-       mutex_unlock(&module_mutex);
+       preempt_enable();
        return -ERANGE;
 }
 
@@ -2307,6 +2327,7 @@ unsigned long module_kallsyms_lookup_name(const char *name)
        unsigned long ret = 0;
 
        /* Don't lock: we're in enough trouble already. */
+       preempt_disable();
        if ((colon = strchr(name, ':')) != NULL) {
                *colon = '\0';
                if ((mod = find_module(name)) != NULL)
@@ -2317,6 +2338,7 @@ unsigned long module_kallsyms_lookup_name(const char *name)
                        if ((ret = mod_find_symname(mod, name)) != 0)
                                break;
        }
+       preempt_enable();
        return ret;
 }
 #endif /* CONFIG_KALLSYMS */
@@ -2407,7 +2429,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);
@@ -2417,7 +2439,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;
 }
 
@@ -2478,95 +2500,23 @@ void print_modules(void)
        printk("\n");
 }
 
-#ifdef CONFIG_SYSFS
-static char *make_driver_name(struct device_driver *drv)
-{
-       char *driver_name;
-
-       driver_name = kmalloc(strlen(drv->name) + strlen(drv->bus->name) + 2,
-                             GFP_KERNEL);
-       if (!driver_name)
-               return NULL;
-
-       sprintf(driver_name, "%s:%s", drv->bus->name, drv->name);
-       return driver_name;
-}
-
-static void module_create_drivers_dir(struct module_kobject *mk)
-{
-       if (!mk || mk->drivers_dir)
-               return;
-
-       mk->drivers_dir = kobject_add_dir(&mk->kobj, "drivers");
-}
-
-void module_add_driver(struct module *mod, struct device_driver *drv)
-{
-       char *driver_name;
-       int no_warn;
-       struct module_kobject *mk = NULL;
-
-       if (!drv)
-               return;
-
-       if (mod)
-               mk = &mod->mkobj;
-       else if (drv->mod_name) {
-               struct kobject *mkobj;
-
-               /* Lookup built-in module entry in /sys/modules */
-               mkobj = kset_find_obj(&module_subsys, drv->mod_name);
-               if (mkobj) {
-                       mk = container_of(mkobj, struct module_kobject, kobj);
-                       /* remember our module structure */
-                       drv->mkobj = mk;
-                       /* kset_find_obj took a reference */
-                       kobject_put(mkobj);
-               }
-       }
-
-       if (!mk)
-               return;
-
-       /* Don't check return codes; these calls are idempotent */
-       no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module");
-       driver_name = make_driver_name(drv);
-       if (driver_name) {
-               module_create_drivers_dir(mk);
-               no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj,
-                                           driver_name);
-               kfree(driver_name);
-       }
-}
-EXPORT_SYMBOL(module_add_driver);
-
-void module_remove_driver(struct device_driver *drv)
-{
-       struct module_kobject *mk = NULL;
-       char *driver_name;
-
-       if (!drv)
-               return;
-
-       sysfs_remove_link(&drv->kobj, "module");
-
-       if (drv->owner)
-               mk = &drv->owner->mkobj;
-       else if (drv->mkobj)
-               mk = drv->mkobj;
-       if (mk && mk->drivers_dir) {
-               driver_name = make_driver_name(drv);
-               if (driver_name) {
-                       sysfs_remove_link(mk->drivers_dir, driver_name);
-                       kfree(driver_name);
-               }
-       }
-}
-EXPORT_SYMBOL(module_remove_driver);
-#endif
-
 #ifdef CONFIG_MODVERSIONS
 /* Generate the signature for struct module here, too, for modversions. */
 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