diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-18 00:46:32 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-18 00:46:32 -0400 |
| commit | 0f49fc95b86fc77b867d643e2d38bc9f28035ed4 (patch) | |
| tree | cdc6297fe95893905d7192df1e7dfb877517eead | |
| parent | 49dc2b7173010792c6923930ffcee84b7094b7de (diff) | |
| parent | 7e545d6eca20ce8ef7f66a63146cbff82b2ba760 (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching
Pull livepatching update from Jiri Kosina:
- cleanup of module notifiers; this depends on a module.c cleanup which
has been acked by Rusty; from Jessica Yu
- small assorted fixes and MAINTAINERS update
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/livepatching:
livepatch/module: remove livepatch module notifier
modules: split part of complete_formation() into prepare_coming_module()
livepatch: Update maintainers
livepatch: Fix the error message about unresolvable ambiguity
klp: remove CONFIG_LIVEPATCH dependency from klp headers
klp: remove superfluous errors in asm/livepatch.h
| -rw-r--r-- | MAINTAINERS | 5 | ||||
| -rw-r--r-- | arch/s390/include/asm/livepatch.h | 4 | ||||
| -rw-r--r-- | arch/x86/include/asm/livepatch.h | 4 | ||||
| -rw-r--r-- | include/linux/livepatch.h | 9 | ||||
| -rw-r--r-- | kernel/livepatch/core.c | 151 | ||||
| -rw-r--r-- | kernel/module.c | 36 |
6 files changed, 113 insertions, 96 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index e32f4847e251..94ea42b76b30 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -6596,9 +6596,10 @@ F: drivers/platform/x86/hp_accel.c | |||
| 6596 | 6596 | ||
| 6597 | LIVE PATCHING | 6597 | LIVE PATCHING |
| 6598 | M: Josh Poimboeuf <jpoimboe@redhat.com> | 6598 | M: Josh Poimboeuf <jpoimboe@redhat.com> |
| 6599 | M: Seth Jennings <sjenning@redhat.com> | 6599 | M: Jessica Yu <jeyu@redhat.com> |
| 6600 | M: Jiri Kosina <jikos@kernel.org> | 6600 | M: Jiri Kosina <jikos@kernel.org> |
| 6601 | M: Vojtech Pavlik <vojtech@suse.com> | 6601 | M: Miroslav Benes <mbenes@suse.cz> |
| 6602 | R: Petr Mladek <pmladek@suse.com> | ||
| 6602 | S: Maintained | 6603 | S: Maintained |
| 6603 | F: kernel/livepatch/ | 6604 | F: kernel/livepatch/ |
| 6604 | F: include/linux/livepatch.h | 6605 | F: include/linux/livepatch.h |
diff --git a/arch/s390/include/asm/livepatch.h b/arch/s390/include/asm/livepatch.h index a52b6cca873d..d5427c78b1b3 100644 --- a/arch/s390/include/asm/livepatch.h +++ b/arch/s390/include/asm/livepatch.h | |||
| @@ -19,7 +19,6 @@ | |||
| 19 | 19 | ||
| 20 | #include <linux/module.h> | 20 | #include <linux/module.h> |
| 21 | 21 | ||
| 22 | #ifdef CONFIG_LIVEPATCH | ||
| 23 | static inline int klp_check_compiler_support(void) | 22 | static inline int klp_check_compiler_support(void) |
| 24 | { | 23 | { |
| 25 | return 0; | 24 | return 0; |
| @@ -36,8 +35,5 @@ static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip) | |||
| 36 | { | 35 | { |
| 37 | regs->psw.addr = ip; | 36 | regs->psw.addr = ip; |
| 38 | } | 37 | } |
| 39 | #else | ||
| 40 | #error Include linux/livepatch.h, not asm/livepatch.h | ||
| 41 | #endif | ||
| 42 | 38 | ||
| 43 | #endif | 39 | #endif |
diff --git a/arch/x86/include/asm/livepatch.h b/arch/x86/include/asm/livepatch.h index e795f5274217..7e68f9558552 100644 --- a/arch/x86/include/asm/livepatch.h +++ b/arch/x86/include/asm/livepatch.h | |||
| @@ -25,7 +25,6 @@ | |||
| 25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
| 26 | #include <linux/ftrace.h> | 26 | #include <linux/ftrace.h> |
| 27 | 27 | ||
| 28 | #ifdef CONFIG_LIVEPATCH | ||
| 29 | static inline int klp_check_compiler_support(void) | 28 | static inline int klp_check_compiler_support(void) |
| 30 | { | 29 | { |
| 31 | #ifndef CC_USING_FENTRY | 30 | #ifndef CC_USING_FENTRY |
| @@ -40,8 +39,5 @@ static inline void klp_arch_set_pc(struct pt_regs *regs, unsigned long ip) | |||
| 40 | { | 39 | { |
| 41 | regs->ip = ip; | 40 | regs->ip = ip; |
| 42 | } | 41 | } |
| 43 | #else | ||
| 44 | #error Include linux/livepatch.h, not asm/livepatch.h | ||
| 45 | #endif | ||
| 46 | 42 | ||
| 47 | #endif /* _ASM_X86_LIVEPATCH_H */ | 43 | #endif /* _ASM_X86_LIVEPATCH_H */ |
diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h index a8828652f794..bd830d590465 100644 --- a/include/linux/livepatch.h +++ b/include/linux/livepatch.h | |||
| @@ -134,6 +134,15 @@ int klp_unregister_patch(struct klp_patch *); | |||
| 134 | int klp_enable_patch(struct klp_patch *); | 134 | int klp_enable_patch(struct klp_patch *); |
| 135 | int klp_disable_patch(struct klp_patch *); | 135 | int klp_disable_patch(struct klp_patch *); |
| 136 | 136 | ||
| 137 | /* Called from the module loader during module coming/going states */ | ||
| 138 | int klp_module_coming(struct module *mod); | ||
| 139 | void klp_module_going(struct module *mod); | ||
| 140 | |||
| 141 | #else /* !CONFIG_LIVEPATCH */ | ||
| 142 | |||
| 143 | static inline int klp_module_coming(struct module *mod) { return 0; } | ||
| 144 | static inline void klp_module_going(struct module *mod) { } | ||
| 145 | |||
| 137 | #endif /* CONFIG_LIVEPATCH */ | 146 | #endif /* CONFIG_LIVEPATCH */ |
| 138 | 147 | ||
| 139 | #endif /* _LINUX_LIVEPATCH_H_ */ | 148 | #endif /* _LINUX_LIVEPATCH_H_ */ |
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index bc2c85c064c1..d68fbf63b083 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c | |||
| @@ -99,12 +99,12 @@ static void klp_find_object_module(struct klp_object *obj) | |||
| 99 | /* | 99 | /* |
| 100 | * We do not want to block removal of patched modules and therefore | 100 | * We do not want to block removal of patched modules and therefore |
| 101 | * we do not take a reference here. The patches are removed by | 101 | * we do not take a reference here. The patches are removed by |
| 102 | * a going module handler instead. | 102 | * klp_module_going() instead. |
| 103 | */ | 103 | */ |
| 104 | mod = find_module(obj->name); | 104 | mod = find_module(obj->name); |
| 105 | /* | 105 | /* |
| 106 | * Do not mess work of the module coming and going notifiers. | 106 | * Do not mess work of klp_module_coming() and klp_module_going(). |
| 107 | * Note that the patch might still be needed before the going handler | 107 | * Note that the patch might still be needed before klp_module_going() |
| 108 | * is called. Module functions can be called even in the GOING state | 108 | * is called. Module functions can be called even in the GOING state |
| 109 | * until mod->exit() finishes. This is especially important for | 109 | * until mod->exit() finishes. This is especially important for |
| 110 | * patches that modify semantic of the functions. | 110 | * patches that modify semantic of the functions. |
| @@ -190,8 +190,8 @@ static int klp_find_object_symbol(const char *objname, const char *name, | |||
| 190 | if (args.addr == 0) | 190 | if (args.addr == 0) |
| 191 | pr_err("symbol '%s' not found in symbol table\n", name); | 191 | pr_err("symbol '%s' not found in symbol table\n", name); |
| 192 | else if (args.count > 1 && sympos == 0) { | 192 | else if (args.count > 1 && sympos == 0) { |
| 193 | pr_err("unresolvable ambiguity (%lu matches) on symbol '%s' in object '%s'\n", | 193 | pr_err("unresolvable ambiguity for symbol '%s' in object '%s'\n", |
| 194 | args.count, name, objname); | 194 | name, objname); |
| 195 | } else if (sympos != args.count && sympos > 0) { | 195 | } else if (sympos != args.count && sympos > 0) { |
| 196 | pr_err("symbol position %lu for symbol '%s' in object '%s' not found\n", | 196 | pr_err("symbol position %lu for symbol '%s' in object '%s' not found\n", |
| 197 | sympos, name, objname ? objname : "vmlinux"); | 197 | sympos, name, objname ? objname : "vmlinux"); |
| @@ -866,103 +866,108 @@ int klp_register_patch(struct klp_patch *patch) | |||
| 866 | } | 866 | } |
| 867 | EXPORT_SYMBOL_GPL(klp_register_patch); | 867 | EXPORT_SYMBOL_GPL(klp_register_patch); |
| 868 | 868 | ||
| 869 | static int klp_module_notify_coming(struct klp_patch *patch, | 869 | int klp_module_coming(struct module *mod) |
| 870 | struct klp_object *obj) | ||
| 871 | { | 870 | { |
| 872 | struct module *pmod = patch->mod; | ||
| 873 | struct module *mod = obj->mod; | ||
| 874 | int ret; | 871 | int ret; |
| 872 | struct klp_patch *patch; | ||
| 873 | struct klp_object *obj; | ||
| 875 | 874 | ||
| 876 | ret = klp_init_object_loaded(patch, obj); | 875 | if (WARN_ON(mod->state != MODULE_STATE_COMING)) |
| 877 | if (ret) { | 876 | return -EINVAL; |
| 878 | pr_warn("failed to initialize patch '%s' for module '%s' (%d)\n", | ||
| 879 | pmod->name, mod->name, ret); | ||
| 880 | return ret; | ||
| 881 | } | ||
| 882 | 877 | ||
| 883 | if (patch->state == KLP_DISABLED) | 878 | mutex_lock(&klp_mutex); |
| 884 | return 0; | 879 | /* |
| 880 | * Each module has to know that klp_module_coming() | ||
| 881 | * has been called. We never know what module will | ||
| 882 | * get patched by a new patch. | ||
| 883 | */ | ||
| 884 | mod->klp_alive = true; | ||
| 885 | 885 | ||
| 886 | pr_notice("applying patch '%s' to loading module '%s'\n", | 886 | list_for_each_entry(patch, &klp_patches, list) { |
| 887 | pmod->name, mod->name); | 887 | klp_for_each_object(patch, obj) { |
| 888 | if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) | ||
| 889 | continue; | ||
| 888 | 890 | ||
| 889 | ret = klp_enable_object(obj); | 891 | obj->mod = mod; |
| 890 | if (ret) | ||
| 891 | pr_warn("failed to apply patch '%s' to module '%s' (%d)\n", | ||
| 892 | pmod->name, mod->name, ret); | ||
| 893 | return ret; | ||
| 894 | } | ||
| 895 | 892 | ||
| 896 | static void klp_module_notify_going(struct klp_patch *patch, | 893 | ret = klp_init_object_loaded(patch, obj); |
| 897 | struct klp_object *obj) | 894 | if (ret) { |
| 898 | { | 895 | pr_warn("failed to initialize patch '%s' for module '%s' (%d)\n", |
| 899 | struct module *pmod = patch->mod; | 896 | patch->mod->name, obj->mod->name, ret); |
| 900 | struct module *mod = obj->mod; | 897 | goto err; |
| 898 | } | ||
| 901 | 899 | ||
| 902 | if (patch->state == KLP_DISABLED) | 900 | if (patch->state == KLP_DISABLED) |
| 903 | goto disabled; | 901 | break; |
| 902 | |||
| 903 | pr_notice("applying patch '%s' to loading module '%s'\n", | ||
| 904 | patch->mod->name, obj->mod->name); | ||
| 905 | |||
| 906 | ret = klp_enable_object(obj); | ||
| 907 | if (ret) { | ||
| 908 | pr_warn("failed to apply patch '%s' to module '%s' (%d)\n", | ||
| 909 | patch->mod->name, obj->mod->name, ret); | ||
| 910 | goto err; | ||
| 911 | } | ||
| 912 | |||
| 913 | break; | ||
| 914 | } | ||
| 915 | } | ||
| 904 | 916 | ||
| 905 | pr_notice("reverting patch '%s' on unloading module '%s'\n", | 917 | mutex_unlock(&klp_mutex); |
| 906 | pmod->name, mod->name); | ||
| 907 | 918 | ||
| 908 | klp_disable_object(obj); | 919 | return 0; |
| 909 | 920 | ||
| 910 | disabled: | 921 | err: |
| 922 | /* | ||
| 923 | * If a patch is unsuccessfully applied, return | ||
| 924 | * error to the module loader. | ||
| 925 | */ | ||
| 926 | pr_warn("patch '%s' failed for module '%s', refusing to load module '%s'\n", | ||
| 927 | patch->mod->name, obj->mod->name, obj->mod->name); | ||
| 928 | mod->klp_alive = false; | ||
| 911 | klp_free_object_loaded(obj); | 929 | klp_free_object_loaded(obj); |
| 930 | mutex_unlock(&klp_mutex); | ||
| 931 | |||
| 932 | return ret; | ||
| 912 | } | 933 | } |
| 913 | 934 | ||
| 914 | static int klp_module_notify(struct notifier_block *nb, unsigned long action, | 935 | void klp_module_going(struct module *mod) |
| 915 | void *data) | ||
| 916 | { | 936 | { |
| 917 | int ret; | ||
| 918 | struct module *mod = data; | ||
| 919 | struct klp_patch *patch; | 937 | struct klp_patch *patch; |
| 920 | struct klp_object *obj; | 938 | struct klp_object *obj; |
| 921 | 939 | ||
| 922 | if (action != MODULE_STATE_COMING && action != MODULE_STATE_GOING) | 940 | if (WARN_ON(mod->state != MODULE_STATE_GOING && |
| 923 | return 0; | 941 | mod->state != MODULE_STATE_COMING)) |
| 942 | return; | ||
| 924 | 943 | ||
| 925 | mutex_lock(&klp_mutex); | 944 | mutex_lock(&klp_mutex); |
| 926 | |||
| 927 | /* | 945 | /* |
| 928 | * Each module has to know that the notifier has been called. | 946 | * Each module has to know that klp_module_going() |
| 929 | * We never know what module will get patched by a new patch. | 947 | * has been called. We never know what module will |
| 948 | * get patched by a new patch. | ||
| 930 | */ | 949 | */ |
| 931 | if (action == MODULE_STATE_COMING) | 950 | mod->klp_alive = false; |
| 932 | mod->klp_alive = true; | ||
| 933 | else /* MODULE_STATE_GOING */ | ||
| 934 | mod->klp_alive = false; | ||
| 935 | 951 | ||
| 936 | list_for_each_entry(patch, &klp_patches, list) { | 952 | list_for_each_entry(patch, &klp_patches, list) { |
| 937 | klp_for_each_object(patch, obj) { | 953 | klp_for_each_object(patch, obj) { |
| 938 | if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) | 954 | if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) |
| 939 | continue; | 955 | continue; |
| 940 | 956 | ||
| 941 | if (action == MODULE_STATE_COMING) { | 957 | if (patch->state != KLP_DISABLED) { |
| 942 | obj->mod = mod; | 958 | pr_notice("reverting patch '%s' on unloading module '%s'\n", |
| 943 | ret = klp_module_notify_coming(patch, obj); | 959 | patch->mod->name, obj->mod->name); |
| 944 | if (ret) { | 960 | klp_disable_object(obj); |
| 945 | obj->mod = NULL; | 961 | } |
| 946 | pr_warn("patch '%s' is in an inconsistent state!\n", | ||
| 947 | patch->mod->name); | ||
| 948 | } | ||
| 949 | } else /* MODULE_STATE_GOING */ | ||
| 950 | klp_module_notify_going(patch, obj); | ||
| 951 | 962 | ||
| 963 | klp_free_object_loaded(obj); | ||
| 952 | break; | 964 | break; |
| 953 | } | 965 | } |
| 954 | } | 966 | } |
| 955 | 967 | ||
| 956 | mutex_unlock(&klp_mutex); | 968 | mutex_unlock(&klp_mutex); |
| 957 | |||
| 958 | return 0; | ||
| 959 | } | 969 | } |
| 960 | 970 | ||
| 961 | static struct notifier_block klp_module_nb = { | ||
| 962 | .notifier_call = klp_module_notify, | ||
| 963 | .priority = INT_MIN+1, /* called late but before ftrace notifier */ | ||
| 964 | }; | ||
| 965 | |||
| 966 | static int __init klp_init(void) | 971 | static int __init klp_init(void) |
| 967 | { | 972 | { |
| 968 | int ret; | 973 | int ret; |
| @@ -973,21 +978,11 @@ static int __init klp_init(void) | |||
| 973 | return -EINVAL; | 978 | return -EINVAL; |
| 974 | } | 979 | } |
| 975 | 980 | ||
| 976 | ret = register_module_notifier(&klp_module_nb); | ||
| 977 | if (ret) | ||
| 978 | return ret; | ||
| 979 | |||
| 980 | klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj); | 981 | klp_root_kobj = kobject_create_and_add("livepatch", kernel_kobj); |
| 981 | if (!klp_root_kobj) { | 982 | if (!klp_root_kobj) |
| 982 | ret = -ENOMEM; | 983 | return -ENOMEM; |
| 983 | goto unregister; | ||
| 984 | } | ||
| 985 | 984 | ||
| 986 | return 0; | 985 | return 0; |
| 987 | |||
| 988 | unregister: | ||
| 989 | unregister_module_notifier(&klp_module_nb); | ||
| 990 | return ret; | ||
| 991 | } | 986 | } |
| 992 | 987 | ||
| 993 | module_init(klp_init); | 988 | module_init(klp_init); |
diff --git a/kernel/module.c b/kernel/module.c index 87cfeb25cf65..041200ca4a2d 100644 --- a/kernel/module.c +++ b/kernel/module.c | |||
| @@ -53,6 +53,7 @@ | |||
| 53 | #include <asm/sections.h> | 53 | #include <asm/sections.h> |
| 54 | #include <linux/tracepoint.h> | 54 | #include <linux/tracepoint.h> |
| 55 | #include <linux/ftrace.h> | 55 | #include <linux/ftrace.h> |
| 56 | #include <linux/livepatch.h> | ||
| 56 | #include <linux/async.h> | 57 | #include <linux/async.h> |
| 57 | #include <linux/percpu.h> | 58 | #include <linux/percpu.h> |
| 58 | #include <linux/kmemleak.h> | 59 | #include <linux/kmemleak.h> |
| @@ -984,6 +985,7 @@ SYSCALL_DEFINE2(delete_module, const char __user *, name_user, | |||
| 984 | mod->exit(); | 985 | mod->exit(); |
| 985 | blocking_notifier_call_chain(&module_notify_list, | 986 | blocking_notifier_call_chain(&module_notify_list, |
| 986 | MODULE_STATE_GOING, mod); | 987 | MODULE_STATE_GOING, mod); |
| 988 | klp_module_going(mod); | ||
| 987 | ftrace_release_mod(mod); | 989 | ftrace_release_mod(mod); |
| 988 | 990 | ||
| 989 | async_synchronize_full(); | 991 | async_synchronize_full(); |
| @@ -3258,6 +3260,7 @@ fail: | |||
| 3258 | module_put(mod); | 3260 | module_put(mod); |
| 3259 | blocking_notifier_call_chain(&module_notify_list, | 3261 | blocking_notifier_call_chain(&module_notify_list, |
| 3260 | MODULE_STATE_GOING, mod); | 3262 | MODULE_STATE_GOING, mod); |
| 3263 | klp_module_going(mod); | ||
| 3261 | ftrace_release_mod(mod); | 3264 | ftrace_release_mod(mod); |
| 3262 | free_module(mod); | 3265 | free_module(mod); |
| 3263 | wake_up_all(&module_wq); | 3266 | wake_up_all(&module_wq); |
| @@ -3335,9 +3338,6 @@ static int complete_formation(struct module *mod, struct load_info *info) | |||
| 3335 | mod->state = MODULE_STATE_COMING; | 3338 | mod->state = MODULE_STATE_COMING; |
| 3336 | mutex_unlock(&module_mutex); | 3339 | mutex_unlock(&module_mutex); |
| 3337 | 3340 | ||
| 3338 | ftrace_module_enable(mod); | ||
| 3339 | blocking_notifier_call_chain(&module_notify_list, | ||
| 3340 | MODULE_STATE_COMING, mod); | ||
| 3341 | return 0; | 3341 | return 0; |
| 3342 | 3342 | ||
| 3343 | out: | 3343 | out: |
| @@ -3345,6 +3345,20 @@ out: | |||
| 3345 | return err; | 3345 | return err; |
| 3346 | } | 3346 | } |
| 3347 | 3347 | ||
| 3348 | static int prepare_coming_module(struct module *mod) | ||
| 3349 | { | ||
| 3350 | int err; | ||
| 3351 | |||
| 3352 | ftrace_module_enable(mod); | ||
| 3353 | err = klp_module_coming(mod); | ||
| 3354 | if (err) | ||
| 3355 | return err; | ||
| 3356 | |||
| 3357 | blocking_notifier_call_chain(&module_notify_list, | ||
| 3358 | MODULE_STATE_COMING, mod); | ||
| 3359 | return 0; | ||
| 3360 | } | ||
| 3361 | |||
| 3348 | static int unknown_module_param_cb(char *param, char *val, const char *modname, | 3362 | static int unknown_module_param_cb(char *param, char *val, const char *modname, |
| 3349 | void *arg) | 3363 | void *arg) |
| 3350 | { | 3364 | { |
| @@ -3459,13 +3473,17 @@ static int load_module(struct load_info *info, const char __user *uargs, | |||
| 3459 | if (err) | 3473 | if (err) |
| 3460 | goto ddebug_cleanup; | 3474 | goto ddebug_cleanup; |
| 3461 | 3475 | ||
| 3476 | err = prepare_coming_module(mod); | ||
| 3477 | if (err) | ||
| 3478 | goto bug_cleanup; | ||
| 3479 | |||
| 3462 | /* Module is ready to execute: parsing args may do that. */ | 3480 | /* Module is ready to execute: parsing args may do that. */ |
| 3463 | after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, | 3481 | after_dashes = parse_args(mod->name, mod->args, mod->kp, mod->num_kp, |
| 3464 | -32768, 32767, mod, | 3482 | -32768, 32767, mod, |
| 3465 | unknown_module_param_cb); | 3483 | unknown_module_param_cb); |
| 3466 | if (IS_ERR(after_dashes)) { | 3484 | if (IS_ERR(after_dashes)) { |
| 3467 | err = PTR_ERR(after_dashes); | 3485 | err = PTR_ERR(after_dashes); |
| 3468 | goto bug_cleanup; | 3486 | goto coming_cleanup; |
| 3469 | } else if (after_dashes) { | 3487 | } else if (after_dashes) { |
| 3470 | pr_warn("%s: parameters '%s' after `--' ignored\n", | 3488 | pr_warn("%s: parameters '%s' after `--' ignored\n", |
| 3471 | mod->name, after_dashes); | 3489 | mod->name, after_dashes); |
| @@ -3474,7 +3492,7 @@ static int load_module(struct load_info *info, const char __user *uargs, | |||
| 3474 | /* Link in to syfs. */ | 3492 | /* Link in to syfs. */ |
| 3475 | err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp); | 3493 | err = mod_sysfs_setup(mod, info, mod->kp, mod->num_kp); |
| 3476 | if (err < 0) | 3494 | if (err < 0) |
| 3477 | goto bug_cleanup; | 3495 | goto coming_cleanup; |
| 3478 | 3496 | ||
| 3479 | /* Get rid of temporary copy. */ | 3497 | /* Get rid of temporary copy. */ |
| 3480 | free_copy(info); | 3498 | free_copy(info); |
| @@ -3484,15 +3502,17 @@ static int load_module(struct load_info *info, const char __user *uargs, | |||
| 3484 | 3502 | ||
| 3485 | return do_init_module(mod); | 3503 | return do_init_module(mod); |
| 3486 | 3504 | ||
| 3505 | coming_cleanup: | ||
| 3506 | blocking_notifier_call_chain(&module_notify_list, | ||
| 3507 | MODULE_STATE_GOING, mod); | ||
| 3508 | klp_module_going(mod); | ||
| 3509 | |||
| 3487 | bug_cleanup: | 3510 | bug_cleanup: |
| 3488 | /* module_bug_cleanup needs module_mutex protection */ | 3511 | /* module_bug_cleanup needs module_mutex protection */ |
| 3489 | mutex_lock(&module_mutex); | 3512 | mutex_lock(&module_mutex); |
| 3490 | module_bug_cleanup(mod); | 3513 | module_bug_cleanup(mod); |
| 3491 | mutex_unlock(&module_mutex); | 3514 | mutex_unlock(&module_mutex); |
| 3492 | 3515 | ||
| 3493 | blocking_notifier_call_chain(&module_notify_list, | ||
| 3494 | MODULE_STATE_GOING, mod); | ||
| 3495 | |||
| 3496 | /* we can't deallocate the module until we clear memory protection */ | 3516 | /* we can't deallocate the module until we clear memory protection */ |
| 3497 | module_disable_ro(mod); | 3517 | module_disable_ro(mod); |
| 3498 | module_disable_nx(mod); | 3518 | module_disable_nx(mod); |
