Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932650AbcCJWpP (ORCPT ); Thu, 10 Mar 2016 17:45:15 -0500 Received: from mx1.redhat.com ([209.132.183.28]:22531 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752521AbcCJWpM (ORCPT ); Thu, 10 Mar 2016 17:45:12 -0500 Date: Thu, 10 Mar 2016 16:45:08 -0600 From: Josh Poimboeuf To: Jessica Yu Cc: Seth Jennings , Jiri Kosina , Vojtech Pavlik , Miroslav Benes , Petr Mladek , Rusty Russell , Steven Rostedt , live-patching@vger.kernel.org, linux-kernel@vger.kernel.org Subject: Re: [PATCH 3/3] livepatch/module: remove livepatch module notifier Message-ID: <20160310224508.GC12493@treble.redhat.com> References: <1457561637-24770-1-git-send-email-jeyu@redhat.com> <1457561637-24770-4-git-send-email-jeyu@redhat.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Disposition: inline In-Reply-To: <1457561637-24770-4-git-send-email-jeyu@redhat.com> User-Agent: Mutt/1.5.23.1-rc1 (2014-03-12) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 6171 Lines: 188 On Wed, Mar 09, 2016 at 05:13:57PM -0500, Jessica Yu wrote: > Remove the livepatch module notifier in favor of directly enabling and > disabling patches to modules in the module loader. Hard-coding the > function calls ensures that ftrace_module_enable() is run before > klp_module_coming() during module load, and that klp_module_going() is > run before ftrace_release_mod() during module unload. This way, ftrace > and livepatch code is run in the correct order during the module > load/unload sequence without dependence on the module notifier call chain. > > Signed-off-by: Jessica Yu > --- > include/linux/livepatch.h | 13 +++++ > kernel/livepatch/core.c | 145 ++++++++++++++++++++++------------------------ > kernel/module.c | 10 ++++ > 3 files changed, 92 insertions(+), 76 deletions(-) > > diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h > index c056797..bd830d5 100644 > --- a/include/linux/livepatch.h > +++ b/include/linux/livepatch.h > @@ -24,6 +24,8 @@ > #include > #include > > +#if IS_ENABLED(CONFIG_LIVEPATCH) > + > #include > > enum klp_state { > @@ -132,4 +134,15 @@ int klp_unregister_patch(struct klp_patch *); > int klp_enable_patch(struct klp_patch *); > int klp_disable_patch(struct klp_patch *); > > +/* Called from the module loader during module coming/going states */ > +int klp_module_coming(struct module *mod); > +void klp_module_going(struct module *mod); > + > +#else /* !CONFIG_LIVEPATCH */ > + > +static inline int klp_module_coming(struct module *mod) { return 0; } > +static inline void klp_module_going(struct module *mod) { } > + > +#endif /* CONFIG_LIVEPATCH */ > + > #endif /* _LINUX_LIVEPATCH_H_ */ > diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c > index bc2c85c..e902377 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) > /* > * We do not want to block removal of patched modules and therefore > * we do not take a reference here. The patches are removed by > - * a going module handler instead. > + * klp_module_going() instead. > */ > mod = find_module(obj->name); > /* > - * Do not mess work of the module coming and going notifiers. > - * Note that the patch might still be needed before the going handler > + * Do not mess work of klp_module_coming() and klp_module_going(). > + * Note that the patch might still be needed before klp_module_going() > * is called. Module functions can be called even in the GOING state > * until mod->exit() finishes. This is especially important for > * patches that modify semantic of the functions. > @@ -866,103 +866,106 @@ int klp_register_patch(struct klp_patch *patch) > } > EXPORT_SYMBOL_GPL(klp_register_patch); > > -static int klp_module_notify_coming(struct klp_patch *patch, > - struct klp_object *obj) > +int klp_module_coming(struct module *mod) > { > - struct module *pmod = patch->mod; > - struct module *mod = obj->mod; > int ret; > + struct klp_patch *patch; > + struct klp_object *obj; > > - ret = klp_init_object_loaded(patch, obj); > - if (ret) { > - pr_warn("failed to initialize patch '%s' for module '%s' (%d)\n", > - pmod->name, mod->name, ret); > - return ret; > - } > + if (WARN_ON(mod->state != MODULE_STATE_COMING)) > + return -EINVAL; > > - if (patch->state == KLP_DISABLED) > - return 0; > + mutex_lock(&klp_mutex); > + /* > + * Each module has to know that klp_module_coming() > + * has been called. We never know what module will > + * get patched by a new patch. > + */ > + mod->klp_alive = true; > > - pr_notice("applying patch '%s' to loading module '%s'\n", > - pmod->name, mod->name); > + list_for_each_entry(patch, &klp_patches, list) { > + klp_for_each_object(patch, obj) { > + if (!klp_is_module(obj) || strcmp(obj->name, mod->name)) > + continue; > > - ret = klp_enable_object(obj); > - if (ret) > - pr_warn("failed to apply patch '%s' to module '%s' (%d)\n", > - pmod->name, mod->name, ret); > - return ret; > -} > + obj->mod = mod; > > -static void klp_module_notify_going(struct klp_patch *patch, > - struct klp_object *obj) > -{ > - struct module *pmod = patch->mod; > - struct module *mod = obj->mod; > + ret = klp_init_object_loaded(patch, obj); > + if (ret) { > + pr_warn("failed to initialize patch '%s' for module '%s' (%d)\n", > + patch->mod->name, obj->mod->name, ret); > + goto err; > + } > > - if (patch->state == KLP_DISABLED) > - goto disabled; > + if (patch->state == KLP_DISABLED) > + break; > + > + pr_notice("applying patch '%s' to loading module '%s'\n", > + patch->mod->name, obj->mod->name); > + > + ret = klp_enable_object(obj); > + if (ret) { > + pr_warn("failed to apply patch '%s' to module '%s' (%d)\n", > + patch->mod->name, obj->mod->name, ret); > + goto err; > + } > + > + break; > + } > + } > > - pr_notice("reverting patch '%s' on unloading module '%s'\n", > - pmod->name, mod->name); > + mutex_unlock(&klp_mutex); > > - klp_disable_object(obj); > + return 0; > > -disabled: > +err: > + /* > + * If a patch is unsuccessfully applied, return > + * error to the module loader. > + */ > + pr_warn("patch '%s' failed for module '%s', refusing to load module '%s'\n", > + patch->mod->name, obj->mod->name, obj->mod->name); > klp_free_object_loaded(obj); > + mutex_unlock(&klp_mutex); > + > + return ret; > } > > -static int klp_module_notify(struct notifier_block *nb, unsigned long action, > - void *data) > +void klp_module_going(struct module *mod) > { > - int ret; > - struct module *mod = data; > struct klp_patch *patch; > struct klp_object *obj; > > - if (action != MODULE_STATE_COMING && action != MODULE_STATE_GOING) > - return 0; > + if (WARN_ON(mod->state != MODULE_STATE_GOING)) > + return; If we're removing patch 2/3, then mod->state isn't necessarily GOING. I think the check can probably just be removed altogether. With that fixed, Acked-by: Josh Poimboeuf -- Josh