aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/kprobes.c
diff options
context:
space:
mode:
authorAnanth N Mavinakayanahalli <ananth@in.ibm.com>2005-11-07 04:00:07 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 10:53:45 -0500
commit66ff2d0691e00e1e7bfdf398a970310c9a0fe671 (patch)
treef53bcd846be8fbaee5a5ee65f9bacc5b34392090 /arch/i386/kernel/kprobes.c
parentb385676b355549afc9a7507ce09c7df47f166521 (diff)
[PATCH] Kprobes: rearrange preempt_disable/enable() calls
The following set of patches are aimed at improving kprobes scalability. We currently serialize kprobe registration, unregistration and handler execution using a single spinlock - kprobe_lock. With these changes, kprobe handlers can run without any locks held. It also allows for simultaneous kprobe handler executions on different processors as we now track kprobe execution on a per processor basis. It is now necessary that the handlers be re-entrant since handlers can run concurrently on multiple processors. All changes have been tested on i386, ia64, ppc64 and x86_64, while sparc64 has been compile tested only. The patches can be viewed as 3 logical chunks: patch 1: Reorder preempt_(dis/en)able calls patches 2-7: Introduce per_cpu data areas to track kprobe execution patches 8-9: Use RCU to synchronize kprobe (un)registration and handler execution. Thanks to Maneesh Soni, James Keniston and Anil Keshavamurthy for their review and suggestions. Thanks again to Anil, Hien Nguyen and Kevin Stafford for testing the patches. This patch: Reorder preempt_disable/enable() calls in arch kprobes files in preparation to introduce locking changes. No functional changes introduced by this patch. Signed-off-by: Ananth N Mavinakayahanalli <ananth@in.ibm.com> Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/kernel/kprobes.c')
-rw-r--r--arch/i386/kernel/kprobes.c35
1 files changed, 18 insertions, 17 deletions
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index 6345b430b105..fd35039859e6 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -158,8 +158,6 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
158 kprobe_opcode_t *addr = NULL; 158 kprobe_opcode_t *addr = NULL;
159 unsigned long *lp; 159 unsigned long *lp;
160 160
161 /* We're in an interrupt, but this is clear and BUG()-safe. */
162 preempt_disable();
163 /* Check if the application is using LDT entry for its code segment and 161 /* Check if the application is using LDT entry for its code segment and
164 * calculate the address by reading the base address from the LDT entry. 162 * calculate the address by reading the base address from the LDT entry.
165 */ 163 */
@@ -232,6 +230,11 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
232 goto no_kprobe; 230 goto no_kprobe;
233 } 231 }
234 232
233 /*
234 * This preempt_disable() matches the preempt_enable_no_resched()
235 * in post_kprobe_handler()
236 */
237 preempt_disable();
235 kprobe_status = KPROBE_HIT_ACTIVE; 238 kprobe_status = KPROBE_HIT_ACTIVE;
236 set_current_kprobe(p, regs); 239 set_current_kprobe(p, regs);
237 240
@@ -245,7 +248,6 @@ ss_probe:
245 return 1; 248 return 1;
246 249
247no_kprobe: 250no_kprobe:
248 preempt_enable_no_resched();
249 return ret; 251 return ret;
250} 252}
251 253
@@ -313,11 +315,11 @@ int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
313 unlock_kprobes(); 315 unlock_kprobes();
314 preempt_enable_no_resched(); 316 preempt_enable_no_resched();
315 317
316 /* 318 /*
317 * By returning a non-zero value, we are telling 319 * By returning a non-zero value, we are telling
318 * kprobe_handler() that we have handled unlocking 320 * kprobe_handler() that we have handled unlocking
319 * and re-enabling preemption. 321 * and re-enabling preemption
320 */ 322 */
321 return 1; 323 return 1;
322} 324}
323 325
@@ -453,29 +455,29 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
453 unsigned long val, void *data) 455 unsigned long val, void *data)
454{ 456{
455 struct die_args *args = (struct die_args *)data; 457 struct die_args *args = (struct die_args *)data;
458 int ret = NOTIFY_DONE;
459
460 preempt_disable();
456 switch (val) { 461 switch (val) {
457 case DIE_INT3: 462 case DIE_INT3:
458 if (kprobe_handler(args->regs)) 463 if (kprobe_handler(args->regs))
459 return NOTIFY_STOP; 464 ret = NOTIFY_STOP;
460 break; 465 break;
461 case DIE_DEBUG: 466 case DIE_DEBUG:
462 if (post_kprobe_handler(args->regs)) 467 if (post_kprobe_handler(args->regs))
463 return NOTIFY_STOP; 468 ret = NOTIFY_STOP;
464 break; 469 break;
465 case DIE_GPF: 470 case DIE_GPF:
466 if (kprobe_running() &&
467 kprobe_fault_handler(args->regs, args->trapnr))
468 return NOTIFY_STOP;
469 break;
470 case DIE_PAGE_FAULT: 471 case DIE_PAGE_FAULT:
471 if (kprobe_running() && 472 if (kprobe_running() &&
472 kprobe_fault_handler(args->regs, args->trapnr)) 473 kprobe_fault_handler(args->regs, args->trapnr))
473 return NOTIFY_STOP; 474 ret = NOTIFY_STOP;
474 break; 475 break;
475 default: 476 default:
476 break; 477 break;
477 } 478 }
478 return NOTIFY_DONE; 479 preempt_enable();
480 return ret;
479} 481}
480 482
481int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) 483int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
@@ -502,7 +504,6 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs)
502 504
503void __kprobes jprobe_return(void) 505void __kprobes jprobe_return(void)
504{ 506{
505 preempt_enable_no_resched();
506 asm volatile (" xchgl %%ebx,%%esp \n" 507 asm volatile (" xchgl %%ebx,%%esp \n"
507 " int3 \n" 508 " int3 \n"
508 " .globl jprobe_return_end \n" 509 " .globl jprobe_return_end \n"