diff options
author | Jiri Kosina <jkosina@suse.cz> | 2016-04-15 05:31:51 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2016-04-15 05:42:51 -0400 |
commit | 4d4fb97a62105c07dcccd350c391a65f576726c4 (patch) | |
tree | 36f5ba480d7ea790b8cedf7e49bebab781659f73 /kernel/livepatch/core.c | |
parent | 61bf12d3304d78ff499245ea995858c3bedb162e (diff) | |
parent | 85baa095497f3e590df9f6c8932121f123efca5c (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.c | 34 |
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 | ||
344 | static unsigned long klp_get_ftrace_location(unsigned long faddr) | ||
345 | { | ||
346 | return faddr; | ||
347 | } | ||
348 | #endif | ||
349 | |||
337 | static void klp_disable_func(struct klp_func *func) | 350 | static 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 | ||