From cbf74cea070fa1f705de4712e25d9e56ae6543c7 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Mon, 30 May 2011 16:31:11 +0200 Subject: oprofile, x86: Add comments to IBS LVT offset initialization Adding a comment in the code as IBS LVT setup is not obvious at all ... Signed-off-by: Robert Richter --- arch/x86/kernel/apic/apic.c | 3 ++- arch/x86/oprofile/op_model_amd.c | 13 +++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index fabf01eff77..a0bf78a0918 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c @@ -390,7 +390,8 @@ static unsigned int reserve_eilvt_offset(int offset, unsigned int new) /* * If mask=1, the LVT entry does not generate interrupts while mask=0 - * enables the vector. See also the BKDGs. + * enables the vector. See also the BKDGs. Must be called with + * preemption disabled. */ int setup_APIC_eilvt(u8 offset, u8 vector, u8 msg_type, u8 mask) diff --git a/arch/x86/oprofile/op_model_amd.c b/arch/x86/oprofile/op_model_amd.c index 9fd8a567fe1..9cbb710dc94 100644 --- a/arch/x86/oprofile/op_model_amd.c +++ b/arch/x86/oprofile/op_model_amd.c @@ -609,16 +609,21 @@ static int setup_ibs_ctl(int ibs_eilvt_off) return 0; } +/* + * This runs only on the current cpu. We try to find an LVT offset and + * setup the local APIC. For this we must disable preemption. On + * success we initialize all nodes with this offset. This updates then + * the offset in the IBS_CTL per-node msr. The per-core APIC setup of + * the IBS interrupt vector is called from op_amd_setup_ctrs()/op_- + * amd_cpu_shutdown() using the new offset. + */ static int force_ibs_eilvt_setup(void) { int offset; int ret; - /* - * find the next free available EILVT entry, skip offset 0, - * pin search to this cpu - */ preempt_disable(); + /* find the next free available EILVT entry, skip offset 0 */ for (offset = 1; offset < APIC_EILVT_NR_MAX; offset++) { if (get_eilvt(offset)) break; -- cgit v1.2.3 From 6ac6519b93065625119a347be1cbcc1b89edb773 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 26 May 2011 18:22:54 +0200 Subject: oprofile: Free potentially owned tasks in case of errors After registering the task free notifier we possibly have tasks in our dying_tasks list. Free them after unregistering the notifier in case of an error. Cc: # .36+ Signed-off-by: Robert Richter --- drivers/oprofile/buffer_sync.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index a3984f4ef19..04250aa16f5 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -141,6 +141,13 @@ static struct notifier_block module_load_nb = { .notifier_call = module_load_notify, }; +static void free_all_tasks(void) +{ + /* make sure we don't leak task structs */ + process_task_mortuary(); + process_task_mortuary(); +} + int sync_start(void) { int err; @@ -174,6 +181,7 @@ out3: profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); out2: task_handoff_unregister(&task_free_nb); + free_all_tasks(); out1: free_cpumask_var(marked_cpus); goto out; @@ -192,10 +200,7 @@ void sync_stop(void) mutex_unlock(&buffer_mutex); flush_cpu_work(); - /* make sure we don't leak task structs */ - process_task_mortuary(); - process_task_mortuary(); - + free_all_tasks(); free_cpumask_var(marked_cpus); } -- cgit v1.2.3 From 130c5ce716c9bfd1c2a2ec840a746eb7ff9ce1e6 Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Thu, 26 May 2011 18:39:35 +0200 Subject: oprofile: Fix locking dependency in sync_start() This fixes the A->B/B->A locking dependency, see the warning below. The function task_exit_notify() is called with (task_exit_notifier) .rwsem set and then calls sync_buffer() which locks buffer_mutex. In sync_start() the buffer_mutex was set to prevent notifier functions to be started before sync_start() is finished. But when registering the notifier, (task_exit_notifier).rwsem is locked too, but now in different order than in sync_buffer(). In theory this causes a locking dependency, what does not occur in practice since task_exit_notify() is always called after the notifier is registered which means the lock is already released. However, after checking the notifier functions it turned out the buffer_mutex in sync_start() is unnecessary. This is because sync_buffer() may be called from the notifiers even if sync_start() did not finish yet, the buffers are already allocated but empty. No need to protect this with the mutex. So we fix this theoretical locking dependency by removing buffer_mutex in sync_start(). This is similar to the implementation before commit: 750d857 oprofile: fix crash when accessing freed task structs which introduced the locking dependency. Lockdep warning: oprofiled/4447 is trying to acquire lock: (buffer_mutex){+.+...}, at: [] sync_buffer+0x31/0x3ec [oprofile] but task is already holding lock: ((task_exit_notifier).rwsem){++++..}, at: [] __blocking_notifier_call_chain+0x39/0x67 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 ((task_exit_notifier).rwsem){++++..}: [] lock_acquire+0xf8/0x11e [] down_write+0x44/0x67 [] blocking_notifier_chain_register+0x52/0x8b [] profile_event_register+0x2d/0x2f [] sync_start+0x47/0xc6 [oprofile] [] oprofile_setup+0x60/0xa5 [oprofile] [] event_buffer_open+0x59/0x8c [oprofile] [] __dentry_open+0x1eb/0x308 [] nameidata_to_filp+0x60/0x67 [] do_last+0x5be/0x6b2 [] path_openat+0xc7/0x360 [] do_filp_open+0x3d/0x8c [] do_sys_open+0x110/0x1a9 [] sys_open+0x20/0x22 [] system_call_fastpath+0x16/0x1b -> #0 (buffer_mutex){+.+...}: [] __lock_acquire+0x1085/0x1711 [] lock_acquire+0xf8/0x11e [] mutex_lock_nested+0x63/0x309 [] sync_buffer+0x31/0x3ec [oprofile] [] task_exit_notify+0x16/0x1a [oprofile] [] notifier_call_chain+0x37/0x63 [] __blocking_notifier_call_chain+0x50/0x67 [] blocking_notifier_call_chain+0x14/0x16 [] profile_task_exit+0x1a/0x1c [] do_exit+0x2a/0x6fc [] do_group_exit+0x83/0xae [] sys_exit_group+0x17/0x1b [] system_call_fastpath+0x16/0x1b other info that might help us debug this: 1 lock held by oprofiled/4447: #0: ((task_exit_notifier).rwsem){++++..}, at: [] __blocking_notifier_call_chain+0x39/0x67 stack backtrace: Pid: 4447, comm: oprofiled Not tainted 2.6.39-00007-gcf4d8d4 #10 Call Trace: [] print_circular_bug+0xae/0xbc [] __lock_acquire+0x1085/0x1711 [] ? sync_buffer+0x31/0x3ec [oprofile] [] lock_acquire+0xf8/0x11e [] ? sync_buffer+0x31/0x3ec [oprofile] [] ? mark_lock+0x42f/0x552 [] ? sync_buffer+0x31/0x3ec [oprofile] [] mutex_lock_nested+0x63/0x309 [] ? sync_buffer+0x31/0x3ec [oprofile] [] sync_buffer+0x31/0x3ec [oprofile] [] ? __blocking_notifier_call_chain+0x39/0x67 [] ? __blocking_notifier_call_chain+0x39/0x67 [] task_exit_notify+0x16/0x1a [oprofile] [] notifier_call_chain+0x37/0x63 [] __blocking_notifier_call_chain+0x50/0x67 [] blocking_notifier_call_chain+0x14/0x16 [] profile_task_exit+0x1a/0x1c [] do_exit+0x2a/0x6fc [] ? retint_swapgs+0xe/0x13 [] do_group_exit+0x83/0xae [] sys_exit_group+0x17/0x1b [] system_call_fastpath+0x16/0x1b Reported-by: Marcin Slusarz Cc: Carl Love Cc: # .36+ Signed-off-by: Robert Richter --- drivers/oprofile/buffer_sync.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 04250aa16f5..f34b5b29fb9 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -155,8 +155,6 @@ int sync_start(void) if (!zalloc_cpumask_var(&marked_cpus, GFP_KERNEL)) return -ENOMEM; - mutex_lock(&buffer_mutex); - err = task_handoff_register(&task_free_nb); if (err) goto out1; @@ -173,7 +171,6 @@ int sync_start(void) start_cpu_work(); out: - mutex_unlock(&buffer_mutex); return err; out4: profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); @@ -190,14 +187,13 @@ out1: void sync_stop(void) { - /* flush buffers */ - mutex_lock(&buffer_mutex); end_cpu_work(); unregister_module_notifier(&module_load_nb); profile_event_unregister(PROFILE_MUNMAP, &munmap_nb); profile_event_unregister(PROFILE_TASK_EXIT, &task_exit_nb); task_handoff_unregister(&task_free_nb); - mutex_unlock(&buffer_mutex); + barrier(); /* do all of the above first */ + flush_cpu_work(); free_all_tasks(); -- cgit v1.2.3 From fe47ae7f53e179d2ef6771024feb000cbb86640f Mon Sep 17 00:00:00 2001 From: Robert Richter Date: Tue, 31 May 2011 12:35:41 +0200 Subject: oprofile, dcookies: Fix possible circular locking dependency The lockdep warning below detects a possible A->B/B->A locking dependency of mm->mmap_sem and dcookie_mutex. The order in sync_buffer() is mm->mmap_sem/dcookie_mutex, while in sys_lookup_dcookie() it is vice versa. Fixing it in sys_lookup_dcookie() by unlocking dcookie_mutex before copy_to_user(). oprofiled/4432 is trying to acquire lock: (&mm->mmap_sem){++++++}, at: [] might_fault+0x53/0xa3 but task is already holding lock: (dcookie_mutex){+.+.+.}, at: [] sys_lookup_dcookie+0x45/0x149 which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (dcookie_mutex){+.+.+.}: [] lock_acquire+0xf8/0x11e [] mutex_lock_nested+0x63/0x309 [] get_dcookie+0x30/0x144 [] sync_buffer+0x196/0x3ec [oprofile] [] task_exit_notify+0x16/0x1a [oprofile] [] notifier_call_chain+0x37/0x63 [] __blocking_notifier_call_chain+0x50/0x67 [] blocking_notifier_call_chain+0x14/0x16 [] profile_task_exit+0x1a/0x1c [] do_exit+0x2a/0x6fc [] do_group_exit+0x83/0xae [] sys_exit_group+0x17/0x1b [] system_call_fastpath+0x16/0x1b -> #0 (&mm->mmap_sem){++++++}: [] __lock_acquire+0x1085/0x1711 [] lock_acquire+0xf8/0x11e [] might_fault+0x80/0xa3 [] sys_lookup_dcookie+0x104/0x149 [] system_call_fastpath+0x16/0x1b other info that might help us debug this: 1 lock held by oprofiled/4432: #0: (dcookie_mutex){+.+.+.}, at: [] sys_lookup_dcookie+0x45/0x149 stack backtrace: Pid: 4432, comm: oprofiled Not tainted 2.6.39-00008-ge5a450d #9 Call Trace: [] print_circular_bug+0xae/0xbc [] __lock_acquire+0x1085/0x1711 [] ? get_parent_ip+0x11/0x42 [] ? might_fault+0x53/0xa3 [] lock_acquire+0xf8/0x11e [] ? might_fault+0x53/0xa3 [] ? path_put+0x22/0x27 [] might_fault+0x80/0xa3 [] ? might_fault+0x53/0xa3 [] sys_lookup_dcookie+0x104/0x149 [] system_call_fastpath+0x16/0x1b References: https://bugzilla.kernel.org/show_bug.cgi?id=13809 Cc: # .27+ Signed-off-by: Robert Richter --- fs/dcookies.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/dcookies.c b/fs/dcookies.c index a21cabdbd87..dda0dc702d1 100644 --- a/fs/dcookies.c +++ b/fs/dcookies.c @@ -178,6 +178,8 @@ SYSCALL_DEFINE(lookup_dcookie)(u64 cookie64, char __user * buf, size_t len) /* FIXME: (deleted) ? */ path = d_path(&dcs->path, kbuf, PAGE_SIZE); + mutex_unlock(&dcookie_mutex); + if (IS_ERR(path)) { err = PTR_ERR(path); goto out_free; @@ -194,6 +196,7 @@ SYSCALL_DEFINE(lookup_dcookie)(u64 cookie64, char __user * buf, size_t len) out_free: kfree(kbuf); + return err; out: mutex_unlock(&dcookie_mutex); return err; -- cgit v1.2.3 From 0aff1c0cef13b34c17e81a502336fad738151c37 Mon Sep 17 00:00:00 2001 From: GuoWen Li Date: Wed, 1 Jun 2011 19:18:47 +0800 Subject: ftrace: Fix possible undefined return code kernel/trace/ftrace.c: In function 'ftrace_regex_write.clone.15': kernel/trace/ftrace.c:2743:6: warning: 'ret' may be used uninitialized in this function Signed-off-by: GuoWen Li Link: http://lkml.kernel.org/r/201106011918.47939.guowen.li.linux@gmail.com Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 1ee417fcbfa..204b3eb4e69 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2740,7 +2740,7 @@ static int ftrace_process_regex(struct ftrace_hash *hash, { char *func, *command, *next = buff; struct ftrace_func_command *p; - int ret; + int ret = -EINVAL; func = strsep(&next, ":"); -- cgit v1.2.3 From 265a5b7ee3eb21a4d0e53e17d59ba6eada91af39 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Mon, 6 Jun 2011 22:35:13 -0400 Subject: kprobes/trace: Fix kprobe selftest for gcc 4.6 With gcc 4.6, the self test kprobe function: kprobe_trace_selftest_target() is optimized such that kallsyms does not list it. The kprobes test uses this function to insert a probe and test it. But it will fail the test if the function is not listed in kallsyms. Adding a __used annotation keeps the symbol in the kallsyms table. Suggested-by: David Daney Cc: Masami Hiramatsu Signed-off-by: Steven Rostedt --- kernel/trace/trace_kprobe.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index f925c45f0af..27d13b36b8b 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -1870,8 +1870,12 @@ fs_initcall(init_kprobe_trace); #ifdef CONFIG_FTRACE_STARTUP_TEST -static int kprobe_trace_selftest_target(int a1, int a2, int a3, - int a4, int a5, int a6) +/* + * The "__used" keeps gcc from removing the function symbol + * from the kallsyms table. + */ +static __used int kprobe_trace_selftest_target(int a1, int a2, int a3, + int a4, int a5, int a6) { return a1 + a2 + a3 + a4 + a5 + a6; } -- cgit v1.2.3 From a4f18ed11a4ddf327dd91cd19e237278600ad327 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Tue, 7 Jun 2011 09:26:46 -0400 Subject: ftrace: Revert 8ab2b7efd ftrace: Remove unnecessary disabling of irqs Revert the commit that removed the disabling of interrupts around the initial modifying of mcount callers to nops, and update the comment. The original comment was outdated and stated that the interrupts were being disabled to prevent kstop machine, which was required with the old ftrace daemon, but was no longer the case. What the comment failed to mention was that interrupts needed to be disabled to keep interrupts from preempting the modifying of the code and then executing the code that was partially modified. Revert the commit and update the comment. Reported-by: Richard W.M. Jones Tested-by: Richard W.M. Jones Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 204b3eb4e69..908038f5744 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -3330,6 +3330,7 @@ static int ftrace_process_locs(struct module *mod, { unsigned long *p; unsigned long addr; + unsigned long flags; mutex_lock(&ftrace_lock); p = start; @@ -3346,7 +3347,13 @@ static int ftrace_process_locs(struct module *mod, ftrace_record_ip(addr); } + /* + * Disable interrupts to prevent interrupts from executing + * code that is being modified. + */ + local_irq_save(flags); ftrace_update_code(mod); + local_irq_restore(flags); mutex_unlock(&ftrace_lock); return 0; -- cgit v1.2.3