diff options
Diffstat (limited to 'kernel/module.c')
| -rw-r--r-- | kernel/module.c | 77 | 
1 files changed, 43 insertions, 34 deletions
| diff --git a/kernel/module.c b/kernel/module.c index cab4bce49c2..206915830d2 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -455,7 +455,7 @@ const struct kernel_symbol *find_symbol(const char *name,  EXPORT_SYMBOL_GPL(find_symbol);  /* Search for module by name: must hold module_mutex. */ -static struct module *find_module_all(const char *name, +static struct module *find_module_all(const char *name, size_t len,  				      bool even_unformed)  {  	struct module *mod; @@ -463,7 +463,7 @@ static struct module *find_module_all(const char *name,  	list_for_each_entry(mod, &modules, list) {  		if (!even_unformed && mod->state == MODULE_STATE_UNFORMED)  			continue; -		if (strcmp(mod->name, name) == 0) +		if (strlen(mod->name) == len && !memcmp(mod->name, name, len))  			return mod;  	}  	return NULL; @@ -471,7 +471,7 @@ static struct module *find_module_all(const char *name,  struct module *find_module(const char *name)  { -	return find_module_all(name, false); +	return find_module_all(name, strlen(name), false);  }  EXPORT_SYMBOL_GPL(find_module); @@ -482,23 +482,28 @@ static inline void __percpu *mod_percpu(struct module *mod)  	return mod->percpu;  } -static int percpu_modalloc(struct module *mod, -			   unsigned long size, unsigned long align) +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) {  		printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n",  		       mod->name, align, PAGE_SIZE);  		align = PAGE_SIZE;  	} -	mod->percpu = __alloc_reserved_percpu(size, align); +	mod->percpu = __alloc_reserved_percpu(pcpusec->sh_size, align);  	if (!mod->percpu) {  		printk(KERN_WARNING  		       "%s: Could not allocate %lu bytes percpu data\n", -		       mod->name, size); +		       mod->name, (unsigned long)pcpusec->sh_size);  		return -ENOMEM;  	} -	mod->percpu_size = size; +	mod->percpu_size = pcpusec->sh_size;  	return 0;  } @@ -563,10 +568,12 @@ static inline void __percpu *mod_percpu(struct module *mod)  {  	return NULL;  } -static inline int percpu_modalloc(struct module *mod, -				  unsigned long size, unsigned long align) +static int percpu_modalloc(struct module *mod, struct load_info *info)  { -	return -ENOMEM; +	/* 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)  { @@ -2927,7 +2934,6 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)  {  	/* Module within temporary copy. */  	struct module *mod; -	Elf_Shdr *pcpusec;  	int err;  	mod = setup_load_info(info, flags); @@ -2942,17 +2948,10 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)  	err = module_frob_arch_sections(info->hdr, info->sechdrs,  					info->secstrings, mod);  	if (err < 0) -		goto out; +		return ERR_PTR(err); -	pcpusec = &info->sechdrs[info->index.pcpu]; -	if (pcpusec->sh_size) { -		/* We have a special allocation for this section. */ -		err = percpu_modalloc(mod, -				      pcpusec->sh_size, pcpusec->sh_addralign); -		if (err) -			goto out; -		pcpusec->sh_flags &= ~(unsigned long)SHF_ALLOC; -	} +	/* We will do a special allocation for per-cpu sections later. */ +	info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC;  	/* Determine total sizes, and put offsets in sh_entsize.  For now  	   this is done generically; there doesn't appear to be any @@ -2963,17 +2962,12 @@ static struct module *layout_and_allocate(struct load_info *info, int flags)  	/* Allocate and move to the final place */  	err = move_module(mod, info);  	if (err) -		goto free_percpu; +		return ERR_PTR(err);  	/* Module has been copied to its final place now: return it. */  	mod = (void *)info->sechdrs[info->index.mod].sh_addr;  	kmemleak_load_module(mod, info);  	return mod; - -free_percpu: -	percpu_modfree(mod); -out: -	return ERR_PTR(err);  }  /* mod is no longer valid after this! */ @@ -3014,7 +3008,7 @@ static bool finished_loading(const char *name)  	bool ret;  	mutex_lock(&module_mutex); -	mod = find_module_all(name, true); +	mod = find_module_all(name, strlen(name), true);  	ret = !mod || mod->state == MODULE_STATE_LIVE  		|| mod->state == MODULE_STATE_GOING;  	mutex_unlock(&module_mutex); @@ -3152,7 +3146,8 @@ static int add_unformed_module(struct module *mod)  again:  	mutex_lock(&module_mutex); -	if ((old = find_module_all(mod->name, true)) != NULL) { +	old = find_module_all(mod->name, strlen(mod->name), true); +	if (old != NULL) {  		if (old->state == MODULE_STATE_COMING  		    || old->state == MODULE_STATE_UNFORMED) {  			/* Wait in case it fails to load. */ @@ -3198,6 +3193,17 @@ out:  	return err;  } +static int unknown_module_param_cb(char *param, char *val, const char *modname) +{ +	/* Check for magic 'dyndbg' arg */  +	int ret = ddebug_dyndbg_module_param_cb(param, val, modname); +	if (ret != 0) { +		printk(KERN_WARNING "%s: unknown parameter '%s' ignored\n", +		       modname, param); +	} +	return 0; +} +  /* Allocate and load the module: note that size of section 0 is always     zero, and we rely on this for optional sections. */  static int load_module(struct load_info *info, const char __user *uargs, @@ -3237,6 +3243,11 @@ static int load_module(struct load_info *info, const char __user *uargs,  	}  #endif +	/* To avoid stressing percpu allocator, do this once we're unique. */ +	err = percpu_modalloc(mod, info); +	if (err) +		goto unlink_mod; +  	/* Now module is in final location, initialize linked lists, etc. */  	err = module_unload_init(mod);  	if (err) @@ -3284,7 +3295,7 @@ static int load_module(struct load_info *info, const char __user *uargs,  	/* Module is ready to execute: parsing args may do that. */  	err = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, -			 -32768, 32767, &ddebug_dyndbg_module_param_cb); +			 -32768, 32767, unknown_module_param_cb);  	if (err < 0)  		goto bug_cleanup; @@ -3563,10 +3574,8 @@ unsigned long module_kallsyms_lookup_name(const char *name)  	/* Don't lock: we're in enough trouble already. */  	preempt_disable();  	if ((colon = strchr(name, ':')) != NULL) { -		*colon = '\0'; -		if ((mod = find_module(name)) != NULL) +		if ((mod = find_module_all(name, colon - name, false)) != NULL)  			ret = mod_find_symname(mod, colon+1); -		*colon = ':';  	} else {  		list_for_each_entry_rcu(mod, &modules, list) {  			if (mod->state == MODULE_STATE_UNFORMED) | 
