2108 lines · 52.8 KB · C
RawDownload
/* Rewritten by Rusty Russell, on the backs of many others...   Copyright (C) 2002 Richard Henderson   Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM.     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/config.h>#include <linux/module.h>#include <linux/moduleloader.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/elf.h>#include <linux/seq_file.h>#include <linux/syscalls.h>#include <linux/fcntl.h>#include <linux/rcupdate.h>#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/stop_machine.h>#include <linux/device.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <asm/cacheflush.h> #if 0#define DEBUGP printk#else#define DEBUGP(fmt , a...)#endif #ifndef ARCH_SHF_SMALL#define ARCH_SHF_SMALL 0#endif /* If this is set, the section belongs in the init part of the module */#define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1)) /* Protects module list */static DEFINE_SPINLOCK(modlist_lock); /* List of modules, protected by module_mutex AND modlist_lock */static DECLARE_MUTEX(module_mutex);static LIST_HEAD(modules); static DECLARE_MUTEX(notify_mutex);static struct notifier_block * module_notify_list; int register_module_notifier(struct notifier_block * nb){	int err;	down(&notify_mutex);	err = notifier_chain_register(&module_notify_list, nb);	up(&notify_mutex);	return err;}EXPORT_SYMBOL(register_module_notifier); int unregister_module_notifier(struct notifier_block * nb){	int err;	down(&notify_mutex);	err = notifier_chain_unregister(&module_notify_list, nb);	up(&notify_mutex);	return err;}EXPORT_SYMBOL(unregister_module_notifier); /* We require a truly strong try_module_get() */static inline int strong_try_module_get(struct module *mod){	if (mod && mod->state == MODULE_STATE_COMING)		return 0;	return try_module_get(mod);} /* A thread that wants to hold a reference to a module only while it * is running can call ths to safely exit. * nfsd and lockd use this. */void __module_put_and_exit(struct module *mod, long code){	module_put(mod);	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,			     const char *secstrings,			     const char *name){	unsigned int i; 	for (i = 1; i < hdr->e_shnum; i++)		/* Alloc bit cleared means "ignore it." */		if ((sechdrs[i].sh_flags & SHF_ALLOC)		    && strcmp(secstrings+sechdrs[i].sh_name, name) == 0)			return i;	return 0;} /* 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 unsigned long __start___kcrctab[];extern const unsigned long __start___kcrctab_gpl[]; #ifndef CONFIG_MODVERSIONS#define symversion(base, idx) NULL#else#define symversion(base, idx) ((base) ? ((base) + (idx)) : NULL)#endif /* Find a symbol, return value, crc and module which owns it */static unsigned long __find_symbol(const char *name,				   struct module **owner,				   const unsigned long **crc,				   int gplok){	struct module *mod;	unsigned int i; 	/* Core kernel first. */ 	*owner = NULL;	for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) {		if (strcmp(__start___ksymtab[i].name, name) == 0) {			*crc = symversion(__start___kcrctab, i);			return __start___ksymtab[i].value;		}	}	if (gplok) {		for (i = 0; __start___ksymtab_gpl+i<__stop___ksymtab_gpl; i++)			if (strcmp(__start___ksymtab_gpl[i].name, name) == 0) {				*crc = symversion(__start___kcrctab_gpl, i);				return __start___ksymtab_gpl[i].value;			}	} 	/* Now try modules. */ 	list_for_each_entry(mod, &modules, list) {		*owner = mod;		for (i = 0; i < mod->num_syms; i++)			if (strcmp(mod->syms[i].name, name) == 0) {				*crc = symversion(mod->crcs, i);				return mod->syms[i].value;			} 		if (gplok) {			for (i = 0; i < mod->num_gpl_syms; i++) {				if (strcmp(mod->gpl_syms[i].name, name) == 0) {					*crc = symversion(mod->gpl_crcs, i);					return mod->gpl_syms[i].value;				}			}		}	}	DEBUGP("Failed to find symbol %s\n", name); 	return 0;} /* Find a symbol in this elf symbol table */static unsigned long find_local_symbol(Elf_Shdr *sechdrs,				       unsigned int symindex,				       const char *strtab,				       const char *name){	unsigned int i;	Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; 	/* Search (defined) internal symbols first. */	for (i = 1; i < sechdrs[symindex].sh_size/sizeof(*sym); i++) {		if (sym[i].st_shndx != SHN_UNDEF		    && strcmp(name, strtab + sym[i].st_name) == 0)			return sym[i].st_value;	}	return 0;} /* Search for module by name: must hold module_mutex. */static struct module *find_module(const char *name){	struct module *mod; 	list_for_each_entry(mod, &modules, list) {		if (strcmp(mod->name, name) == 0)			return mod;	}	return NULL;} #ifdef CONFIG_SMP/* Number of blocks used and allocated. */static unsigned int pcpu_num_used, pcpu_num_allocated;/* Size of each block.  -ve means used. */static int *pcpu_size; static int split_block(unsigned int i, unsigned short size){	/* Reallocation required? */	if (pcpu_num_used + 1 > pcpu_num_allocated) {		int *new = kmalloc(sizeof(new[0]) * pcpu_num_allocated*2,				   GFP_KERNEL);		if (!new)			return 0; 		memcpy(new, pcpu_size, sizeof(new[0])*pcpu_num_allocated);		pcpu_num_allocated *= 2;		kfree(pcpu_size);		pcpu_size = new;	} 	/* Insert a new subblock */	memmove(&pcpu_size[i+1], &pcpu_size[i],		sizeof(pcpu_size[0]) * (pcpu_num_used - i));	pcpu_num_used++; 	pcpu_size[i+1] -= size;	pcpu_size[i] = size;	return 1;} static inline unsigned int block_size(int val){	if (val < 0)		return -val;	return val;} /* Created by linker magic */extern char __per_cpu_start[], __per_cpu_end[]; static void *percpu_modalloc(unsigned long size, unsigned long align){	unsigned long extra;	unsigned int i;	void *ptr; 	BUG_ON(align > SMP_CACHE_BYTES); 	ptr = __per_cpu_start;	for (i = 0; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) {		/* Extra for alignment requirement. */		extra = ALIGN((unsigned long)ptr, align) - (unsigned long)ptr;		BUG_ON(i == 0 && extra != 0); 		if (pcpu_size[i] < 0 || pcpu_size[i] < extra + size)			continue; 		/* Transfer extra to previous block. */		if (pcpu_size[i-1] < 0)			pcpu_size[i-1] -= extra;		else			pcpu_size[i-1] += extra;		pcpu_size[i] -= extra;		ptr += extra; 		/* Split block if warranted */		if (pcpu_size[i] - size > sizeof(unsigned long))			if (!split_block(i, size))				return NULL; 		/* Mark allocated */		pcpu_size[i] = -pcpu_size[i];		return ptr;	} 	printk(KERN_WARNING "Could not allocate %lu bytes percpu data\n",	       size);	return NULL;} static void percpu_modfree(void *freeme){	unsigned int i;	void *ptr = __per_cpu_start + block_size(pcpu_size[0]); 	/* First entry is core kernel percpu data. */	for (i = 1; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) {		if (ptr == freeme) {			pcpu_size[i] = -pcpu_size[i];			goto free;		}	}	BUG();  free:	/* Merge with previous? */	if (pcpu_size[i-1] >= 0) {		pcpu_size[i-1] += pcpu_size[i];		pcpu_num_used--;		memmove(&pcpu_size[i], &pcpu_size[i+1],			(pcpu_num_used - i) * sizeof(pcpu_size[0]));		i--;	}	/* Merge with next? */	if (i+1 < pcpu_num_used && pcpu_size[i+1] >= 0) {		pcpu_size[i] += pcpu_size[i+1];		pcpu_num_used--;		memmove(&pcpu_size[i+1], &pcpu_size[i+2],			(pcpu_num_used - (i+1)) * sizeof(pcpu_size[0]));	}} static unsigned int find_pcpusec(Elf_Ehdr *hdr,				 Elf_Shdr *sechdrs,				 const char *secstrings){	return find_sec(hdr, sechdrs, secstrings, ".data.percpu");} static int percpu_modinit(void){	pcpu_num_used = 2;	pcpu_num_allocated = 2;	pcpu_size = kmalloc(sizeof(pcpu_size[0]) * pcpu_num_allocated,			    GFP_KERNEL);	/* Static in-kernel percpu data (used). */	pcpu_size[0] = -ALIGN(__per_cpu_end-__per_cpu_start, SMP_CACHE_BYTES);	/* Free room. */	pcpu_size[1] = PERCPU_ENOUGH_ROOM + pcpu_size[0];	if (pcpu_size[1] < 0) {		printk(KERN_ERR "No per-cpu room for modules.\n");		pcpu_num_used = 1;	} 	return 0;}	__initcall(percpu_modinit);#else /* ... !CONFIG_SMP */static inline void *percpu_modalloc(unsigned long size, unsigned long align){	return NULL;}static inline void percpu_modfree(void *pcpuptr){	BUG();}static inline unsigned int find_pcpusec(Elf_Ehdr *hdr,					Elf_Shdr *sechdrs,					const char *secstrings){	return 0;}static inline void percpu_modcopy(void *pcpudst, const void *src,				  unsigned long size){	/* pcpusec should be 0, and size of that section should be 0. */	BUG_ON(size != 0);}#endif /* CONFIG_SMP */ #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[_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;	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);	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);				/* There can be at most one match. */				break;			}		}	}} #ifdef CONFIG_MODULE_FORCE_UNLOADstatic inline int try_force(unsigned int flags){	int ret = (flags & O_TRUNC);	if (ret)		tainted |= TAINT_FORCED_MODULE;	return ret;}#elsestatic inline int try_force(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(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; 

Lines 1–500 of 2108.