X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=kernel%2Fmodule.c;h=dcb8a2cbf75e2152496ebe4ca25d19ac50018401;hb=c2d727aa2ff17a1c8e5ed1e5e231bb8579b27e82;hp=db0ead0363e2504be6760e73cbef5a2b981a8565;hpb=b160292cc216a50fd0cd386b0bda2cd48352c73b;p=linux-2.6-omap-h63xx.git diff --git a/kernel/module.c b/kernel/module.c index db0ead0363e..dcb8a2cbf75 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -46,8 +47,6 @@ #include #include -extern int module_sysfs_initialized; - #if 0 #define DEBUGP printk #else @@ -80,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) @@ -104,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, @@ -178,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) { @@ -230,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); @@ -284,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. */ @@ -440,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, @@ -482,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 }, \ @@ -692,8 +692,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 +740,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],"); @@ -957,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; @@ -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, + ¬es_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 = ¬es_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_create_and_add("notes", &mod->mkobj.kobj); + if (!notes_attrs->dir) + goto out; + + for (i = 0; i < notes; ++i) + if (sysfs_create_bin_file(notes_attrs->dir, + ¬es_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 @@ -1119,15 +1217,16 @@ int mod_sysfs_init(struct module *mod) err = -EINVAL; goto out; } - memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj)); - err = kobject_set_name(&mod->mkobj.kobj, "%s", mod->name); - if (err) - goto out; - kobj_set_kset_s(&mod->mkobj, module_subsys); mod->mkobj.mod = mod; - kobject_init(&mod->mkobj.kobj); + memset(&mod->mkobj.kobj, 0, sizeof(mod->mkobj.kobj)); + mod->mkobj.kobj.kset = module_kset; + err = kobject_init_and_add(&mod->mkobj.kobj, &module_ktype, NULL, + "%s", mod->name); + if (err) + kobject_put(&mod->mkobj.kobj); + /* delay uevent until full sysfs population */ out: return err; } @@ -1138,12 +1237,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; @@ -1163,11 +1257,9 @@ int mod_sysfs_setup(struct module *mod, out_unreg_param: module_param_sysfs_remove(mod); out_unreg_holders: - kobject_unregister(mod->holders_dir); + kobject_put(mod->holders_dir); out_unreg: - kobject_del(&mod->mkobj.kobj); kobject_put(&mod->mkobj.kobj); -out: return err; } #endif @@ -1176,9 +1268,9 @@ static void mod_kobject_remove(struct module *mod) { module_remove_modinfo_attrs(mod); module_param_sysfs_remove(mod); - kobject_unregister(mod->mkobj.drivers_dir); - kobject_unregister(mod->holders_dir); - kobject_unregister(&mod->mkobj.kobj); + kobject_put(mod->mkobj.drivers_dir); + kobject_put(mod->holders_dir); + kobject_put(&mod->mkobj.kobj); } /* @@ -1197,6 +1289,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 +1342,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; @@ -1270,7 +1363,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, @@ -1574,6 +1667,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 */ @@ -1781,9 +1876,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. */ - if (mod_sysfs_init(mod) != 0) - goto cleanup; + /* add kobject, so we can reference it. */ + err = mod_sysfs_init(mod); + if (err) + goto free_unload; /* Set up license info based on the info section */ set_license(mod, get_modinfo(sechdrs, infoindex, "license")); @@ -1829,7 +1925,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 +1935,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 +1960,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 +1983,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 +2025,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 +2033,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); @@ -1939,6 +2049,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: @@ -2011,15 +2124,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 +2158,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 +2173,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; @@ -2101,29 +2209,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)) { @@ -2133,12 +2246,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; } @@ -2147,7 +2260,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)) { @@ -2160,12 +2273,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; } @@ -2174,7 +2287,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; @@ -2183,12 +2296,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; } @@ -2211,6 +2324,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) @@ -2221,6 +2335,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 */ @@ -2311,7 +2426,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 +2436,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; } @@ -2382,95 +2497,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