aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/livepatch/core.c
diff options
context:
space:
mode:
authorJiri Kosina <jkosina@suse.cz>2016-04-15 05:31:51 -0400
committerJiri Kosina <jkosina@suse.cz>2016-04-15 05:42:51 -0400
commit4d4fb97a62105c07dcccd350c391a65f576726c4 (patch)
tree36f5ba480d7ea790b8cedf7e49bebab781659f73 /kernel/livepatch/core.c
parent61bf12d3304d78ff499245ea995858c3bedb162e (diff)
parent85baa095497f3e590df9f6c8932121f123efca5c (diff)
Merge branch 'topic/livepatch' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux into for-4.7/livepatching-ppc64le
Pull livepatching support for ppc64 architecture from Michael Ellerman. Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'kernel/livepatch/core.c')
-rw-r--r--kernel/livepatch/core.c34
1 files changed, 31 insertions, 3 deletions
diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c
index 28c37fa3d3f9..a19f1954f4ac 100644
--- a/kernel/livepatch/core.c
+++ b/kernel/livepatch/core.c
@@ -334,6 +334,19 @@ unlock:
334 rcu_read_unlock(); 334 rcu_read_unlock();
335} 335}
336 336
337/*
338 * Convert a function address into the appropriate ftrace location.
339 *
340 * Usually this is just the address of the function, but on some architectures
341 * it's more complicated so allow them to provide a custom behaviour.
342 */
343#ifndef klp_get_ftrace_location
344static unsigned long klp_get_ftrace_location(unsigned long faddr)
345{
346 return faddr;
347}
348#endif
349
337static void klp_disable_func(struct klp_func *func) 350static void klp_disable_func(struct klp_func *func)
338{ 351{
339 struct klp_ops *ops; 352 struct klp_ops *ops;
@@ -348,8 +361,14 @@ static void klp_disable_func(struct klp_func *func)
348 return; 361 return;
349 362
350 if (list_is_singular(&ops->func_stack)) { 363 if (list_is_singular(&ops->func_stack)) {
364 unsigned long ftrace_loc;
365
366 ftrace_loc = klp_get_ftrace_location(func->old_addr);
367 if (WARN_ON(!ftrace_loc))
368 return;
369
351 WARN_ON(unregister_ftrace_function(&ops->fops)); 370 WARN_ON(unregister_ftrace_function(&ops->fops));
352 WARN_ON(ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0)); 371 WARN_ON(ftrace_set_filter_ip(&ops->fops, ftrace_loc, 1, 0));
353 372
354 list_del_rcu(&func->stack_node); 373 list_del_rcu(&func->stack_node);
355 list_del(&ops->node); 374 list_del(&ops->node);
@@ -374,6 +393,15 @@ static int klp_enable_func(struct klp_func *func)
374 393
375 ops = klp_find_ops(func->old_addr); 394 ops = klp_find_ops(func->old_addr);
376 if (!ops) { 395 if (!ops) {
396 unsigned long ftrace_loc;
397
398 ftrace_loc = klp_get_ftrace_location(func->old_addr);
399 if (!ftrace_loc) {
400 pr_err("failed to find location for function '%s'\n",
401 func->old_name);
402 return -EINVAL;
403 }
404
377 ops = kzalloc(sizeof(*ops), GFP_KERNEL); 405 ops = kzalloc(sizeof(*ops), GFP_KERNEL);
378 if (!ops) 406 if (!ops)
379 return -ENOMEM; 407 return -ENOMEM;
@@ -388,7 +416,7 @@ static int klp_enable_func(struct klp_func *func)
388 INIT_LIST_HEAD(&ops->func_stack); 416 INIT_LIST_HEAD(&ops->func_stack);
389 list_add_rcu(&func->stack_node, &ops->func_stack); 417 list_add_rcu(&func->stack_node, &ops->func_stack);
390 418
391 ret = ftrace_set_filter_ip(&ops->fops, func->old_addr, 0, 0); 419 ret = ftrace_set_filter_ip(&ops->fops, ftrace_loc, 0, 0);
392 if (ret) { 420 if (ret) {
393 pr_err("failed to set ftrace filter for function '%s' (%d)\n", 421 pr_err("failed to set ftrace filter for function '%s' (%d)\n",
394 func->old_name, ret); 422 func->old_name, ret);
@@ -399,7 +427,7 @@ static int klp_enable_func(struct klp_func *func)
399 if (ret) { 427 if (ret) {
400 pr_err("failed to register ftrace handler for function '%s' (%d)\n", 428 pr_err("failed to register ftrace handler for function '%s' (%d)\n",
401 func->old_name, ret); 429 func->old_name, ret);
402 ftrace_set_filter_ip(&ops->fops, func->old_addr, 1, 0); 430 ftrace_set_filter_ip(&ops->fops, ftrace_loc, 1, 0);
403 goto err; 431 goto err;
404 } 432 }
405 433