From 87d852afa26f7b5a7e21ac3a92d89f19c984cacd Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Mon, 28 Apr 2014 10:29:33 -0500 Subject: [PATCH] kmod/core: fail more gracefully in kpatch_unregister In kpatch_unregister(), if kpatch_remove_patch succeeds but one of the subsequent ftrace unregistering calls fails, it returns an error and fails to module_put() the patch module, even though the patch has been removed. This causes the patch module to get stuck in a weird place where its patch has been unregistered but the patch module can't ever be removed. These errors aren't serious and wouldn't cause any real problems if they did somehow fail, so instead just WARN if they fail. --- kmod/core/core.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/kmod/core/core.c b/kmod/core/core.c index aef71c6..490778e 100644 --- a/kmod/core/core.c +++ b/kmod/core/core.c @@ -321,8 +321,8 @@ static struct ftrace_ops kpatch_ftrace_ops __read_mostly = { }; /* Remove kpatch_funcs from ftrace filter */ -static int kpatch_remove_funcs_from_filter(struct kpatch_func *funcs, - int num_funcs) +static void kpatch_remove_funcs_from_filter(struct kpatch_func *funcs, + int num_funcs) { int i, ret = 0; @@ -339,14 +339,8 @@ static int kpatch_remove_funcs_from_filter(struct kpatch_func *funcs, /* Remove the ftrace handler for this function. */ ret = ftrace_set_filter_ip(&kpatch_ftrace_ops, func->old_addr, 1, 0); - if (ret) { - pr_err("can't remove ftrace filter at address 0x%lx\n", - func->old_addr); - break; - } + WARN_ON(ret); } - - return ret; } int kpatch_register(struct kpatch_module *kpmod) @@ -480,12 +474,11 @@ int kpatch_unregister(struct kpatch_module *kpmod) if (kpatch_num_registered == 1) { ret = unregister_ftrace_function(&kpatch_ftrace_ops); - if (ret) { - pr_err("can't unregister ftrace handler\n"); - goto out; - } + if (ret) + WARN_ON(1); + else + kpatch_num_registered--; } - kpatch_num_registered--; /* * This synchronize_rcu is to ensure any other kpatch_get_func @@ -494,9 +487,7 @@ int kpatch_unregister(struct kpatch_module *kpmod) */ synchronize_rcu(); - ret = kpatch_remove_funcs_from_filter(funcs, num_funcs); - if (ret) - goto out; + kpatch_remove_funcs_from_filter(funcs, num_funcs); pr_notice("unloaded patch module \"%s\"\n", kpmod->mod->name);