Skip to content
Snippets Groups Projects
module.c 96.4 KiB
Newer Older
  • Learn to ignore specific revisions
  • Linus Torvalds's avatar
    Linus Torvalds committed
       Copyright (C) 2002 Richard Henderson
    
       Copyright (C) 2001 Rusty Russell, 2002, 2010 Rusty Russell IBM.
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
        This program is free software; you can redistribute it and/or modify
        it under the terms of the GNU General Public License as published by
        the Free Software Foundation; either version 2 of the License, or
        (at your option) any later version.
    
        This program is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
        GNU General Public License for more details.
    
        You should have received a copy of the GNU General Public License
        along with this program; if not, write to the Free Software
        Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    */
    
    #include <linux/export.h>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #include <linux/moduleloader.h>
    
    #include <linux/ftrace_event.h>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #include <linux/init.h>
    
    #include <linux/kallsyms.h>
    
    #include <linux/file.h>
    
    #include <linux/sysfs.h>
    
    #include <linux/kernel.h>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #include <linux/slab.h>
    #include <linux/vmalloc.h>
    #include <linux/elf.h>
    
    #include <linux/proc_fs.h>
    
    #include <linux/security.h>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #include <linux/seq_file.h>
    #include <linux/syscalls.h>
    #include <linux/fcntl.h>
    #include <linux/rcupdate.h>
    
    #include <linux/capability.h>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #include <linux/cpu.h>
    #include <linux/moduleparam.h>
    #include <linux/errno.h>
    #include <linux/err.h>
    #include <linux/vermagic.h>
    #include <linux/notifier.h>
    
    #include <linux/sched.h>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #include <linux/stop_machine.h>
    #include <linux/device.h>
    
    #include <linux/string.h>
    
    #include <linux/mutex.h>
    
    #include <linux/rculist.h>
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #include <asm/uaccess.h>
    #include <asm/cacheflush.h>
    
    #include <asm/mmu_context.h>
    
    #include <linux/license.h>
    
    #include <linux/tracepoint.h>
    
    #include <linux/ftrace.h>
    
    #include <linux/percpu.h>
    
    #include <linux/kmemleak.h>
    
    #include <linux/jump_label.h>
    
    #include <linux/bsearch.h>
    
    David Howells's avatar
    David Howells committed
    #include <linux/fips.h>
    
    #include <uapi/linux/module.h>
    
    #include "module-internal.h"
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    #define CREATE_TRACE_POINTS
    #include <trace/events/module.h>
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #ifndef ARCH_SHF_SMALL
    #define ARCH_SHF_SMALL 0
    #endif
    
    
    /*
     * Modules' sections will be aligned on page boundaries
     * to ensure complete separation of code and data, but
     * only when CONFIG_DEBUG_SET_MODULE_RONX=y
     */
    #ifdef CONFIG_DEBUG_SET_MODULE_RONX
    # define debug_align(X) ALIGN(X, PAGE_SIZE)
    #else
    # define debug_align(X) (X)
    #endif
    
    /*
     * Given BASE and SIZE this macro calculates the number of pages the
     * memory regions occupies
     */
    #define MOD_NUMBER_OF_PAGES(BASE, SIZE) (((SIZE) > 0) ?		\
    		(PFN_DOWN((unsigned long)(BASE) + (SIZE) - 1) -	\
    			 PFN_DOWN((unsigned long)BASE) + 1)	\
    		: (0UL))
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    /* If this is set, the section belongs in the init part of the module */
    #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
    
    
    /*
     * Mutex protects:
     * 1) List of modules (also safely readable with preempt_disable),
     * 2) module_use links,
     * 3) module_addr_min/module_addr_max.
    
     * (delete uses stop_machine/add uses RCU list operations). */
    
    DEFINE_MUTEX(module_mutex);
    EXPORT_SYMBOL_GPL(module_mutex);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    static LIST_HEAD(modules);
    
    #ifdef CONFIG_KGDB_KDB
    struct list_head *kdb_modules = &modules; /* kdb needs the list of modules */
    #endif /* CONFIG_KGDB_KDB */
    
    
    #ifdef CONFIG_MODULE_SIG
    #ifdef CONFIG_MODULE_SIG_FORCE
    static bool sig_enforce = true;
    #else
    static bool sig_enforce = false;
    
    static int param_set_bool_enable_only(const char *val,
    				      const struct kernel_param *kp)
    {
    	int err;
    	bool test;
    	struct kernel_param dummy_kp = *kp;
    
    	dummy_kp.arg = &test;
    
    	err = param_set_bool(val, &dummy_kp);
    	if (err)
    		return err;
    
    	/* Don't let them unset it once it's set! */
    	if (!test && sig_enforce)
    		return -EROFS;
    
    	if (test)
    		sig_enforce = true;
    	return 0;
    }
    
    static const struct kernel_param_ops param_ops_bool_enable_only = {
    
    	.set = param_set_bool_enable_only,
    	.get = param_get_bool,
    };
    #define param_check_bool_enable_only param_check_bool
    
    module_param(sig_enforce, bool_enable_only, 0644);
    #endif /* !CONFIG_MODULE_SIG_FORCE */
    #endif /* CONFIG_MODULE_SIG */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    /* Block module loading/unloading? */
    int modules_disabled = 0;
    
    core_param(nomodule, modules_disabled, bint, 0);
    
    /* Waiting for a module to finish initializing? */
    static DECLARE_WAIT_QUEUE_HEAD(module_wq);
    
    
    static BLOCKING_NOTIFIER_HEAD(module_notify_list);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    /* Bounds of module allocation, for speeding __module_address.
     * Protected by module_mutex. */
    
    static unsigned long module_addr_min = -1UL, module_addr_max = 0;
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    int register_module_notifier(struct notifier_block * nb)
    {
    
    	return blocking_notifier_chain_register(&module_notify_list, nb);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    EXPORT_SYMBOL(register_module_notifier);
    
    int unregister_module_notifier(struct notifier_block * nb)
    {
    
    	return blocking_notifier_chain_unregister(&module_notify_list, nb);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    EXPORT_SYMBOL(unregister_module_notifier);
    
    
    struct load_info {
    	Elf_Ehdr *hdr;
    	unsigned long len;
    	Elf_Shdr *sechdrs;
    
    	char *secstrings, *strtab;
    
    	unsigned long symoffs, stroffs;
    
    	struct _ddebug *debug;
    	unsigned int num_debug;
    
    	bool sig_ok;
    
    	struct {
    		unsigned int sym, str, mod, vers, info, pcpu;
    	} index;
    };
    
    
    /* We require a truly strong try_module_get(): 0 means failure due to
       ongoing or failed initialization etc. */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    static inline int strong_try_module_get(struct module *mod)
    {
    
    	BUG_ON(mod && mod->state == MODULE_STATE_UNFORMED);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	if (mod && mod->state == MODULE_STATE_COMING)
    
    		return -EBUSY;
    	if (try_module_get(mod))
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		return 0;
    
    static inline void add_taint_module(struct module *mod, unsigned flag,
    				    enum lockdep_ok lockdep_ok)
    
    	add_taint(flag, lockdep_ok);
    
    	mod->taints |= (1U << flag);
    
    /*
     * A thread that wants to hold a reference to a module only while it
     * is running can call this to safely exit.  nfsd and lockd use this.
    
    Linus Torvalds's avatar
    Linus Torvalds committed
     */
    void __module_put_and_exit(struct module *mod, long code)
    {
    	module_put(mod);
    	do_exit(code);
    }
    EXPORT_SYMBOL(__module_put_and_exit);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    /* Find a module section: 0 means not found. */
    
    static unsigned int find_sec(const struct load_info *info, const char *name)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	unsigned int i;
    
    
    	for (i = 1; i < info->hdr->e_shnum; i++) {
    		Elf_Shdr *shdr = &info->sechdrs[i];
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		/* Alloc bit cleared means "ignore it." */
    
    		if ((shdr->sh_flags & SHF_ALLOC)
    		    && strcmp(info->secstrings + shdr->sh_name, name) == 0)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			return i;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return 0;
    }
    
    
    /* Find a module section, or NULL. */
    
    static void *section_addr(const struct load_info *info, const char *name)
    
    {
    	/* Section 0 has sh_addr 0. */
    
    	return (void *)info->sechdrs[find_sec(info, name)].sh_addr;
    
    }
    
    /* Find a module section, or NULL.  Fill in number of "objects" in section. */
    
    static void *section_objs(const struct load_info *info,
    
    			  const char *name,
    			  size_t object_size,
    			  unsigned int *num)
    {
    
    	unsigned int sec = find_sec(info, name);
    
    
    	/* Section 0 has sh_addr 0 and sh_size 0. */
    
    	*num = info->sechdrs[sec].sh_size / object_size;
    	return (void *)info->sechdrs[sec].sh_addr;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    /* Provided by the linker */
    extern const struct kernel_symbol __start___ksymtab[];
    extern const struct kernel_symbol __stop___ksymtab[];
    extern const struct kernel_symbol __start___ksymtab_gpl[];
    extern const struct kernel_symbol __stop___ksymtab_gpl[];
    
    extern const struct kernel_symbol __start___ksymtab_gpl_future[];
    extern const struct kernel_symbol __stop___ksymtab_gpl_future[];
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    extern const unsigned long __start___kcrctab[];
    extern const unsigned long __start___kcrctab_gpl[];
    
    extern const unsigned long __start___kcrctab_gpl_future[];
    
    #ifdef CONFIG_UNUSED_SYMBOLS
    extern const struct kernel_symbol __start___ksymtab_unused[];
    extern const struct kernel_symbol __stop___ksymtab_unused[];
    extern const struct kernel_symbol __start___ksymtab_unused_gpl[];
    extern const struct kernel_symbol __stop___ksymtab_unused_gpl[];
    
    extern const unsigned long __start___kcrctab_unused[];
    extern const unsigned long __start___kcrctab_unused_gpl[];
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    #ifndef CONFIG_MODVERSIONS
    #define symversion(base, idx) NULL
    #else
    
    #define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #endif
    
    
    static bool each_symbol_in_section(const struct symsearch *arr,
    				   unsigned int arrsize,
    				   struct module *owner,
    				   bool (*fn)(const struct symsearch *syms,
    					      struct module *owner,
    
    	for (j = 0; j < arrsize; j++) {
    
    		if (fn(&arr[j], owner, data))
    			return true;
    
    /* Returns true as soon as fn returns true, otherwise false. */
    
    bool each_symbol_section(bool (*fn)(const struct symsearch *arr,
    				    struct module *owner,
    				    void *data),
    			 void *data)
    
    	static const struct symsearch arr[] = {
    
    		{ __start___ksymtab, __stop___ksymtab, __start___kcrctab,
    
    		  NOT_GPL_ONLY, false },
    
    		{ __start___ksymtab_gpl, __stop___ksymtab_gpl,
    
    		  __start___kcrctab_gpl,
    		  GPL_ONLY, false },
    
    		{ __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future,
    
    		  __start___kcrctab_gpl_future,
    		  WILL_BE_GPL_ONLY, false },
    
    #ifdef CONFIG_UNUSED_SYMBOLS
    
    		{ __start___ksymtab_unused, __stop___ksymtab_unused,
    
    		  __start___kcrctab_unused,
    		  NOT_GPL_ONLY, true },
    
    		{ __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl,
    
    		  __start___kcrctab_unused_gpl,
    		  GPL_ONLY, true },
    
    	if (each_symbol_in_section(arr, ARRAY_SIZE(arr), NULL, fn, data))
    		return true;
    
    	list_for_each_entry_rcu(mod, &modules, list) {
    
    		struct symsearch arr[] = {
    			{ mod->syms, mod->syms + mod->num_syms, mod->crcs,
    
    			  NOT_GPL_ONLY, false },
    
    			{ mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms,
    
    			  mod->gpl_crcs,
    			  GPL_ONLY, false },
    
    			{ mod->gpl_future_syms,
    			  mod->gpl_future_syms + mod->num_gpl_future_syms,
    
    			  mod->gpl_future_crcs,
    			  WILL_BE_GPL_ONLY, false },
    
    #ifdef CONFIG_UNUSED_SYMBOLS
    
    			{ mod->unused_syms,
    			  mod->unused_syms + mod->num_unused_syms,
    
    			  mod->unused_crcs,
    			  NOT_GPL_ONLY, true },
    
    			{ mod->unused_gpl_syms,
    			  mod->unused_gpl_syms + mod->num_unused_gpl_syms,
    
    			  mod->unused_gpl_crcs,
    			  GPL_ONLY, true },
    
    		if (mod->state == MODULE_STATE_UNFORMED)
    			continue;
    
    
    		if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data))
    			return true;
    	}
    	return false;
    }
    
    EXPORT_SYMBOL_GPL(each_symbol_section);
    
    
    struct find_symbol_arg {
    	/* Input */
    	const char *name;
    	bool gplok;
    	bool warn;
    
    	/* Output */
    	struct module *owner;
    	const unsigned long *crc;
    
    	const struct kernel_symbol *sym;
    
    static bool check_symbol(const struct symsearch *syms,
    				 struct module *owner,
    				 unsigned int symnum, void *data)
    
    {
    	struct find_symbol_arg *fsa = data;
    
    	if (!fsa->gplok) {
    		if (syms->licence == GPL_ONLY)
    			return false;
    		if (syms->licence == WILL_BE_GPL_ONLY && fsa->warn) {
    
    			pr_warn("Symbol %s is being used by a non-GPL module, "
    				"which will not be allowed in the future\n",
    				fsa->name);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    #ifdef CONFIG_UNUSED_SYMBOLS
    
    	if (syms->unused && fsa->warn) {
    
    		pr_warn("Symbol %s is marked as UNUSED, however this module is "
    			"using it.\n", fsa->name);
    		pr_warn("This symbol will go away in the future.\n");
    		pr_warn("Please evalute if this is the right api to use and if "
    			"it really is, submit a report the linux kernel "
    			"mailinglist together with submitting your code for "
    			"inclusion.\n");
    
    
    	fsa->owner = owner;
    	fsa->crc = symversion(syms->crcs, symnum);
    
    	fsa->sym = &syms->start[symnum];
    
    static int cmp_name(const void *va, const void *vb)
    {
    	const char *a;
    	const struct kernel_symbol *b;
    	a = va; b = vb;
    	return strcmp(a, b->name);
    }
    
    
    static bool find_symbol_in_section(const struct symsearch *syms,
    				   struct module *owner,
    				   void *data)
    {
    	struct find_symbol_arg *fsa = data;
    
    	struct kernel_symbol *sym;
    
    	sym = bsearch(fsa->name, syms->start, syms->stop - syms->start,
    			sizeof(struct kernel_symbol), cmp_name);
    
    	if (sym != NULL && check_symbol(syms, owner, sym - syms->start, data))
    		return true;
    
    /* Find a symbol and return it, along with, (optional) crc and
    
     * (optional) module which owns it.  Needs preempt disabled or module_mutex. */
    
    const struct kernel_symbol *find_symbol(const char *name,
    					struct module **owner,
    					const unsigned long **crc,
    					bool gplok,
    					bool warn)
    
    {
    	struct find_symbol_arg fsa;
    
    	fsa.name = name;
    	fsa.gplok = gplok;
    	fsa.warn = warn;
    
    
    	if (each_symbol_section(find_symbol_in_section, &fsa)) {
    
    		if (owner)
    			*owner = fsa.owner;
    		if (crc)
    			*crc = fsa.crc;
    
    	pr_debug("Failed to find symbol %s\n", name);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    EXPORT_SYMBOL_GPL(find_symbol);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    /* Search for module by name: must hold module_mutex. */
    
    static struct module *find_module_all(const char *name, size_t len,
    
    				      bool even_unformed)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct module *mod;
    
    	list_for_each_entry(mod, &modules, list) {
    
    		if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)
    			continue;
    
    		if (strlen(mod->name) == len && !memcmp(mod->name, name, len))
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			return mod;
    	}
    	return NULL;
    }
    
    
    struct module *find_module(const char *name)
    {
    
    	return find_module_all(name, strlen(name), false);
    
    EXPORT_SYMBOL_GPL(find_module);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    #ifdef CONFIG_SMP
    
    static inline void __percpu *mod_percpu(struct module *mod)
    
    static int percpu_modalloc(struct module *mod, struct load_info *info)
    
    	Elf_Shdr *pcpusec = &info->sechdrs[info->index.pcpu];
    	unsigned long align = pcpusec->sh_addralign;
    
    	if (!pcpusec->sh_size)
    		return 0;
    
    
    	if (align > PAGE_SIZE) {
    
    		pr_warn("%s: per-cpu alignment %li > %li\n",
    			mod->name, align, PAGE_SIZE);
    
    	mod->percpu = __alloc_reserved_percpu(pcpusec->sh_size, align);
    
    		pr_warn("%s: Could not allocate %lu bytes percpu data\n",
    			mod->name, (unsigned long)pcpusec->sh_size);
    
    	mod->percpu_size = pcpusec->sh_size;
    
    static void percpu_modfree(struct module *mod)
    
    static unsigned int find_pcpusec(struct load_info *info)
    
    	return find_sec(info, ".data..percpu");
    
    static void percpu_modcopy(struct module *mod,
    			   const void *from, unsigned long size)
    
    {
    	int cpu;
    
    	for_each_possible_cpu(cpu)
    
    		memcpy(per_cpu_ptr(mod->percpu, cpu), from, size);
    
    /**
     * is_module_percpu_address - test whether address is from module static percpu
     * @addr: address to test
     *
     * Test whether @addr belongs to module static percpu area.
     *
     * RETURNS:
     * %true if @addr is from module static percpu area
     */
    bool is_module_percpu_address(unsigned long addr)
    {
    	struct module *mod;
    	unsigned int cpu;
    
    	preempt_disable();
    
    	list_for_each_entry_rcu(mod, &modules, list) {
    
    		if (mod->state == MODULE_STATE_UNFORMED)
    			continue;
    
    		if (!mod->percpu_size)
    			continue;
    		for_each_possible_cpu(cpu) {
    			void *start = per_cpu_ptr(mod->percpu, cpu);
    
    			if ((void *)addr >= start &&
    			    (void *)addr < start + mod->percpu_size) {
    				preempt_enable();
    				return true;
    			}
    		}
    	}
    
    	preempt_enable();
    	return false;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #else /* ... !CONFIG_SMP */
    
    static inline void __percpu *mod_percpu(struct module *mod)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	return NULL;
    }
    
    static int percpu_modalloc(struct module *mod, struct load_info *info)
    
    	/* UP modules shouldn't have this section: ENOMEM isn't quite right */
    	if (info->sechdrs[info->index.pcpu].sh_size != 0)
    		return -ENOMEM;
    	return 0;
    
    }
    static inline void percpu_modfree(struct module *mod)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    }
    
    static unsigned int find_pcpusec(struct load_info *info)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	return 0;
    }
    
    static inline void percpu_modcopy(struct module *mod,
    				  const void *from, unsigned long size)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	/* pcpusec should be 0, and size of that section should be 0. */
    	BUG_ON(size != 0);
    }
    
    bool is_module_percpu_address(unsigned long addr)
    {
    	return false;
    }
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #endif /* CONFIG_SMP */
    
    
    #define MODINFO_ATTR(field)	\
    static void setup_modinfo_##field(struct module *mod, const char *s)  \
    {                                                                     \
    	mod->field = kstrdup(s, GFP_KERNEL);                          \
    }                                                                     \
    static ssize_t show_modinfo_##field(struct module_attribute *mattr,   \
    
    			struct module_kobject *mk, char *buffer)      \
    
    	return scnprintf(buffer, PAGE_SIZE, "%s\n", mk->mod->field);  \
    
    }                                                                     \
    static int modinfo_##field##_exists(struct module *mod)               \
    {                                                                     \
    	return mod->field != NULL;                                    \
    }                                                                     \
    static void free_modinfo_##field(struct module *mod)                  \
    {                                                                     \
    
    	kfree(mod->field);                                            \
    	mod->field = NULL;                                            \
    
    }                                                                     \
    static struct module_attribute modinfo_##field = {                    \
    
    	.attr = { .name = __stringify(field), .mode = 0444 },         \
    
    	.show = show_modinfo_##field,                                 \
    	.setup = setup_modinfo_##field,                               \
    	.test = modinfo_##field##_exists,                             \
    	.free = free_modinfo_##field,                                 \
    };
    
    MODINFO_ATTR(version);
    MODINFO_ATTR(srcversion);
    
    
    static char last_unloaded_module[MODULE_NAME_LEN+1];
    
    
    #ifdef CONFIG_MODULE_UNLOAD
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    /* Init the unload section of the module. */
    
    static int module_unload_init(struct module *mod)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	mod->refptr = alloc_percpu(struct module_ref);
    	if (!mod->refptr)
    		return -ENOMEM;
    
    
    	INIT_LIST_HEAD(&mod->source_list);
    	INIT_LIST_HEAD(&mod->target_list);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	/* Hold reference count during initialization. */
    
    	raw_cpu_write(mod->refptr->incs, 1);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    /* 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->source_list, source_list) {
    		if (use->source == a) {
    
    			pr_debug("%s uses %s!\n", a->name, b->name);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			return 1;
    		}
    	}
    
    	pr_debug("%s does not use %s!\n", a->name, b->name);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return 0;
    }
    
    
    /*
     * Module a uses b
     *  - we add 'a' as a "source", 'b' as a "target" of module use
     *  - the module_use is added to the list of 'b' sources (so
     *    'b' can walk the list to see who sourced them), and of 'a'
     *    targets (so 'a' can see what modules it targets).
     */
    static int add_module_usage(struct module *a, struct module *b)
    {
    	struct module_use *use;
    
    
    	pr_debug("Allocating new usage for %s.\n", a->name);
    
    	use = kmalloc(sizeof(*use), GFP_ATOMIC);
    	if (!use) {
    
    		pr_warn("%s: out of memory loading\n", a->name);
    
    		return -ENOMEM;
    	}
    
    	use->source = a;
    	use->target = b;
    	list_add(&use->source_list, &b->source_list);
    	list_add(&use->target_list, &a->target_list);
    	return 0;
    }
    
    
    /* Module a uses b: caller needs module_mutex() */
    
    int ref_module(struct module *a, struct module *b)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	if (b == NULL || already_uses(a, b))
    
    	/* If module isn't available, we fail. */
    	err = strong_try_module_get(b);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	err = add_module_usage(a, b);
    	if (err) {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		module_put(b);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    EXPORT_SYMBOL_GPL(ref_module);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    /* Clear the unload stuff of the module. */
    static void module_unload_free(struct module *mod)
    {
    
    	struct module_use *use, *tmp;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	mutex_lock(&module_mutex);
    
    	list_for_each_entry_safe(use, tmp, &mod->target_list, target_list) {
    		struct module *i = use->target;
    
    		pr_debug("%s unusing %s\n", mod->name, i->name);
    
    		module_put(i);
    		list_del(&use->source_list);
    		list_del(&use->target_list);
    		kfree(use);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    	mutex_unlock(&module_mutex);
    
    
    	free_percpu(mod->refptr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    #ifdef CONFIG_MODULE_FORCE_UNLOAD
    
    static inline int try_force_unload(unsigned int flags)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	int ret = (flags & O_TRUNC);
    	if (ret)
    
    		add_taint(TAINT_FORCED_RMMOD, LOCKDEP_NOW_UNRELIABLE);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return ret;
    }
    #else
    
    static inline int try_force_unload(unsigned int flags)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	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're forcing. */
    	if (module_refcount(sref->mod) != 0) {
    
    		if (!(*sref->forced = try_force_unload(sref->flags)))
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    			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 };
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	return stop_machine(__try_stop_module, &sref, NULL);
    
    unsigned long module_refcount(struct module *mod)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	unsigned long incs = 0, decs = 0;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	for_each_possible_cpu(cpu)
    
    		decs += per_cpu_ptr(mod->refptr, cpu)->decs;
    	/*
    	 * ensure the incs are added up after the decs.
    	 * module_put ensures incs are visible before decs with smp_wmb.
    	 *
    	 * This 2-count scheme avoids the situation where the refcount
    	 * for CPU0 is read, then CPU0 increments the module refcount,
    	 * then CPU1 drops that refcount, then the refcount for CPU1 is
    	 * read. We would record a decrement but not its corresponding
    	 * increment so we would see a low count (disaster).
    	 *
    	 * Rare situation? But module_refcount can be preempted, and we
    	 * might be tallying up 4096+ CPUs. So it is not impossible.
    	 */
    	smp_rmb();
    	for_each_possible_cpu(cpu)
    		incs += per_cpu_ptr(mod->refptr, cpu)->incs;
    	return incs - decs;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    EXPORT_SYMBOL(module_refcount);
    
    /* This exists whether we can unload or not */
    static void free_module(struct module *mod);
    
    
    SYSCALL_DEFINE2(delete_module, const char __user *, name_user,
    		unsigned int, flags)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct module *mod;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	int ret, forced = 0;
    
    
    	if (!capable(CAP_SYS_MODULE) || modules_disabled)
    
    		return -EPERM;
    
    	if (strncpy_from_user(name, name_user, MODULE_NAME_LEN-1) < 0)
    		return -EFAULT;
    	name[MODULE_NAME_LEN-1] = '\0';
    
    
    	if (!(flags & O_NONBLOCK))
    		pr_warn("waiting module removal not supported: please upgrade\n");
    
    	if (mutex_lock_interruptible(&module_mutex) != 0)
    		return -EINTR;
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	mod = find_module(name);
    	if (!mod) {
    		ret = -ENOENT;
    		goto out;
    	}
    
    
    	if (!list_empty(&mod->source_list)) {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		/* 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 damn the torpedoes */
    
    		pr_debug("%s already dying\n", mod->name);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		ret = -EBUSY;
    		goto out;
    	}
    
    	/* If it has an init func, it must have an exit func to unload */
    
    	if (mod->init && !mod->exit) {
    
    		forced = try_force_unload(flags);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		if (!forced) {
    			/* This module can't be removed */
    			ret = -EBUSY;
    			goto out;
    		}
    	}
    
    	/* Stop the machine so refcounts can't move and disable module. */
    	ret = try_stop_module(mod, flags, &forced);
    	if (ret != 0)
    		goto out;
    
    
    	mutex_unlock(&module_mutex);
    
    Lucas De Marchi's avatar
    Lucas De Marchi committed
    	/* Final destruction now no one is using it. */
    
    	if (mod->exit != NULL)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		mod->exit();
    
    	blocking_notifier_call_chain(&module_notify_list,
    				     MODULE_STATE_GOING, mod);
    
    	/* Store the name of the last unloaded module for diagnostic purposes */
    
    	strlcpy(last_unloaded_module, mod->name, sizeof(last_unloaded_module));
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	free_module(mod);
    	return 0;
    out:
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	return ret;
    }
    
    
    static inline void print_unload_info(struct seq_file *m, struct module *mod)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	struct module_use *use;
    	int printed_something = 0;
    
    
    	seq_printf(m, " %lu ", module_refcount(mod));
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    	/* Always include a trailing , so userspace can differentiate
               between this and the old multi-field proc format. */
    
    	list_for_each_entry(use, &mod->source_list, source_list) {
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		printed_something = 1;
    
    		seq_printf(m, "%s,", use->source->name);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    	}
    
    	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;
    
    
    	preempt_disable();
    
    	if (!find_symbol(symbol, &owner, NULL, true, false))
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    		BUG();
    	module_put(owner);
    
    	preempt_enable();
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    EXPORT_SYMBOL(__symbol_put);
    
    
    /* Note this assumes addr is a function, which it currently always is. */
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    void symbol_put_addr(void *addr)
    {
    
    	struct module *modaddr;
    
    	unsigned long a = (unsigned long)dereference_function_descriptor(addr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    	/* 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(a);
    
    	BUG_ON(!modaddr);
    
    	module_put(modaddr);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    EXPORT_SYMBOL_GPL(symbol_put_addr);
    
    static ssize_t show_refcnt(struct module_attribute *mattr,
    
    			   struct module_kobject *mk, char *buffer)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	return sprintf(buffer, "%lu\n", module_refcount(mk->mod));
    
    static struct module_attribute modinfo_refcnt =
    	__ATTR(refcnt, 0444, show_refcnt, NULL);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    void __module_get(struct module *module)
    {
    	if (module) {
    		preempt_disable();
    		__this_cpu_inc(module->refptr->incs);
    		trace_module_get(module, _RET_IP_);
    		preempt_enable();
    	}
    }
    EXPORT_SYMBOL(__module_get);
    
    bool try_module_get(struct module *module)
    {
    	bool ret = true;
    
    	if (module) {
    		preempt_disable();
    
    		if (likely(module_is_live(module))) {
    			__this_cpu_inc(module->refptr->incs);
    			trace_module_get(module, _RET_IP_);
    		} else
    			ret = false;
    
    		preempt_enable();
    	}
    	return ret;
    }
    EXPORT_SYMBOL(try_module_get);
    
    
    void module_put(struct module *module)
    {
    	if (module) {
    
    		smp_wmb(); /* see comment in module_refcount */
    		__this_cpu_inc(module->refptr->decs);
    
    		trace_module_put(module, _RET_IP_);
    
    	}
    }
    EXPORT_SYMBOL(module_put);
    
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    #else /* !CONFIG_MODULE_UNLOAD */
    
    static inline void print_unload_info(struct seq_file *m, struct module *mod)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    	/* We don't know the usage count, or what modules are using. */
    	seq_printf(m, " - -");
    }
    
    static inline void module_unload_free(struct module *mod)
    {
    }
    
    
    int ref_module(struct module *a, struct module *b)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {
    
    	return strong_try_module_get(b);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    }
    
    EXPORT_SYMBOL_GPL(ref_module);
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    
    
    static inline int module_unload_init(struct module *mod)
    
    Linus Torvalds's avatar
    Linus Torvalds committed
    {