📄 module.c
字号:
MODINFO_ATTR(srcversion);#ifdef CONFIG_MODULE_UNLOAD/* Init the unload section of the module. */static void module_unload_init(struct module *mod){ unsigned int i; INIT_LIST_HEAD(&mod->modules_which_use_me); for (i = 0; i < NR_CPUS; i++) local_set(&mod->ref[i].count, 0); /* Hold reference count during initialization. */ local_set(&mod->ref[raw_smp_processor_id()].count, 1); /* Backwards compatibility macros put refcount during init. */ mod->waiter = current;}/* modules using other modules */struct module_use{ struct list_head list; struct module *module_which_uses;};/* Does a already use b? */static int already_uses(struct module *a, struct module *b){ struct module_use *use; list_for_each_entry(use, &b->modules_which_use_me, list) { if (use->module_which_uses == a) { DEBUGP("%s uses %s!\n", a->name, b->name); return 1; } } DEBUGP("%s does not use %s!\n", a->name, b->name); return 0;}/* Module a uses b */static int use_module(struct module *a, struct module *b){ struct module_use *use; int no_warn; if (b == NULL || already_uses(a, b)) return 1; if (!strong_try_module_get(b)) return 0; DEBUGP("Allocating new usage for %s.\n", a->name); use = kmalloc(sizeof(*use), GFP_ATOMIC); if (!use) { printk("%s: out of memory loading\n", a->name); module_put(b); return 0; } use->module_which_uses = a; list_add(&use->list, &b->modules_which_use_me); no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name); return 1;}/* Clear the unload stuff of the module. */static void module_unload_free(struct module *mod){ struct module *i; list_for_each_entry(i, &modules, list) { struct module_use *use; list_for_each_entry(use, &i->modules_which_use_me, list) { if (use->module_which_uses == mod) { DEBUGP("%s unusing %s\n", mod->name, i->name); module_put(i); list_del(&use->list); kfree(use); sysfs_remove_link(i->holders_dir, mod->name); /* There can be at most one match. */ break; } } }}#ifdef CONFIG_MODULE_FORCE_UNLOADstatic inline int try_force_unload(unsigned int flags){ int ret = (flags & O_TRUNC); if (ret) add_taint(TAINT_FORCED_RMMOD); return ret;}#elsestatic inline int try_force_unload(unsigned int flags){ return 0;}#endif /* CONFIG_MODULE_FORCE_UNLOAD */struct stopref{ struct module *mod; int flags; int *forced;};/* Whole machine is stopped with interrupts off when this runs. */static int __try_stop_module(void *_sref){ struct stopref *sref = _sref; /* If it's not unused, quit unless we are told to block. */ if ((sref->flags & O_NONBLOCK) && module_refcount(sref->mod) != 0) { if (!(*sref->forced = try_force_unload(sref->flags))) return -EWOULDBLOCK; } /* Mark it as dying. */ sref->mod->state = MODULE_STATE_GOING; return 0;}static int try_stop_module(struct module *mod, int flags, int *forced){ struct stopref sref = { mod, flags, forced }; return stop_machine_run(__try_stop_module, &sref, NR_CPUS);}unsigned int module_refcount(struct module *mod){ unsigned int i, total = 0; for (i = 0; i < NR_CPUS; i++) total += local_read(&mod->ref[i].count); return total;}EXPORT_SYMBOL(module_refcount);/* This exists whether we can unload or not */static void free_module(struct module *mod);static void wait_for_zero_refcount(struct module *mod){ /* Since we might sleep for some time, drop the semaphore first */ mutex_unlock(&module_mutex); for (;;) { DEBUGP("Looking at refcount...\n"); set_current_state(TASK_UNINTERRUPTIBLE); if (module_refcount(mod) == 0) break; schedule(); } current->state = TASK_RUNNING; mutex_lock(&module_mutex);}asmlinkage longsys_delete_module(const char __user *name_user, unsigned int flags){ struct module *mod; char name[MODULE_NAME_LEN]; int ret, forced = 0; if (!capable(CAP_SYS_MODULE)) return -EPERM; if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0) return -EFAULT; name[MODULE_NAME_LEN-1] = '\0'; if (mutex_lock_interruptible(&module_mutex) != 0) return -EINTR; mod = find_module(name); if (!mod) { ret = -ENOENT; goto out; } if (!list_empty(&mod->modules_which_use_me)) { /* Other modules depend on us: get rid of them first. */ ret = -EWOULDBLOCK; goto out; } /* Doing init or already dying? */ if (mod->state != MODULE_STATE_LIVE) { /* FIXME: if (force), slam module count and wake up waiter --RR */ DEBUGP("%s already dying\n", mod->name); ret = -EBUSY; goto out; } /* If it has an init func, it must have an exit func to unload */ if ((mod->init != NULL && mod->exit == NULL) || mod->unsafe) { forced = try_force_unload(flags); if (!forced) { /* This module can't be removed */ ret = -EBUSY; goto out; } } /* Set this up before setting mod->state */ mod->waiter = current; /* Stop the machine so refcounts can't move and disable module. */ ret = try_stop_module(mod, flags, &forced); if (ret != 0) goto out; /* Never wait if forced. */ if (!forced && module_refcount(mod) != 0) wait_for_zero_refcount(mod); /* Final destruction now noone is using it. */ if (mod->exit != NULL) { mutex_unlock(&module_mutex); mod->exit(); mutex_lock(&module_mutex); } free_module(mod); out: mutex_unlock(&module_mutex); return ret;}static void print_unload_info(struct seq_file *m, struct module *mod){ struct module_use *use; int printed_something = 0; seq_printf(m, " %u ", module_refcount(mod)); /* Always include a trailing , so userspace can differentiate between this and the old multi-field proc format. */ list_for_each_entry(use, &mod->modules_which_use_me, list) { printed_something = 1; 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],"); } if (!printed_something) seq_printf(m, "-");}void __symbol_put(const char *symbol){ struct module *owner; unsigned long flags; const unsigned long *crc; spin_lock_irqsave(&modlist_lock, flags); if (!__find_symbol(symbol, &owner, &crc, 1)) BUG(); module_put(owner); spin_unlock_irqrestore(&modlist_lock, flags);}EXPORT_SYMBOL(__symbol_put);void symbol_put_addr(void *addr){ struct module *modaddr; if (core_kernel_text((unsigned long)addr)) return; if (!(modaddr = module_text_address((unsigned long)addr))) BUG(); module_put(modaddr);}EXPORT_SYMBOL_GPL(symbol_put_addr);static ssize_t show_refcnt(struct module_attribute *mattr, struct module *mod, char *buffer){ /* sysfs holds a reference */ return sprintf(buffer, "%u\n", module_refcount(mod)-1);}static struct module_attribute refcnt = { .attr = { .name = "refcnt", .mode = 0444, .owner = THIS_MODULE }, .show = show_refcnt,};void module_put(struct module *module){ if (module) { unsigned int cpu = get_cpu(); local_dec(&module->ref[cpu].count); /* Maybe they're waiting for us to drop reference? */ if (unlikely(!module_is_live(module))) wake_up_process(module->waiter); put_cpu(); }}EXPORT_SYMBOL(module_put);#else /* !CONFIG_MODULE_UNLOAD */static void print_unload_info(struct seq_file *m, struct module *mod){ /* We don't know the usage count, or what modules are using. */ seq_printf(m, " - -");}static inline void module_unload_free(struct module *mod){}static inline int use_module(struct module *a, struct module *b){ return strong_try_module_get(b);}static inline void module_unload_init(struct module *mod){}#endif /* CONFIG_MODULE_UNLOAD */static ssize_t show_initstate(struct module_attribute *mattr, struct module *mod, char *buffer){ const char *state = "unknown"; switch (mod->state) { case MODULE_STATE_LIVE: state = "live"; break; case MODULE_STATE_COMING: state = "coming"; break; case MODULE_STATE_GOING: state = "going"; break; } return sprintf(buffer, "%s\n", state);}static struct module_attribute initstate = { .attr = { .name = "initstate", .mode = 0444, .owner = THIS_MODULE }, .show = show_initstate,};static struct module_attribute *modinfo_attrs[] = { &modinfo_version, &modinfo_srcversion, &initstate,#ifdef CONFIG_MODULE_UNLOAD &refcnt,#endif NULL,};static const char vermagic[] = VERMAGIC_STRING;#ifdef CONFIG_MODVERSIONSstatic int check_version(Elf_Shdr *sechdrs, unsigned int versindex, const char *symname, struct module *mod, const unsigned long *crc){ unsigned int i, num_versions; struct modversion_info *versions; /* Exporting module didn't supply crcs? OK, we're already tainted. */ if (!crc) return 1; versions = (void *) sechdrs[versindex].sh_addr; num_versions = sechdrs[versindex].sh_size / sizeof(struct modversion_info); for (i = 0; i < num_versions; i++) { if (strcmp(versions[i].name, symname) != 0) continue; if (versions[i].crc == *crc) return 1; printk("%s: disagrees about version of symbol %s\n", mod->name, symname); DEBUGP("Found checksum %lX vs module %lX\n", *crc, versions[i].crc); return 0; } /* Not in module's version table. OK, but that taints the kernel. */ if (!(tainted & TAINT_FORCED_MODULE)) printk("%s: no version for \"%s\" found: kernel tainted.\n", mod->name, symname); add_taint_module(mod, TAINT_FORCED_MODULE); return 1;}static inline int check_modstruct_version(Elf_Shdr *sechdrs, unsigned int versindex, struct module *mod){ const unsigned long *crc; struct module *owner; if (!__find_symbol("struct_module", &owner, &crc, 1)) BUG(); return check_version(sechdrs, versindex, "struct_module", mod, crc);}/* First part is kernel version, which we ignore. */static inline int same_magic(const char *amagic, const char *bmagic){ amagic += strcspn(amagic, " "); bmagic += strcspn(bmagic, " "); return strcmp(amagic, bmagic) == 0;}#elsestatic inline int check_version(Elf_Shdr *sechdrs, unsigned int versindex, const char *symname, struct module *mod, const unsigned long *crc){ return 1;}static inline int check_modstruct_version(Elf_Shdr *sechdrs, unsigned int versindex, struct module *mod){ return 1;}static inline int same_magic(const char *amagic, const char *bmagic){ return strcmp(amagic, bmagic) == 0;}#endif /* CONFIG_MODVERSIONS *//* Resolve a symbol for this module. I.e. if we find one, record usage. Must be holding module_mutex. */static unsigned long resolve_symbol(Elf_Shdr *sechdrs, unsigned int versindex, const char *name, struct module *mod){ struct module *owner; unsigned long ret; const unsigned long *crc; ret = __find_symbol(name, &owner, &crc, !(mod->taints & TAINT_PROPRIETARY_MODULE)); if (ret) { /* use_module can fail due to OOM, or module unloading */ if (!check_version(sechdrs, versindex, name, mod, crc) || !use_module(mod, owner)) ret = 0; } return ret;}/* * /sys/module/foo/sections stuff * J. Corbet <corbet@lwn.net> */#ifdef CONFIG_KALLSYMSstatic ssize_t module_sect_show(struct module_attribute *mattr, struct module *mod, char *buf){ struct module_sect_attr *sattr = container_of(mattr, struct module_sect_attr, mattr); return sprintf(buf, "0x%lx\n", sattr->address);}static void free_sect_attrs(struct module_sect_attrs *sect_attrs){ int section; for (section = 0; section < sect_attrs->nsections; section++) kfree(sect_attrs->attrs[section].name); kfree(sect_attrs);}static void add_sect_attrs(struct module *mod, unsigned int nsect, char *secstrings, Elf_Shdr *sechdrs){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -