mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	module: encapsulate percpu handling better and record percpu_size
Better encapsulate module static percpu area handling so that code outsidef of CONFIG_SMP ifdef doesn't deal with mod->percpu directly and add mod->percpu_size and record percpu_size in it. Both percpu fields are compiled out on UP. While at it, mark mod->percpu w/ __percpu. This is to prepare for is_module_percpu_address(). Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
		
							parent
							
								
									b72c40949b
								
							
						
					
					
						commit
						259354deaa
					
				
					 2 changed files with 39 additions and 32 deletions
				
			
		| 
						 | 
					@ -330,8 +330,11 @@ struct module
 | 
				
			||||||
	struct module_notes_attrs *notes_attrs;
 | 
						struct module_notes_attrs *notes_attrs;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
	/* Per-cpu data. */
 | 
						/* Per-cpu data. */
 | 
				
			||||||
	void *percpu;
 | 
						void __percpu *percpu;
 | 
				
			||||||
 | 
						unsigned int percpu_size;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* The command line arguments (may be mangled).  People like
 | 
						/* The command line arguments (may be mangled).  People like
 | 
				
			||||||
	   keeping pointers to this stuff */
 | 
						   keeping pointers to this stuff */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -370,27 +370,33 @@ EXPORT_SYMBOL_GPL(find_module);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void *percpu_modalloc(unsigned long size, unsigned long align,
 | 
					static inline void __percpu *mod_percpu(struct module *mod)
 | 
				
			||||||
			     const char *name)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	void *ptr;
 | 
						return mod->percpu;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int percpu_modalloc(struct module *mod,
 | 
				
			||||||
 | 
								   unsigned long size, unsigned long align)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
	if (align > PAGE_SIZE) {
 | 
						if (align > PAGE_SIZE) {
 | 
				
			||||||
		printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n",
 | 
							printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n",
 | 
				
			||||||
		       name, align, PAGE_SIZE);
 | 
							       mod->name, align, PAGE_SIZE);
 | 
				
			||||||
		align = PAGE_SIZE;
 | 
							align = PAGE_SIZE;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ptr = __alloc_reserved_percpu(size, align);
 | 
						mod->percpu = __alloc_reserved_percpu(size, align);
 | 
				
			||||||
	if (!ptr)
 | 
						if (!mod->percpu) {
 | 
				
			||||||
		printk(KERN_WARNING
 | 
							printk(KERN_WARNING
 | 
				
			||||||
		       "Could not allocate %lu bytes percpu data\n", size);
 | 
							       "Could not allocate %lu bytes percpu data\n", size);
 | 
				
			||||||
	return ptr;
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						mod->percpu_size = size;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void percpu_modfree(void *freeme)
 | 
					static void percpu_modfree(struct module *mod)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	free_percpu(freeme);
 | 
						free_percpu(mod->percpu);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned int find_pcpusec(Elf_Ehdr *hdr,
 | 
					static unsigned int find_pcpusec(Elf_Ehdr *hdr,
 | 
				
			||||||
| 
						 | 
					@ -400,24 +406,28 @@ static unsigned int find_pcpusec(Elf_Ehdr *hdr,
 | 
				
			||||||
	return find_sec(hdr, sechdrs, secstrings, ".data.percpu");
 | 
						return find_sec(hdr, sechdrs, secstrings, ".data.percpu");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void percpu_modcopy(void *pcpudest, const void *from, unsigned long size)
 | 
					static void percpu_modcopy(struct module *mod,
 | 
				
			||||||
 | 
								   const void *from, unsigned long size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int cpu;
 | 
						int cpu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_possible_cpu(cpu)
 | 
						for_each_possible_cpu(cpu)
 | 
				
			||||||
		memcpy(pcpudest + per_cpu_offset(cpu), from, size);
 | 
							memcpy(per_cpu_ptr(mod->percpu, cpu), from, size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else /* ... !CONFIG_SMP */
 | 
					#else /* ... !CONFIG_SMP */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void *percpu_modalloc(unsigned long size, unsigned long align,
 | 
					static inline void __percpu *mod_percpu(struct module *mod)
 | 
				
			||||||
				    const char *name)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static inline void percpu_modfree(void *pcpuptr)
 | 
					static inline int percpu_modalloc(struct module *mod,
 | 
				
			||||||
 | 
									  unsigned long size, unsigned long align)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return -ENOMEM;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					static inline void percpu_modfree(struct module *mod)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	BUG();
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static inline unsigned int find_pcpusec(Elf_Ehdr *hdr,
 | 
					static inline unsigned int find_pcpusec(Elf_Ehdr *hdr,
 | 
				
			||||||
					Elf_Shdr *sechdrs,
 | 
										Elf_Shdr *sechdrs,
 | 
				
			||||||
| 
						 | 
					@ -425,8 +435,8 @@ static inline unsigned int find_pcpusec(Elf_Ehdr *hdr,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static inline void percpu_modcopy(void *pcpudst, const void *src,
 | 
					static inline void percpu_modcopy(struct module *mod,
 | 
				
			||||||
				  unsigned long size)
 | 
									  const void *from, unsigned long size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* pcpusec should be 0, and size of that section should be 0. */
 | 
						/* pcpusec should be 0, and size of that section should be 0. */
 | 
				
			||||||
	BUG_ON(size != 0);
 | 
						BUG_ON(size != 0);
 | 
				
			||||||
| 
						 | 
					@ -1400,8 +1410,7 @@ static void free_module(struct module *mod)
 | 
				
			||||||
	/* This may be NULL, but that's OK */
 | 
						/* This may be NULL, but that's OK */
 | 
				
			||||||
	module_free(mod, mod->module_init);
 | 
						module_free(mod, mod->module_init);
 | 
				
			||||||
	kfree(mod->args);
 | 
						kfree(mod->args);
 | 
				
			||||||
	if (mod->percpu)
 | 
						percpu_modfree(mod);
 | 
				
			||||||
		percpu_modfree(mod->percpu);
 | 
					 | 
				
			||||||
#if defined(CONFIG_MODULE_UNLOAD)
 | 
					#if defined(CONFIG_MODULE_UNLOAD)
 | 
				
			||||||
	if (mod->refptr)
 | 
						if (mod->refptr)
 | 
				
			||||||
		free_percpu(mod->refptr);
 | 
							free_percpu(mod->refptr);
 | 
				
			||||||
| 
						 | 
					@ -1520,7 +1529,7 @@ static int simplify_symbols(Elf_Shdr *sechdrs,
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			/* Divert to percpu allocation if a percpu var. */
 | 
								/* Divert to percpu allocation if a percpu var. */
 | 
				
			||||||
			if (sym[i].st_shndx == pcpuindex)
 | 
								if (sym[i].st_shndx == pcpuindex)
 | 
				
			||||||
				secbase = (unsigned long)mod->percpu;
 | 
									secbase = (unsigned long)mod_percpu(mod);
 | 
				
			||||||
			else
 | 
								else
 | 
				
			||||||
				secbase = sechdrs[sym[i].st_shndx].sh_addr;
 | 
									secbase = sechdrs[sym[i].st_shndx].sh_addr;
 | 
				
			||||||
			sym[i].st_value += secbase;
 | 
								sym[i].st_value += secbase;
 | 
				
			||||||
| 
						 | 
					@ -1954,7 +1963,7 @@ static noinline struct module *load_module(void __user *umod,
 | 
				
			||||||
	unsigned int modindex, versindex, infoindex, pcpuindex;
 | 
						unsigned int modindex, versindex, infoindex, pcpuindex;
 | 
				
			||||||
	struct module *mod;
 | 
						struct module *mod;
 | 
				
			||||||
	long err = 0;
 | 
						long err = 0;
 | 
				
			||||||
	void *percpu = NULL, *ptr = NULL; /* Stops spurious gcc warning */
 | 
						void *ptr = NULL; /* Stops spurious gcc warning */
 | 
				
			||||||
	unsigned long symoffs, stroffs, *strmap;
 | 
						unsigned long symoffs, stroffs, *strmap;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mm_segment_t old_fs;
 | 
						mm_segment_t old_fs;
 | 
				
			||||||
| 
						 | 
					@ -2094,15 +2103,11 @@ static noinline struct module *load_module(void __user *umod,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pcpuindex) {
 | 
						if (pcpuindex) {
 | 
				
			||||||
		/* We have a special allocation for this section. */
 | 
							/* We have a special allocation for this section. */
 | 
				
			||||||
		percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size,
 | 
							err = percpu_modalloc(mod, sechdrs[pcpuindex].sh_size,
 | 
				
			||||||
					 sechdrs[pcpuindex].sh_addralign,
 | 
									      sechdrs[pcpuindex].sh_addralign);
 | 
				
			||||||
					 mod->name);
 | 
							if (err)
 | 
				
			||||||
		if (!percpu) {
 | 
					 | 
				
			||||||
			err = -ENOMEM;
 | 
					 | 
				
			||||||
			goto free_mod;
 | 
								goto free_mod;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
 | 
							sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC;
 | 
				
			||||||
		mod->percpu = percpu;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Determine total sizes, and put offsets in sh_entsize.  For now
 | 
						/* Determine total sizes, and put offsets in sh_entsize.  For now
 | 
				
			||||||
| 
						 | 
					@ -2317,7 +2322,7 @@ static noinline struct module *load_module(void __user *umod,
 | 
				
			||||||
	sort_extable(mod->extable, mod->extable + mod->num_exentries);
 | 
						sort_extable(mod->extable, mod->extable + mod->num_exentries);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Finally, copy percpu area over. */
 | 
						/* Finally, copy percpu area over. */
 | 
				
			||||||
	percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr,
 | 
						percpu_modcopy(mod, (void *)sechdrs[pcpuindex].sh_addr,
 | 
				
			||||||
		       sechdrs[pcpuindex].sh_size);
 | 
							       sechdrs[pcpuindex].sh_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	add_kallsyms(mod, sechdrs, hdr->e_shnum, symindex, strindex,
 | 
						add_kallsyms(mod, sechdrs, hdr->e_shnum, symindex, strindex,
 | 
				
			||||||
| 
						 | 
					@ -2409,8 +2414,7 @@ static noinline struct module *load_module(void __user *umod,
 | 
				
			||||||
	module_free(mod, mod->module_core);
 | 
						module_free(mod, mod->module_core);
 | 
				
			||||||
	/* mod will be freed with core. Don't access it beyond this line! */
 | 
						/* mod will be freed with core. Don't access it beyond this line! */
 | 
				
			||||||
 free_percpu:
 | 
					 free_percpu:
 | 
				
			||||||
	if (percpu)
 | 
						percpu_modfree(mod);
 | 
				
			||||||
		percpu_modfree(percpu);
 | 
					 | 
				
			||||||
 free_mod:
 | 
					 free_mod:
 | 
				
			||||||
	kfree(args);
 | 
						kfree(args);
 | 
				
			||||||
	kfree(strmap);
 | 
						kfree(strmap);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue