aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorMarkus Metzger <markus.t.metzger@intel.com>2008-12-19 09:10:24 -0500
committerIngo Molnar <mingo@elte.hu>2008-12-20 03:15:46 -0500
commitbf53de907dfdaac178c92d774aae7370d7b97d20 (patch)
tree738a07a8b4b22f7bb8ec2029c9ea9c635db6c62a /arch/x86
parent30cd324e9787ccc9a5ede59742d5409857550692 (diff)
x86, bts: add fork and exit handling
Impact: introduce new ptrace facility Add arch_ptrace_untrace() function that is called when the tracer detaches (either voluntarily or when the tracing task dies); ptrace_disable() is only called on a voluntary detach. Add ptrace_fork() and arch_ptrace_fork(). They are called when a traced task is forked. Clear DS and BTS related fields on fork. Release DS resources and reclaim memory in ptrace_untrace(). This releases resources already when the tracing task dies. We used to do that when the traced task dies. Signed-off-by: Markus Metzger <markus.t.metzger@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/include/asm/ds.h9
-rw-r--r--arch/x86/include/asm/ptrace.h7
-rw-r--r--arch/x86/kernel/ds.c11
-rw-r--r--arch/x86/kernel/process_32.c20
-rw-r--r--arch/x86/kernel/process_64.c20
-rw-r--r--arch/x86/kernel/ptrace.c50
6 files changed, 85 insertions, 32 deletions
diff --git a/arch/x86/include/asm/ds.h b/arch/x86/include/asm/ds.h
index ee0ea3a96c11..a8f672ba100c 100644
--- a/arch/x86/include/asm/ds.h
+++ b/arch/x86/include/asm/ds.h
@@ -252,12 +252,21 @@ extern void __cpuinit ds_init_intel(struct cpuinfo_x86 *);
252 */ 252 */
253extern void ds_switch_to(struct task_struct *prev, struct task_struct *next); 253extern void ds_switch_to(struct task_struct *prev, struct task_struct *next);
254 254
255/*
256 * Task clone/init and cleanup work
257 */
258extern void ds_copy_thread(struct task_struct *tsk, struct task_struct *father);
259extern void ds_exit_thread(struct task_struct *tsk);
260
255#else /* CONFIG_X86_DS */ 261#else /* CONFIG_X86_DS */
256 262
257struct cpuinfo_x86; 263struct cpuinfo_x86;
258static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {} 264static inline void __cpuinit ds_init_intel(struct cpuinfo_x86 *ignored) {}
259static inline void ds_switch_to(struct task_struct *prev, 265static inline void ds_switch_to(struct task_struct *prev,
260 struct task_struct *next) {} 266 struct task_struct *next) {}
267static inline void ds_copy_thread(struct task_struct *tsk,
268 struct task_struct *father) {}
269static inline void ds_exit_thread(struct task_struct *tsk) {}
261 270
262#endif /* CONFIG_X86_DS */ 271#endif /* CONFIG_X86_DS */
263#endif /* _ASM_X86_DS_H */ 272#endif /* _ASM_X86_DS_H */
diff --git a/arch/x86/include/asm/ptrace.h b/arch/x86/include/asm/ptrace.h
index fbf744215911..6d34d954c228 100644
--- a/arch/x86/include/asm/ptrace.h
+++ b/arch/x86/include/asm/ptrace.h
@@ -235,6 +235,13 @@ extern int do_get_thread_area(struct task_struct *p, int idx,
235extern int do_set_thread_area(struct task_struct *p, int idx, 235extern int do_set_thread_area(struct task_struct *p, int idx,
236 struct user_desc __user *info, int can_allocate); 236 struct user_desc __user *info, int can_allocate);
237 237
238extern void x86_ptrace_untrace(struct task_struct *);
239extern void x86_ptrace_fork(struct task_struct *child,
240 unsigned long clone_flags);
241
242#define arch_ptrace_untrace(tsk) x86_ptrace_untrace(tsk)
243#define arch_ptrace_fork(child, flags) x86_ptrace_fork(child, flags)
244
238#endif /* __KERNEL__ */ 245#endif /* __KERNEL__ */
239 246
240#endif /* !__ASSEMBLY__ */ 247#endif /* !__ASSEMBLY__ */
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c
index 98d271e60e08..da91701a2348 100644
--- a/arch/x86/kernel/ds.c
+++ b/arch/x86/kernel/ds.c
@@ -1017,3 +1017,14 @@ void ds_switch_to(struct task_struct *prev, struct task_struct *next)
1017 1017
1018 update_debugctlmsr(next->thread.debugctlmsr); 1018 update_debugctlmsr(next->thread.debugctlmsr);
1019} 1019}
1020
1021void ds_copy_thread(struct task_struct *tsk, struct task_struct *father)
1022{
1023 clear_tsk_thread_flag(tsk, TIF_DS_AREA_MSR);
1024 tsk->thread.ds_ctx = NULL;
1025}
1026
1027void ds_exit_thread(struct task_struct *tsk)
1028{
1029 WARN_ON(tsk->thread.ds_ctx);
1030}
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 605eff9a8ac0..3ba155d24884 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -60,6 +60,7 @@
60#include <asm/idle.h> 60#include <asm/idle.h>
61#include <asm/syscalls.h> 61#include <asm/syscalls.h>
62#include <asm/smp.h> 62#include <asm/smp.h>
63#include <asm/ds.h>
63 64
64asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); 65asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
65 66
@@ -251,17 +252,8 @@ void exit_thread(void)
251 tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET; 252 tss->x86_tss.io_bitmap_base = INVALID_IO_BITMAP_OFFSET;
252 put_cpu(); 253 put_cpu();
253 } 254 }
254#ifdef CONFIG_X86_DS 255
255 /* Free any BTS tracers that have not been properly released. */ 256 ds_exit_thread(current);
256 if (unlikely(current->bts)) {
257 ds_release_bts(current->bts);
258 current->bts = NULL;
259
260 kfree(current->bts_buffer);
261 current->bts_buffer = NULL;
262 current->bts_size = 0;
263 }
264#endif /* CONFIG_X86_DS */
265} 257}
266 258
267void flush_thread(void) 259void flush_thread(void)
@@ -343,6 +335,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
343 kfree(p->thread.io_bitmap_ptr); 335 kfree(p->thread.io_bitmap_ptr);
344 p->thread.io_bitmap_max = 0; 336 p->thread.io_bitmap_max = 0;
345 } 337 }
338
339 ds_copy_thread(p, current);
340
341 clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);
342 p->thread.debugctlmsr = 0;
343
346 return err; 344 return err;
347} 345}
348 346
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 1cfd2a4bf853..416fb9282f4f 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -53,6 +53,7 @@
53#include <asm/ia32.h> 53#include <asm/ia32.h>
54#include <asm/idle.h> 54#include <asm/idle.h>
55#include <asm/syscalls.h> 55#include <asm/syscalls.h>
56#include <asm/ds.h>
56 57
57asmlinkage extern void ret_from_fork(void); 58asmlinkage extern void ret_from_fork(void);
58 59
@@ -236,17 +237,8 @@ void exit_thread(void)
236 t->io_bitmap_max = 0; 237 t->io_bitmap_max = 0;
237 put_cpu(); 238 put_cpu();
238 } 239 }
239#ifdef CONFIG_X86_DS 240
240 /* Free any BTS tracers that have not been properly released. */ 241 ds_exit_thread(current);
241 if (unlikely(current->bts)) {
242 ds_release_bts(current->bts);
243 current->bts = NULL;
244
245 kfree(current->bts_buffer);
246 current->bts_buffer = NULL;
247 current->bts_size = 0;
248 }
249#endif /* CONFIG_X86_DS */
250} 242}
251 243
252void flush_thread(void) 244void flush_thread(void)
@@ -376,6 +368,12 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp,
376 if (err) 368 if (err)
377 goto out; 369 goto out;
378 } 370 }
371
372 ds_copy_thread(p, me);
373
374 clear_tsk_thread_flag(p, TIF_DEBUGCTLMSR);
375 p->thread.debugctlmsr = 0;
376
379 err = 0; 377 err = 0;
380out: 378out:
381 if (err && p->thread.io_bitmap_ptr) { 379 if (err && p->thread.io_bitmap_ptr) {
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index 45e9855da2d2..6ad2bb607650 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -769,8 +769,47 @@ static int ptrace_bts_size(struct task_struct *child)
769 769
770 return (trace->ds.top - trace->ds.begin) / trace->ds.size; 770 return (trace->ds.top - trace->ds.begin) / trace->ds.size;
771} 771}
772
773static void ptrace_bts_fork(struct task_struct *tsk)
774{
775 tsk->bts = NULL;
776 tsk->bts_buffer = NULL;
777 tsk->bts_size = 0;
778 tsk->thread.bts_ovfl_signal = 0;
779}
780
781static void ptrace_bts_untrace(struct task_struct *child)
782{
783 if (unlikely(child->bts)) {
784 ds_release_bts(child->bts);
785 child->bts = NULL;
786
787 kfree(child->bts_buffer);
788 child->bts_buffer = NULL;
789 child->bts_size = 0;
790 }
791}
792
793static void ptrace_bts_detach(struct task_struct *child)
794{
795 ptrace_bts_untrace(child);
796}
797#else
798static inline void ptrace_bts_fork(struct task_struct *tsk) {}
799static inline void ptrace_bts_detach(struct task_struct *child) {}
800static inline void ptrace_bts_untrace(struct task_struct *child) {}
772#endif /* CONFIG_X86_PTRACE_BTS */ 801#endif /* CONFIG_X86_PTRACE_BTS */
773 802
803void x86_ptrace_fork(struct task_struct *child, unsigned long clone_flags)
804{
805 ptrace_bts_fork(child);
806}
807
808void x86_ptrace_untrace(struct task_struct *child)
809{
810 ptrace_bts_untrace(child);
811}
812
774/* 813/*
775 * Called by kernel/ptrace.c when detaching.. 814 * Called by kernel/ptrace.c when detaching..
776 * 815 *
@@ -782,16 +821,7 @@ void ptrace_disable(struct task_struct *child)
782#ifdef TIF_SYSCALL_EMU 821#ifdef TIF_SYSCALL_EMU
783 clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); 822 clear_tsk_thread_flag(child, TIF_SYSCALL_EMU);
784#endif 823#endif
785#ifdef CONFIG_X86_PTRACE_BTS 824 ptrace_bts_detach(child);
786 if (child->bts) {
787 ds_release_bts(child->bts);
788 child->bts = NULL;
789
790 kfree(child->bts_buffer);
791 child->bts_buffer = NULL;
792 child->bts_size = 0;
793 }
794#endif /* CONFIG_X86_PTRACE_BTS */
795} 825}
796 826
797#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION 827#if defined CONFIG_X86_32 || defined CONFIG_IA32_EMULATION