diff options
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 34 |
1 files changed, 18 insertions, 16 deletions
diff --git a/kernel/module.c b/kernel/module.c index cab4bce49c23..fa53db8aadeb 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
@@ -2927,7 +2927,6 @@ static struct module *layout_and_allocate(struct load_info *info, int flags) | |||
2927 | { | 2927 | { |
2928 | /* Module within temporary copy. */ | 2928 | /* Module within temporary copy. */ |
2929 | struct module *mod; | 2929 | struct module *mod; |
2930 | Elf_Shdr *pcpusec; | ||
2931 | int err; | 2930 | int err; |
2932 | 2931 | ||
2933 | mod = setup_load_info(info, flags); | 2932 | mod = setup_load_info(info, flags); |
@@ -2942,17 +2941,10 @@ static struct module *layout_and_allocate(struct load_info *info, int flags) | |||
2942 | err = module_frob_arch_sections(info->hdr, info->sechdrs, | 2941 | err = module_frob_arch_sections(info->hdr, info->sechdrs, |
2943 | info->secstrings, mod); | 2942 | info->secstrings, mod); |
2944 | if (err < 0) | 2943 | if (err < 0) |
2945 | goto out; | 2944 | return ERR_PTR(err); |
2946 | 2945 | ||
2947 | pcpusec = &info->sechdrs[info->index.pcpu]; | 2946 | /* We will do a special allocation for per-cpu sections later. */ |
2948 | if (pcpusec->sh_size) { | 2947 | info->sechdrs[info->index.pcpu].sh_flags &= ~(unsigned long)SHF_ALLOC; |
2949 | /* We have a special allocation for this section. */ | ||
2950 | err = percpu_modalloc(mod, | ||
2951 | pcpusec->sh_size, pcpusec->sh_addralign); | ||
2952 | if (err) | ||
2953 | goto out; | ||
2954 | pcpusec->sh_flags &= ~(unsigned long)SHF_ALLOC; | ||
2955 | } | ||
2956 | 2948 | ||
2957 | /* Determine total sizes, and put offsets in sh_entsize. For now | 2949 | /* Determine total sizes, and put offsets in sh_entsize. For now |
2958 | this is done generically; there doesn't appear to be any | 2950 | this is done generically; there doesn't appear to be any |
@@ -2963,17 +2955,22 @@ static struct module *layout_and_allocate(struct load_info *info, int flags) | |||
2963 | /* Allocate and move to the final place */ | 2955 | /* Allocate and move to the final place */ |
2964 | err = move_module(mod, info); | 2956 | err = move_module(mod, info); |
2965 | if (err) | 2957 | if (err) |
2966 | goto free_percpu; | 2958 | return ERR_PTR(err); |
2967 | 2959 | ||
2968 | /* Module has been copied to its final place now: return it. */ | 2960 | /* Module has been copied to its final place now: return it. */ |
2969 | mod = (void *)info->sechdrs[info->index.mod].sh_addr; | 2961 | mod = (void *)info->sechdrs[info->index.mod].sh_addr; |
2970 | kmemleak_load_module(mod, info); | 2962 | kmemleak_load_module(mod, info); |
2971 | return mod; | 2963 | return mod; |
2964 | } | ||
2972 | 2965 | ||
2973 | free_percpu: | 2966 | static int alloc_module_percpu(struct module *mod, struct load_info *info) |
2974 | percpu_modfree(mod); | 2967 | { |
2975 | out: | 2968 | Elf_Shdr *pcpusec = &info->sechdrs[info->index.pcpu]; |
2976 | return ERR_PTR(err); | 2969 | if (!pcpusec->sh_size) |
2970 | return 0; | ||
2971 | |||
2972 | /* We have a special allocation for this section. */ | ||
2973 | return percpu_modalloc(mod, pcpusec->sh_size, pcpusec->sh_addralign); | ||
2977 | } | 2974 | } |
2978 | 2975 | ||
2979 | /* mod is no longer valid after this! */ | 2976 | /* mod is no longer valid after this! */ |
@@ -3237,6 +3234,11 @@ static int load_module(struct load_info *info, const char __user *uargs, | |||
3237 | } | 3234 | } |
3238 | #endif | 3235 | #endif |
3239 | 3236 | ||
3237 | /* To avoid stressing percpu allocator, do this once we're unique. */ | ||
3238 | err = alloc_module_percpu(mod, info); | ||
3239 | if (err) | ||
3240 | goto unlink_mod; | ||
3241 | |||
3240 | /* Now module is in final location, initialize linked lists, etc. */ | 3242 | /* Now module is in final location, initialize linked lists, etc. */ |
3241 | err = module_unload_init(mod); | 3243 | err = module_unload_init(mod); |
3242 | if (err) | 3244 | if (err) |