diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2010-12-03 04:54:28 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-12-06 11:59:31 -0500 |
commit | cd7ebe2298ff1c3112232878678ce5fe6be8a15b (patch) | |
tree | 7bac7adf40ce2141e779b7d99b2784279c2dc45c | |
parent | 7deb18dcf0478940ac979de002db1ed8ba6531dc (diff) |
kprobes: Use text_poke_smp_batch for optimizing
Use text_poke_smp_batch() in optimization path for reducing
the number of stop_machine() issues. If the number of optimizing
probes is more than MAX_OPTIMIZE_PROBES(=256), kprobes optimizes
first MAX_OPTIMIZE_PROBES probes and kicks optimizer for
remaining probes.
Changes in v5:
- Use kick_kprobe_optimizer() instead of directly calling
schedule_delayed_work().
- Rescheduling optimizer outside of kprobe mutex lock.
Changes in v2:
- Allocate code buffer and parameters in arch_init_kprobes()
instead of using static arraies.
- Merge previous max optimization limit patch into this patch.
So, this patch introduces upper limit of optimization at
once.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Jason Baron <jbaron@redhat.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: 2nddept-manager@sdl.hitachi.co.jp
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Steven Rostedt <rostedt@goodmis.org>
LKML-Reference: <20101203095428.2961.8994.stgit@ltc236.sdl.hitachi.co.jp>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/kernel/kprobes.c | 69 | ||||
-rw-r--r-- | include/linux/kprobes.h | 2 | ||||
-rw-r--r-- | kernel/kprobes.c | 17 |
3 files changed, 69 insertions, 19 deletions
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c index da51dc8e77cb..25a8af76feb5 100644 --- a/arch/x86/kernel/kprobes.c +++ b/arch/x86/kernel/kprobes.c | |||
@@ -1405,10 +1405,16 @@ int __kprobes arch_prepare_optimized_kprobe(struct optimized_kprobe *op) | |||
1405 | return 0; | 1405 | return 0; |
1406 | } | 1406 | } |
1407 | 1407 | ||
1408 | /* Replace a breakpoint (int3) with a relative jump. */ | 1408 | #define MAX_OPTIMIZE_PROBES 256 |
1409 | int __kprobes arch_optimize_kprobe(struct optimized_kprobe *op) | 1409 | static struct text_poke_param *jump_poke_params; |
1410 | static struct jump_poke_buffer { | ||
1411 | u8 buf[RELATIVEJUMP_SIZE]; | ||
1412 | } *jump_poke_bufs; | ||
1413 | |||
1414 | static void __kprobes setup_optimize_kprobe(struct text_poke_param *tprm, | ||
1415 | u8 *insn_buf, | ||
1416 | struct optimized_kprobe *op) | ||
1410 | { | 1417 | { |
1411 | unsigned char jmp_code[RELATIVEJUMP_SIZE]; | ||
1412 | s32 rel = (s32)((long)op->optinsn.insn - | 1418 | s32 rel = (s32)((long)op->optinsn.insn - |
1413 | ((long)op->kp.addr + RELATIVEJUMP_SIZE)); | 1419 | ((long)op->kp.addr + RELATIVEJUMP_SIZE)); |
1414 | 1420 | ||
@@ -1416,16 +1422,39 @@ int __kprobes arch_optimize_kprobe(struct optimized_kprobe *op) | |||
1416 | memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_SIZE, | 1422 | memcpy(op->optinsn.copied_insn, op->kp.addr + INT3_SIZE, |
1417 | RELATIVE_ADDR_SIZE); | 1423 | RELATIVE_ADDR_SIZE); |
1418 | 1424 | ||
1419 | jmp_code[0] = RELATIVEJUMP_OPCODE; | 1425 | insn_buf[0] = RELATIVEJUMP_OPCODE; |
1420 | *(s32 *)(&jmp_code[1]) = rel; | 1426 | *(s32 *)(&insn_buf[1]) = rel; |
1427 | |||
1428 | tprm->addr = op->kp.addr; | ||
1429 | tprm->opcode = insn_buf; | ||
1430 | tprm->len = RELATIVEJUMP_SIZE; | ||
1431 | } | ||
1432 | |||
1433 | /* | ||
1434 | * Replace breakpoints (int3) with relative jumps. | ||
1435 | * Caller must call with locking kprobe_mutex and text_mutex. | ||
1436 | */ | ||
1437 | void __kprobes arch_optimize_kprobes(struct list_head *oplist) | ||
1438 | { | ||
1439 | struct optimized_kprobe *op, *tmp; | ||
1440 | int c = 0; | ||
1441 | |||
1442 | list_for_each_entry_safe(op, tmp, oplist, list) { | ||
1443 | WARN_ON(kprobe_disabled(&op->kp)); | ||
1444 | /* Setup param */ | ||
1445 | setup_optimize_kprobe(&jump_poke_params[c], | ||
1446 | jump_poke_bufs[c].buf, op); | ||
1447 | list_del_init(&op->list); | ||
1448 | if (++c >= MAX_OPTIMIZE_PROBES) | ||
1449 | break; | ||
1450 | } | ||
1421 | 1451 | ||
1422 | /* | 1452 | /* |
1423 | * text_poke_smp doesn't support NMI/MCE code modifying. | 1453 | * text_poke_smp doesn't support NMI/MCE code modifying. |
1424 | * However, since kprobes itself also doesn't support NMI/MCE | 1454 | * However, since kprobes itself also doesn't support NMI/MCE |
1425 | * code probing, it's not a problem. | 1455 | * code probing, it's not a problem. |
1426 | */ | 1456 | */ |
1427 | text_poke_smp(op->kp.addr, jmp_code, RELATIVEJUMP_SIZE); | 1457 | text_poke_smp_batch(jump_poke_params, c); |
1428 | return 0; | ||
1429 | } | 1458 | } |
1430 | 1459 | ||
1431 | /* Replace a relative jump with a breakpoint (int3). */ | 1460 | /* Replace a relative jump with a breakpoint (int3). */ |
@@ -1457,11 +1486,35 @@ static int __kprobes setup_detour_execution(struct kprobe *p, | |||
1457 | } | 1486 | } |
1458 | return 0; | 1487 | return 0; |
1459 | } | 1488 | } |
1489 | |||
1490 | static int __kprobes init_poke_params(void) | ||
1491 | { | ||
1492 | /* Allocate code buffer and parameter array */ | ||
1493 | jump_poke_bufs = kmalloc(sizeof(struct jump_poke_buffer) * | ||
1494 | MAX_OPTIMIZE_PROBES, GFP_KERNEL); | ||
1495 | if (!jump_poke_bufs) | ||
1496 | return -ENOMEM; | ||
1497 | |||
1498 | jump_poke_params = kmalloc(sizeof(struct text_poke_param) * | ||
1499 | MAX_OPTIMIZE_PROBES, GFP_KERNEL); | ||
1500 | if (!jump_poke_params) { | ||
1501 | kfree(jump_poke_bufs); | ||
1502 | jump_poke_bufs = NULL; | ||
1503 | return -ENOMEM; | ||
1504 | } | ||
1505 | |||
1506 | return 0; | ||
1507 | } | ||
1508 | #else /* !CONFIG_OPTPROBES */ | ||
1509 | static int __kprobes init_poke_params(void) | ||
1510 | { | ||
1511 | return 0; | ||
1512 | } | ||
1460 | #endif | 1513 | #endif |
1461 | 1514 | ||
1462 | int __init arch_init_kprobes(void) | 1515 | int __init arch_init_kprobes(void) |
1463 | { | 1516 | { |
1464 | return 0; | 1517 | return init_poke_params(); |
1465 | } | 1518 | } |
1466 | 1519 | ||
1467 | int __kprobes arch_trampoline_kprobe(struct kprobe *p) | 1520 | int __kprobes arch_trampoline_kprobe(struct kprobe *p) |
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index e7d1b2e0070d..fe157ba6aa0e 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h | |||
@@ -275,7 +275,7 @@ extern int arch_prepared_optinsn(struct arch_optimized_insn *optinsn); | |||
275 | extern int arch_check_optimized_kprobe(struct optimized_kprobe *op); | 275 | extern int arch_check_optimized_kprobe(struct optimized_kprobe *op); |
276 | extern int arch_prepare_optimized_kprobe(struct optimized_kprobe *op); | 276 | extern int arch_prepare_optimized_kprobe(struct optimized_kprobe *op); |
277 | extern void arch_remove_optimized_kprobe(struct optimized_kprobe *op); | 277 | extern void arch_remove_optimized_kprobe(struct optimized_kprobe *op); |
278 | extern int arch_optimize_kprobe(struct optimized_kprobe *op); | 278 | extern void arch_optimize_kprobes(struct list_head *oplist); |
279 | extern void arch_unoptimize_kprobe(struct optimized_kprobe *op); | 279 | extern void arch_unoptimize_kprobe(struct optimized_kprobe *op); |
280 | extern kprobe_opcode_t *get_optinsn_slot(void); | 280 | extern kprobe_opcode_t *get_optinsn_slot(void); |
281 | extern void free_optinsn_slot(kprobe_opcode_t *slot, int dirty); | 281 | extern void free_optinsn_slot(kprobe_opcode_t *slot, int dirty); |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 134754d18bb4..531e10164836 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -480,8 +480,6 @@ static DECLARE_COMPLETION(optimizer_comp); | |||
480 | */ | 480 | */ |
481 | static __kprobes void do_optimize_kprobes(void) | 481 | static __kprobes void do_optimize_kprobes(void) |
482 | { | 482 | { |
483 | struct optimized_kprobe *op, *tmp; | ||
484 | |||
485 | /* Optimization never be done when disarmed */ | 483 | /* Optimization never be done when disarmed */ |
486 | if (kprobes_all_disarmed || !kprobes_allow_optimization || | 484 | if (kprobes_all_disarmed || !kprobes_allow_optimization || |
487 | list_empty(&optimizing_list)) | 485 | list_empty(&optimizing_list)) |
@@ -499,12 +497,7 @@ static __kprobes void do_optimize_kprobes(void) | |||
499 | */ | 497 | */ |
500 | get_online_cpus(); | 498 | get_online_cpus(); |
501 | mutex_lock(&text_mutex); | 499 | mutex_lock(&text_mutex); |
502 | list_for_each_entry_safe(op, tmp, &optimizing_list, list) { | 500 | arch_optimize_kprobes(&optimizing_list); |
503 | WARN_ON(kprobe_disabled(&op->kp)); | ||
504 | if (arch_optimize_kprobe(op) < 0) | ||
505 | op->kp.flags &= ~KPROBE_FLAG_OPTIMIZED; | ||
506 | list_del_init(&op->list); | ||
507 | } | ||
508 | mutex_unlock(&text_mutex); | 501 | mutex_unlock(&text_mutex); |
509 | put_online_cpus(); | 502 | put_online_cpus(); |
510 | } | 503 | } |
@@ -598,8 +591,12 @@ static __kprobes void kprobe_optimizer(struct work_struct *work) | |||
598 | mutex_unlock(&kprobe_mutex); | 591 | mutex_unlock(&kprobe_mutex); |
599 | mutex_unlock(&module_mutex); | 592 | mutex_unlock(&module_mutex); |
600 | 593 | ||
601 | /* Wake up all waiters */ | 594 | /* Step 5: Kick optimizer again if needed */ |
602 | complete_all(&optimizer_comp); | 595 | if (!list_empty(&optimizing_list)) |
596 | kick_kprobe_optimizer(); | ||
597 | else | ||
598 | /* Wake up all waiters */ | ||
599 | complete_all(&optimizer_comp); | ||
603 | } | 600 | } |
604 | 601 | ||
605 | /* Wait for completing optimization and unoptimization */ | 602 | /* Wait for completing optimization and unoptimization */ |