⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 module.c

📁 linux 2.6.19 kernel source code before patching
💻 C
📖 第 1 页 / 共 5 页
字号:
/*   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/module.h>#include <linux/moduleloader.h>#include <linux/init.h>#include <linux/kallsyms.h>#include <linux/kernel.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/capability.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/sched.h>#include <linux/stop_machine.h>#include <linux/device.h>#include <linux/string.h>#include <linux/mutex.h>#include <linux/unwind.h>#include <asm/uaccess.h>#include <asm/semaphore.h>#include <asm/cacheflush.h>#include <linux/license.h>extern int module_sysfs_initialized;#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 DEFINE_MUTEX(module_mutex);static LIST_HEAD(modules);static BLOCKING_NOTIFIER_HEAD(module_notify_list);int register_module_notifier(struct notifier_block * nb){	return blocking_notifier_chain_register(&module_notify_list, nb);}EXPORT_SYMBOL(register_module_notifier);int unregister_module_notifier(struct notifier_block * nb){	return blocking_notifier_chain_unregister(&module_notify_list, nb);}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);}static inline void add_taint_module(struct module *mod, unsigned flag){	add_taint(flag);	mod->taints |= 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. */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 struct kernel_symbol __start___ksymtab_gpl_future[];extern const struct kernel_symbol __stop___ksymtab_gpl_future[];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 struct kernel_symbol __start___ksymtab_gpl_future[];extern const struct kernel_symbol __stop___ksymtab_gpl_future[];extern const unsigned long __start___kcrctab[];extern const unsigned long __start___kcrctab_gpl[];extern const unsigned long __start___kcrctab_gpl_future[];extern const unsigned long __start___kcrctab_unused[];extern const unsigned long __start___kcrctab_unused_gpl[];#ifndef CONFIG_MODVERSIONS#define symversion(base, idx) NULL#else#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)#endif/* lookup symbol in given range of kernel_symbols */static const struct kernel_symbol *lookup_symbol(const char *name,	const struct kernel_symbol *start,	const struct kernel_symbol *stop){	const struct kernel_symbol *ks = start;	for (; ks < stop; ks++)		if (strcmp(ks->name, name) == 0)			return ks;	return NULL;}static void printk_unused_warning(const char *name){	printk(KERN_WARNING "Symbol %s is marked as UNUSED, "		"however this module is using it.\n", name);	printk(KERN_WARNING "This symbol will go away in the future.\n");	printk(KERN_WARNING "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");}/* 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;	const struct kernel_symbol *ks;	/* Core kernel first. */ 	*owner = NULL;	ks = lookup_symbol(name, __start___ksymtab, __stop___ksymtab);	if (ks) {		*crc = symversion(__start___kcrctab, (ks - __start___ksymtab));		return ks->value;	}	if (gplok) {		ks = lookup_symbol(name, __start___ksymtab_gpl,					 __stop___ksymtab_gpl);		if (ks) {			*crc = symversion(__start___kcrctab_gpl,					  (ks - __start___ksymtab_gpl));			return ks->value;		}	}	ks = lookup_symbol(name, __start___ksymtab_gpl_future,				 __stop___ksymtab_gpl_future);	if (ks) {		if (!gplok) {			printk(KERN_WARNING "Symbol %s is being used "			       "by a non-GPL module, which will not "			       "be allowed in the future\n", name);			printk(KERN_WARNING "Please see the file "			       "Documentation/feature-removal-schedule.txt "			       "in the kernel source tree for more "			       "details.\n");		}		*crc = symversion(__start___kcrctab_gpl_future,				  (ks - __start___ksymtab_gpl_future));		return ks->value;	}	ks = lookup_symbol(name, __start___ksymtab_unused,				 __stop___ksymtab_unused);	if (ks) {		printk_unused_warning(name);		*crc = symversion(__start___kcrctab_unused,				  (ks - __start___ksymtab_unused));		return ks->value;	}	if (gplok)		ks = lookup_symbol(name, __start___ksymtab_unused_gpl,				 __stop___ksymtab_unused_gpl);	if (ks) {		printk_unused_warning(name);		*crc = symversion(__start___kcrctab_unused_gpl,				  (ks - __start___ksymtab_unused_gpl));		return ks->value;	}	/* Now try modules. */ 	list_for_each_entry(mod, &modules, list) {		*owner = mod;		ks = lookup_symbol(name, mod->syms, mod->syms + mod->num_syms);		if (ks) {			*crc = symversion(mod->crcs, (ks - mod->syms));			return ks->value;		}		if (gplok) {			ks = lookup_symbol(name, mod->gpl_syms,					   mod->gpl_syms + mod->num_gpl_syms);			if (ks) {				*crc = symversion(mod->gpl_crcs,						  (ks - mod->gpl_syms));				return ks->value;			}		}		ks = lookup_symbol(name, mod->unused_syms, mod->unused_syms + mod->num_unused_syms);		if (ks) {			printk_unused_warning(name);			*crc = symversion(mod->unused_crcs, (ks - mod->unused_syms));			return ks->value;		}		if (gplok) {			ks = lookup_symbol(name, mod->unused_gpl_syms,					   mod->unused_gpl_syms + mod->num_unused_gpl_syms);			if (ks) {				printk_unused_warning(name);				*crc = symversion(mod->unused_gpl_crcs,						  (ks - mod->unused_gpl_syms));				return ks->value;			}		}		ks = lookup_symbol(name, mod->gpl_future_syms,				   (mod->gpl_future_syms +				    mod->num_gpl_future_syms));		if (ks) {			if (!gplok) {				printk(KERN_WARNING "Symbol %s is being used "				       "by a non-GPL module, which will not "				       "be allowed in the future\n", name);				printk(KERN_WARNING "Please see the file "				       "Documentation/feature-removal-schedule.txt "				       "in the kernel source tree for more "				       "details.\n");			}			*crc = symversion(mod->gpl_future_crcs,					  (ks - mod->gpl_future_syms));			return ks->value;		}	}	DEBUGP("Failed to find symbol %s\n", name); 	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;		new = krealloc(pcpu_size, sizeof(new[0])*pcpu_num_allocated*2,			       GFP_KERNEL);		if (!new)			return 0;		pcpu_num_allocated *= 2;		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,			     const char *name){	unsigned long extra;	unsigned int i;	void *ptr;	if (align > PAGE_SIZE) {		printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n",		       name, align, PAGE_SIZE);		align = PAGE_SIZE;	}	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] = -(__per_cpu_end-__per_cpu_start);	/* 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,				    const char *name){	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 */#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 *mod, char *buffer)             \{                                                                     \	return sprintf(buffer, "%s\n", 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,           \		  .owner = THIS_MODULE },                             \	.show = show_modinfo_##field,                                 \	.setup = setup_modinfo_##field,                               \	.test = modinfo_##field##_exists,                             \	.free = free_modinfo_##field,                                 \};MODINFO_ATTR(version);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -