aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/livepatch/patch.c
diff options
context:
space:
mode:
authorPetr Mladek <pmladek@suse.com>2019-01-09 07:43:26 -0500
committerJiri Kosina <jkosina@suse.cz>2019-01-11 14:51:24 -0500
commitd697bad588eb4e76311193e6eaacc7c7aaa5a4ba (patch)
tree53f96c1a0ddbec0307bc3c7f2c1bfda8c5368fc7 /kernel/livepatch/patch.c
parente1452b607c48c642caf57299f4da83aa002f8533 (diff)
livepatch: Remove Nop structures when unused
Replaced patches are removed from the stack when the transition is finished. It means that Nop structures will never be needed again and can be removed. Why should we care? + Nop structures give the impression that the function is patched even though the ftrace handler has no effect. + Ftrace handlers do not come for free. They cause slowdown that might be visible in some workloads. The ftrace-related slowdown might actually be the reason why the function is no longer patched in the new cumulative patch. One would expect that cumulative patch would help solve these problems as well. + Cumulative patches are supposed to replace any earlier version of the patch. The amount of NOPs depends on which version was replaced. This multiplies the amount of scenarios that might happen. One might say that NOPs are innocent. But there are even optimized NOP instructions for different processors, for example, see arch/x86/kernel/alternative.c. And klp_ftrace_handler() is much more complicated. + It sounds natural to clean up a mess that is no longer needed. It could only be worse if we do not do it. This patch allows to unpatch and free the dynamic structures independently when the transition finishes. The free part is a bit tricky because kobject free callbacks are called asynchronously. We could not wait for them easily. Fortunately, we do not have to. Any further access can be avoided by removing them from the dynamic lists. Signed-off-by: Petr Mladek <pmladek@suse.com> Acked-by: Miroslav Benes <mbenes@suse.cz> Acked-by: Josh Poimboeuf <jpoimboe@redhat.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'kernel/livepatch/patch.c')
-rw-r--r--kernel/livepatch/patch.c31
1 files changed, 26 insertions, 5 deletions
diff --git a/kernel/livepatch/patch.c b/kernel/livepatch/patch.c
index 0ff466ab4b5a..99cb3ad05eb4 100644
--- a/kernel/livepatch/patch.c
+++ b/kernel/livepatch/patch.c
@@ -246,15 +246,26 @@ err:
246 return ret; 246 return ret;
247} 247}
248 248
249void klp_unpatch_object(struct klp_object *obj) 249static void __klp_unpatch_object(struct klp_object *obj, bool nops_only)
250{ 250{
251 struct klp_func *func; 251 struct klp_func *func;
252 252
253 klp_for_each_func(obj, func) 253 klp_for_each_func(obj, func) {
254 if (nops_only && !func->nop)
255 continue;
256
254 if (func->patched) 257 if (func->patched)
255 klp_unpatch_func(func); 258 klp_unpatch_func(func);
259 }
256 260
257 obj->patched = false; 261 if (obj->dynamic || !nops_only)
262 obj->patched = false;
263}
264
265
266void klp_unpatch_object(struct klp_object *obj)
267{
268 __klp_unpatch_object(obj, false);
258} 269}
259 270
260int klp_patch_object(struct klp_object *obj) 271int klp_patch_object(struct klp_object *obj)
@@ -277,11 +288,21 @@ int klp_patch_object(struct klp_object *obj)
277 return 0; 288 return 0;
278} 289}
279 290
280void klp_unpatch_objects(struct klp_patch *patch) 291static void __klp_unpatch_objects(struct klp_patch *patch, bool nops_only)
281{ 292{
282 struct klp_object *obj; 293 struct klp_object *obj;
283 294
284 klp_for_each_object(patch, obj) 295 klp_for_each_object(patch, obj)
285 if (obj->patched) 296 if (obj->patched)
286 klp_unpatch_object(obj); 297 __klp_unpatch_object(obj, nops_only);
298}
299
300void klp_unpatch_objects(struct klp_patch *patch)
301{
302 __klp_unpatch_objects(patch, false);
303}
304
305void klp_unpatch_objects_dynamic(struct klp_patch *patch)
306{
307 __klp_unpatch_objects(patch, true);
287} 308}