diff options
author | Robert Richter <robert.richter@amd.com> | 2011-10-07 10:31:46 -0400 |
---|---|---|
committer | Robert Richter <robert.richter@amd.com> | 2011-11-04 10:04:33 -0400 |
commit | 87121ca504fd1d963a66b3fb0c72054b0fd9a177 (patch) | |
tree | 789b9c8a7ea7b92d5359aa59653dd394bdec3710 /drivers/oprofile | |
parent | 4167ab90ee6a2c029855db53d1631c84a213f3d1 (diff) |
oprofile: Fix crash when unloading module (hr timer mode)
Oprofile may crash in a KVM guest while unlaoding modules. This
happens if oprofile_arch_init() fails and oprofile switches to the hr
timer mode as a fallback. In this case oprofile_arch_exit() is called,
but it never was initialized properly which causes the crash. This
patch fixes this.
oprofile: using timer interrupt.
BUG: unable to handle kernel NULL pointer dereference at 0000000000000008
IP: [<ffffffff8123c226>] unregister_syscore_ops+0x41/0x58
PGD 41da3f067 PUD 41d80e067 PMD 0
Oops: 0002 [#1] PREEMPT SMP
CPU 5
Modules linked in: oprofile(-)
Pid: 2382, comm: modprobe Not tainted 3.1.0-rc7-00018-g709a39d #18 Advanced Micro Device Anaheim/Anaheim
RIP: 0010:[<ffffffff8123c226>] [<ffffffff8123c226>] unregister_syscore_ops+0x41/0x58
RSP: 0018:ffff88041de1de98 EFLAGS: 00010296
RAX: 0000000000000000 RBX: ffffffffa00060e0 RCX: dead000000200200
RDX: 0000000000000000 RSI: dead000000100100 RDI: ffffffff8178c620
RBP: ffff88041de1dea8 R08: 0000000000000001 R09: 0000000000000082
R10: 0000000000000000 R11: ffff88041de1dde8 R12: 0000000000000080
R13: fffffffffffffff5 R14: 0000000000000001 R15: 0000000000610210
FS: 00007f9ae5bef700(0000) GS:ffff88042fd40000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
CR2: 0000000000000008 CR3: 000000041ca44000 CR4: 00000000000006e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process modprobe (pid: 2382, threadinfo ffff88041de1c000, task ffff88042db6d040)
Stack:
ffff88041de1deb8 ffffffffa0006770 ffff88041de1deb8 ffffffffa000251e
ffff88041de1dec8 ffffffffa00022c2 ffff88041de1ded8 ffffffffa0004993
ffff88041de1df78 ffffffff81073115 656c69666f72706f 0000000000610200
Call Trace:
[<ffffffffa000251e>] op_nmi_exit+0x15/0x17 [oprofile]
[<ffffffffa00022c2>] oprofile_arch_exit+0xe/0x10 [oprofile]
[<ffffffffa0004993>] oprofile_exit+0x13/0x15 [oprofile]
[<ffffffff81073115>] sys_delete_module+0x1c3/0x22f
[<ffffffff811bf09e>] ? trace_hardirqs_on_thunk+0x3a/0x3f
[<ffffffff8148070b>] system_call_fastpath+0x16/0x1b
Code: 20 c6 78 81 e8 c5 cc 23 00 48 8b 13 48 8b 43 08 48 be 00 01 10 00 00 00 ad de 48 b9 00 02 20 00 00 00 ad de 48 c7 c7 20 c6 78 81
89 42 08 48 89 10 48 89 33 48 89 4b 08 e8 a6 c0 23 00 5a 5b
RIP [<ffffffff8123c226>] unregister_syscore_ops+0x41/0x58
RSP <ffff88041de1de98>
CR2: 0000000000000008
---[ end trace 06d4e95b6aa3b437 ]---
CC: stable@kernel.org # 2.6.37+
Signed-off-by: Robert Richter <robert.richter@amd.com>
Diffstat (limited to 'drivers/oprofile')
-rw-r--r-- | drivers/oprofile/oprof.c | 29 | ||||
-rw-r--r-- | drivers/oprofile/timer_int.c | 1 |
2 files changed, 25 insertions, 5 deletions
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c index dccd8636095c..f8c752e408a6 100644 --- a/drivers/oprofile/oprof.c +++ b/drivers/oprofile/oprof.c | |||
@@ -239,26 +239,45 @@ int oprofile_set_ulong(unsigned long *addr, unsigned long val) | |||
239 | return err; | 239 | return err; |
240 | } | 240 | } |
241 | 241 | ||
242 | static int timer_mode; | ||
243 | |||
242 | static int __init oprofile_init(void) | 244 | static int __init oprofile_init(void) |
243 | { | 245 | { |
244 | int err; | 246 | int err; |
245 | 247 | ||
248 | /* always init architecture to setup backtrace support */ | ||
246 | err = oprofile_arch_init(&oprofile_ops); | 249 | err = oprofile_arch_init(&oprofile_ops); |
247 | if (err < 0 || timer) { | 250 | |
248 | printk(KERN_INFO "oprofile: using timer interrupt.\n"); | 251 | timer_mode = err || timer; /* fall back to timer mode on errors */ |
252 | if (timer_mode) { | ||
253 | if (!err) | ||
254 | oprofile_arch_exit(); | ||
249 | err = oprofile_timer_init(&oprofile_ops); | 255 | err = oprofile_timer_init(&oprofile_ops); |
250 | if (err) | 256 | if (err) |
251 | return err; | 257 | return err; |
252 | } | 258 | } |
253 | return oprofilefs_register(); | 259 | |
260 | err = oprofilefs_register(); | ||
261 | if (!err) | ||
262 | return 0; | ||
263 | |||
264 | /* failed */ | ||
265 | if (timer_mode) | ||
266 | oprofile_timer_exit(); | ||
267 | else | ||
268 | oprofile_arch_exit(); | ||
269 | |||
270 | return err; | ||
254 | } | 271 | } |
255 | 272 | ||
256 | 273 | ||
257 | static void __exit oprofile_exit(void) | 274 | static void __exit oprofile_exit(void) |
258 | { | 275 | { |
259 | oprofile_timer_exit(); | ||
260 | oprofilefs_unregister(); | 276 | oprofilefs_unregister(); |
261 | oprofile_arch_exit(); | 277 | if (timer_mode) |
278 | oprofile_timer_exit(); | ||
279 | else | ||
280 | oprofile_arch_exit(); | ||
262 | } | 281 | } |
263 | 282 | ||
264 | 283 | ||
diff --git a/drivers/oprofile/timer_int.c b/drivers/oprofile/timer_int.c index 3ef44624f510..878fba126582 100644 --- a/drivers/oprofile/timer_int.c +++ b/drivers/oprofile/timer_int.c | |||
@@ -110,6 +110,7 @@ int oprofile_timer_init(struct oprofile_operations *ops) | |||
110 | ops->start = oprofile_hrtimer_start; | 110 | ops->start = oprofile_hrtimer_start; |
111 | ops->stop = oprofile_hrtimer_stop; | 111 | ops->stop = oprofile_hrtimer_stop; |
112 | ops->cpu_type = "timer"; | 112 | ops->cpu_type = "timer"; |
113 | printk(KERN_INFO "oprofile: using timer interrupt.\n"); | ||
113 | return 0; | 114 | return 0; |
114 | } | 115 | } |
115 | 116 | ||