[<prev] [next>] [day] [month] [year] [list]
Message-ID: <912acd9b-5639-ddef-a394-c02dc82923e6@huawei.com>
Date: Thu, 25 Mar 2021 11:29:56 +0800
From: wangjian <wangjian161@...wei.com>
To: <tglx@...utronix.de>, <fweisbec@...il.com>, <mingo@...nel.org>,
<akpm@...ux-foundation.org>
CC: <linux-kernel@...r.kernel.org>, <kenel-bugs@...neuler.org>,
<dev@...neuler.org>, <eric.fangyi@...wei.com>
Subject: [question] kernel panic at timerqueue_add+32
On the x86 platform, we encountered the following problems. The kernel version we are using is 3.10. The following is our analysis process, hoping to get your help.
kernel panic at timerqueue_add+32.The stack information is as follows.
crash> bt -c 3
PID: 27797 TASK: ffff9f9e28805f40 CPU: 3 COMMAND: "ipmi_sim"
#0 [ffff9f9ec0ac3dd0] die at ffffffffac82f97b
#1 [ffff9f9ec0ac3e00] do_general_protection at ffffffffacf3211e
#2 [ffff9f9ec0ac3e30] general_protection at ffffffffacf31718
[exception RIP: timerqueue_add+32]
RIP: ffffffffacb67340 RSP: ffff9f9ec0ac3ee0 RFLAGS: 00010006
RAX: 7401f88348078b48 RBX: ffff9f9ec0ad3fa0 RCX: 0000000000000000
RDX: ffffffffac8d4395 RSI: ffff9f9ec0ad3fa0 RDI: ffffffffac8d4395
RBP: ffff9f9ec0ac3ef0 R8: 00405b31f6958080 R9: ffff9f9ec0ac3de0
R10: 0000000000000002 R11: ffff9f9ec0ac3de8 R12: ffffffffac8d4395
R13: ffffffffac8d4385 R14: 0000000000000001 R15: ffff9f9ec0ad3b58
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
#3 [ffff9f9ec0ac3ef8] enqueue_hrtimer at ffffffffac8c32f5
#4 [ffff9f9ec0ac3f20] __hrtimer_run_queues at ffffffffac8c3c7d
#5 [ffff9f9ec0ac3f78] hrtimer_interrupt at ffffffffac8c41af
#6 [ffff9f9ec0ac3fc0] local_apic_timer_interrupt at ffffffffac85aeeb
#7 [ffff9f9ec0ac3fd8] smp_apic_timer_interrupt at ffffffffacf3f0a3
#8 [ffff9f9ec0ac3ff0] apic_timer_interrupt at ffffffffacf3b7ba
--- <IRQ stack> ---
bt: cannot transition from IRQ stack to current process stack:
IRQ stack pointer: ffff9f9ec0ac3dd0
process stack pointer: ffff9f708e693df8
current stack base: ffff9f9e25764000
We first parse timerqueue_add+32
crash> dis -l timerqueue_add+32
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/lib/timerqueue.c: 52
0xffffffffacb67340 <timerqueue_add+32>: mov 0x18(%rax),%rsi
39 void timerqueue_add(struct timerqueue_head *head, struct timerqueue_node *node)
40 {
41 struct rb_node **p = &head->head.rb_node;
42 struct rb_node *parent = NULL;
43 struct timerqueue_node *ptr;
44
45 /* Make sure we don't add nodes that are already added */
46 WARN_ON_ONCE(!RB_EMPTY_NODE(&node->node));
47
48 while (*p) {
49 parent = *p;
50 ptr = rb_entry(parent, struct timerqueue_node, node);
51 if (node->expires.tv64 < ptr->expires.tv64)
52 p = &(*p)->rb_left; //at here, the p is the invalid address
53 else
54 p = &(*p)->rb_right;
55 }
56 rb_link_node(&node->node, parent, p);
57 rb_insert_color(&node->node, &head->head);
58
59 if (!head->next || node->expires.tv64 < head->next->expires.tv64)
60 head->next = node;
61 }
62 EXPORT_SYMBOL_GPL(timerqueue_add);
Let's disassemble the timerqueue_add function, the following is the part of the disassembled code of the timerqueue_add function
crash> dis -l timerqueue_add
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/lib/timerqueue.c: 40
0xffffffffacb67320 <timerqueue_add>: push %rbp
0xffffffffacb67321 <timerqueue_add+1>: mov %rsp,%rbp
0xffffffffacb67324 <timerqueue_add+4>: push %r12
0xffffffffacb67326 <timerqueue_add+6>: mov %rdi,%r12
0xffffffffacb67329 <timerqueue_add+9>: push %rbx
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/lib/timerqueue.c: 46
0xffffffffacb6732a <timerqueue_add+10>: cmp (%rsi),%rsi
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/lib/timerqueue.c: 40
0xffffffffacb6732d <timerqueue_add+13>: mov %rsi,%rbx
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/lib/timerqueue.c: 46
0xffffffffacb67330 <timerqueue_add+16>: jne 0xffffffffacb6739e <timerqueue_add+126>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/lib/timerqueue.c: 41
0xffffffffacb67332 <timerqueue_add+18>: mov %r12,%rdx
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/lib/timerqueue.c: 42
0xffffffffacb67335 <timerqueue_add+21>: xor %ecx,%ecx
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/lib/timerqueue.c: 48
0xffffffffacb67337 <timerqueue_add+23>: jmp 0xffffffffacb67357 <timerqueue_add+55>
0xffffffffacb67339 <timerqueue_add+25>: nopl 0x0(%rax)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/lib/timerqueue.c: 52
0xffffffffacb67340 <timerqueue_add+32>: mov 0x18(%rax),%rsi //rax is the p
0xffffffffacb67344 <timerqueue_add+36>: cmp %rsi,0x18(%rbx)
0xffffffffacb67348 <timerqueue_add+40>: lea 0x8(%rax),%rcx
0xffffffffacb6734c <timerqueue_add+44>: lea 0x10(%rax),%rdx
0xffffffffacb67350 <timerqueue_add+48>: cmovge %rcx,%rdx
0xffffffffacb67354 <timerqueue_add+52>: mov %rax,%rcx
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/lib/timerqueue.c: 48
0xffffffffacb67357 <timerqueue_add+55>: mov (%rdx),%rax
0xffffffffacb6735a <timerqueue_add+58>: test %rax,%rax
0xffffffffacb6735d <timerqueue_add+61>: jne 0xffffffffacb67340 <timerqueue_add+32>
Through the disassembly code of the timerqueue_add function, you can see that rdi is the first parameter of the timerqueue_add function (struct timerqueue_head *head),
and rsi is the second parameter of the timerqueue_add function (struct timerqueue_node *node).
We go to parse rdi (ffffffffac8d4395) and rsi(ffff9f9ec0ad3fa0) to get the value of the parameter. The result is as follows.
crash> struct timerqueue_head -ox
struct timerqueue_head {
[0x0] struct rb_root head;
[0x8] struct timerqueue_node *next;
}
SIZE: 0x10
crash> struct timerqueue_head ffffffffac8d4395
struct timerqueue_head {
head = {
rb_node = 0x7401f88348078b48 //the invalid address p
},
next = 0x415541e58948556e
}
>From the above, We can see that the first parameter (struct timerqueue_head *head) passed into the timerqueue_add function is an incorrect address ffffffffac8d4395(rdi).
Let me see the code of the enqueue_hrtimer function and the corresponding part of disassembly code. The result is as follows.
851 static int enqueue_hrtimer(struct hrtimer *timer,
852 struct hrtimer_clock_base *base)
853 {
854 debug_activate(timer);
855
856 timerqueue_add(&base->active, &timer->node);
857 base->cpu_base->active_bases |= 1 << base->index;
858
859 /*
860 * HRTIMER_STATE_ENQUEUED is or'ed to the current state to preserve the
861 * state of a possibly running callback.
862 */
863 timer->state |= HRTIMER_STATE_ENQUEUED;
864
865 return (&timer->node == base->active.next);
866 }
crash> dis -l enqueue_hrtimer
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 853
0xffffffffac8c32d0 <enqueue_hrtimer>: nopl 0x0(%rax,%rax,1) [FTRACE NOP]
0xffffffffac8c32d5 <enqueue_hrtimer+5>: push %rbp
0xffffffffac8c32d6 <enqueue_hrtimer+6>: mov %rsp,%rbp
0xffffffffac8c32d9 <enqueue_hrtimer+9>: push %r13
0xffffffffac8c32db <enqueue_hrtimer+11>: mov %rsi,%r13
0xffffffffac8c32de <enqueue_hrtimer+14>: push %r12
0xffffffffac8c32e0 <enqueue_hrtimer+16>: mov %rdi,%r12
0xffffffffac8c32e3 <enqueue_hrtimer+19>: push %rbx
0xffffffffac8c32e4 <enqueue_hrtimer+20>: nopl 0x0(%rax,%rax,1)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 856
0xffffffffac8c32e9 <enqueue_hrtimer+25>: lea 0x10(%r13),%rdi
0xffffffffac8c32ed <enqueue_hrtimer+29>: mov %r12,%rsi
0xffffffffac8c32f0 <enqueue_hrtimer+32>: callq 0xffffffffacb67320 <timerqueue_add>
As can be seen from the above, r13 is ffffffffac8d4385 (0xffffffffac8d4395-0x10), so the second input parameter struct hrtimer_clock_base *base of the enqueue_hrtimer function is ffffffffac8d4385. r12 is ffff9f9ec0ad3fa0, so the first input parameter of enqueue_hrtimer function struct hrtimer *timer and the second input parameter of timerqueue_add are both ffff9f9ec0ad3fa0.
Then we analyze the first input parameter struct hrtimer *timer of the enqueue_hrtimer function, that is, the second input parameter of timerqueue_add. The result is as follows
crash> struct hrtimer -ox
struct hrtimer {
[0x0] struct timerqueue_node node;
[0x20] ktime_t _softexpires;
[0x28] enum hrtimer_restart (*function)(struct hrtimer *);
[0x30] struct hrtimer_clock_base *base;
[0x38] unsigned long state;
[0x40] int start_pid;
[0x48] void *start_site;
[0x50] char start_comm[16];
}
SIZE: 0x60
crash> struct hrtimer ffff9f9ec0ad3fa0
struct hrtimer {
node = {
node = {
__rb_parent_color = 18446638102919069600, //0xffff9f9ec0ad3fa0
rb_right = 0x0,
rb_left = 0x0
},
expires = {
tv64 = 18114668659000000
}
},
_softexpires = {
tv64 = 18114668659000000
},
function = 0xffffffffac9083f0, //tick_sched_timer function
base = 0xffff9f9ec0ad3a60, //correct struct hrtimer_clock_base
state = 2,
start_pid = 0,
start_site = 0x0,
start_comm = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
}
It can be seen from the above that hrtimer(struct hrtimer ffff9f9ec0ad3fa0) is correct.
At the same time base = 0xffff9f9ec0ad3a60 is the correct struct hrtimer_clock_base, which we will prove below.
Next, we need to reason from top to bottom in accordance with the function call process. The call flow of the function is like this: hrtimer_interrupt -> __hrtimer_run_queues -> __run_hrtimer (optimized by the compiler) -> enqueue_hrtimer ->enqueue_hrtimer
Let's look at the hrtimer_interrupt function first, the following is part of the code of the hrtimer_interrupt function.
void hrtimer_interrupt(struct clock_event_device *dev)
{
struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases);
ktime_t expires_next, now, entry_time, delta;
int retries = 0;
BUG_ON(!cpu_base->hres_active);
cpu_base->nr_events++;
dev->next_event.tv64 = KTIME_MAX;
raw_spin_lock(&cpu_base->lock);
entry_time = now = hrtimer_update_base(cpu_base);
retry:
cpu_base->in_hrtirq = 1;
/*
* We set expires_next to KTIME_MAX here with cpu_base->lock
* held to prevent that a timer is enqueued in our queue via
* the migration code. This does not affect enqueueing of
* timers which run their callback and need to be requeued on
* this CPU.
*/
cpu_base->expires_next.tv64 = KTIME_MAX;
__hrtimer_run_queues(cpu_base, now);
/* Reevaluate the clock bases for the next expiry */
expires_next = __hrtimer_get_next_event(cpu_base);
......
}
We can see that hrtimer_bases is a per_cpu variable, let's parse hrtimer_bases. The result is as follows.
crash> p hrtimer_bases
PER-CPU DATA TYPE:
struct hrtimer_cpu_base hrtimer_bases;
PER-CPU ADDRESSES:
[0]: ffff9f9ec0a13a20
[1]: ffff9f9ec0a53a20
[2]: ffff9f9ec0a93a20
[3]: ffff9f9ec0ad3a20
[4]: ffff9f9ec0b13a20
The problem occurs on cpu3, so for cpu3, the address of struct hrtimer_cpu_base is ffff9f9ec0ad3a20. Let's take a look at the structure of struct hrtimer_cpu_base.
crash> struct hrtimer_cpu_base -ox
struct hrtimer_cpu_base {
[0x0] raw_spinlock_t lock;
[0x4] unsigned int active_bases;
[0x8] unsigned int clock_was_set;
[0x10] ktime_t expires_next;
[0x18] int hres_active;
[0x1c] int hang_detected;
[0x20] unsigned long nr_events;
[0x28] unsigned long nr_retries;
[0x30] unsigned long nr_hangs;
[0x38] ktime_t max_hang_time;
[0x40] struct hrtimer_clock_base clock_base[4];
[0x140] int cpu;
[0x144] int in_hrtirq;
}
You can see that the offset of struct hrtimer_clock_base clock_base[0] in struct hrtimer_cpu_base is 0x40, so the address of struct hrtimer_clock_base clock_base[0] is 0xffff9f9ec0ad3a60 = 0xffff9f9ec0ad3a20 + 0x40.
0xffff9f9ec0ad3a60 is just the struct hrtimer_clock_base *base in the struct hrtimer mentioned above.
struct hrtimer_clock_base clock_base[0] is
crash> struct hrtimer_clock_base 0xffff9f9ec0ad3a60
struct hrtimer_clock_base {
cpu_base = 0xffff9f9ec0ad3a20,
index = 0,
clockid = 1,
active = {
head = {
rb_node = 0xffff9f9e6308fcc8
},
next = 0xffff9f9e5b8af8d8
},
resolution = {
tv64 = 1
},
get_time = 0xffffffffac8ff970,
rh_reserved_softirq_time = {
tv64 = 0
},
offset = {
tv64 = 0
}
}
struct hrtimer_clock_base clock_base[1] is
crash> struct hrtimer_clock_base 0xffff9f9ec0ad3aa0
struct hrtimer_clock_base {
cpu_base = 0xffff9f9ec0ad3a20,
index = 1,
clockid = 0,
active = {
head = {
rb_node = 0x0
},
next = 0x0
},
resolution = {
tv64 = 1
},
get_time = 0xffffffffac8ffdf0,
rh_reserved_softirq_time = {
tv64 = 0
},
offset = {
tv64 = 1596550100169477875
}
}
struct hrtimer_clock_base clock_base[2] is
crash> struct hrtimer_clock_base 0xffff9f9ec0ad3ae0
struct hrtimer_clock_base {
cpu_base = 0xffff9f9ec0ad3a20,
index = 2,
clockid = 7,
active = {
head = {
rb_node = 0x0
},
next = 0x0
},
resolution = {
tv64 = 1
},
get_time = 0xffffffffac8fff70,
rh_reserved_softirq_time = {
tv64 = 0
},
offset = {
tv64 = 0
}
}
struct hrtimer_clock_base clock_base[3] is
crash> struct hrtimer_clock_base 0xffff9f9ec0ad3b20
struct hrtimer_clock_base {
cpu_base = 0xffff9f9ec0ad3a20,
index = 3,
clockid = 11,
active = {
head = {
rb_node = 0x0
},
next = 0x0
},
resolution = {
tv64 = 1
},
get_time = 0xffffffffac8ffc10,
rh_reserved_softirq_time = {
tv64 = 0
},
offset = {
tv64 = 1596550100169477875
}
}
>From the above, we can see that only the first clock_base is valid.
Let us continue to look at the __hrtimer_run_queues function and __run_hrtimer function.
static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now)
{
int i;
for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) {
struct hrtimer_clock_base *base;
struct timerqueue_node *node;
ktime_t basenow;
if (!(cpu_base->active_bases & (1 << i)))
continue;
base = cpu_base->clock_base + i;
basenow = ktime_add(now, base->offset);
while ((node = timerqueue_getnext(&base->active))) {
struct hrtimer *timer;
timer = container_of(node, struct hrtimer, node);
/*
* The immediate goal for using the softexpires is
* minimizing wakeups, not running timers at the
* earliest interrupt after their soft expiration.
* This allows us to avoid using a Priority Search
* Tree, which can answer a stabbing querry for
* overlapping intervals and instead use the simple
* BST we already have.
* We don't add extra wakeups by delaying timers that
* are right-of a not yet expired timer, because that
* timer will have to trigger a wakeup anyway.
*/
if (basenow.tv64 < hrtimer_get_softexpires_tv64(timer))
break;
__run_hrtimer(cpu_base, base, timer, &basenow);
}
}
}
static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base,
struct hrtimer_clock_base *base,
struct hrtimer *timer, ktime_t *now)
{
enum hrtimer_restart (*fn)(struct hrtimer *);
int restart;
WARN_ON(!irqs_disabled());
debug_deactivate(timer);
__remove_hrtimer(timer, base, HRTIMER_STATE_CALLBACK, 0);
fn = timer->function;
/*
* Because we run timers from hardirq context, there is no chance
* they get migrated to another cpu, therefore its safe to unlock
* the timer base.
*/
raw_spin_unlock(&cpu_base->lock);
trace_hrtimer_expire_entry(timer, now);
restart = fn(timer);
trace_hrtimer_expire_exit(timer);
raw_spin_lock(&cpu_base->lock);
/*
* Note: We clear the CALLBACK bit after enqueue_hrtimer and
* we do not reprogramm the event hardware. Happens either in
* hrtimer_start_range_ns() or in hrtimer_interrupt()
*
* Note: Because we dropped the cpu_base->lock above,
* hrtimer_start_range_ns() can have popped in and enqueued the timer
* for us already.
*/
if (restart != HRTIMER_NORESTART &&
!(timer->state & HRTIMER_STATE_ENQUEUED))
enqueue_hrtimer(timer, base);
WARN_ON_ONCE(!(timer->state & HRTIMER_STATE_CALLBACK));
timer->state &= ~HRTIMER_STATE_CALLBACK;
}
In the __hrtimer_run_queues function, you can see that struct hrtimer *timer is obtained by struct hrtimer_clock_base *base. The timer is correct, indicating that the base is correct at this moment. That is, the input parameter base of the __run_hrtimer function is correct, but the base passed in by calling enqueue_hrtimer by __run_hrtimer is wrong. At the same time, there is no code to modify the base in the __run_hrtimer function. This is very strange.
Since the __run_hrtimer function is optimized by the compiler, let's analyze the disassembly code of the __hrtimer_run_queues function. The result is as follows.
crash> dis -l __hrtimer_run_queues
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1216
0xffffffffac8c3b80 <__hrtimer_run_queues>: nopl 0x0(%rax,%rax,1) [FTRACE NOP]
0xffffffffac8c3b85 <__hrtimer_run_queues+5>: push %rbp
0xffffffffac8c3b86 <__hrtimer_run_queues+6>: mov %rsp,%rbp
0xffffffffac8c3b89 <__hrtimer_run_queues+9>: push %r15
0xffffffffac8c3b8b <__hrtimer_run_queues+11>: push %r14
0xffffffffac8c3b8d <__hrtimer_run_queues+13>: push %r13
0xffffffffac8c3b8f <__hrtimer_run_queues+15>: lea 0x40(%rdi),%r13
0xffffffffac8c3b93 <__hrtimer_run_queues+19>: push %r12
0xffffffffac8c3b95 <__hrtimer_run_queues+21>: mov %rdi,%r12
0xffffffffac8c3b98 <__hrtimer_run_queues+24>: push %rbx
0xffffffffac8c3b99 <__hrtimer_run_queues+25>: sub $0x20,%rsp
0xffffffffac8c3b9d <__hrtimer_run_queues+29>: mov %rsi,-0x48(%rbp)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1219
0xffffffffac8c3ba1 <__hrtimer_run_queues+33>: movl $0x0,-0x3c(%rbp)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1216
0xffffffffac8c3ba8 <__hrtimer_run_queues+40>: mov %gs:0x28,%rax
0xffffffffac8c3bb1 <__hrtimer_run_queues+49>: mov %rax,-0x30(%rbp)
0xffffffffac8c3bb5 <__hrtimer_run_queues+53>: xor %eax,%eax
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1224
0xffffffffac8c3bb7 <__hrtimer_run_queues+55>: movzbl -0x3c(%rbp),%ecx
0xffffffffac8c3bbb <__hrtimer_run_queues+59>: mov $0x1,%eax
0xffffffffac8c3bc0 <__hrtimer_run_queues+64>: shl %cl,%eax
0xffffffffac8c3bc2 <__hrtimer_run_queues+66>: test %eax,0x4(%r12)
0xffffffffac8c3bc7 <__hrtimer_run_queues+71>: je 0xffffffffac8c3d30 <__hrtimer_run_queues+432>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1228
0xffffffffac8c3bcd <__hrtimer_run_queues+77>: mov -0x48(%rbp),%rax
0xffffffffac8c3bd1 <__hrtimer_run_queues+81>: add 0x38(%r13),%rax
0xffffffffac8c3bd5 <__hrtimer_run_queues+85>: mov %rax,-0x38(%rbp)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1230
0xffffffffac8c3bd9 <__hrtimer_run_queues+89>: jmp 0xffffffffac8c3bf0 <__hrtimer_run_queues+112>
0xffffffffac8c3bdb <__hrtimer_run_queues+91>: nopl 0x0(%rax,%rax,1)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1210
0xffffffffac8c3be0 <__hrtimer_run_queues+96>: test $0x2,%al
0xffffffffac8c3be2 <__hrtimer_run_queues+98>: je 0xffffffffac8c3d76 <__hrtimer_run_queues+502>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1212
0xffffffffac8c3be8 <__hrtimer_run_queues+104>: and $0xfffffffffffffffd,%rax
0xffffffffac8c3bec <__hrtimer_run_queues+108>: mov %rax,0x38(%rbx)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1230
0xffffffffac8c3bf0 <__hrtimer_run_queues+112>: mov 0x18(%r13),%rbx
0xffffffffac8c3bf4 <__hrtimer_run_queues+116>: test %rbx,%rbx
0xffffffffac8c3bf7 <__hrtimer_run_queues+119>: je 0xffffffffac8c3d30 <__hrtimer_run_queues+432>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1247
0xffffffffac8c3bfd <__hrtimer_run_queues+125>: mov 0x20(%rbx),%rax
0xffffffffac8c3c01 <__hrtimer_run_queues+129>: cmp %rax,-0x38(%rbp)
0xffffffffac8c3c05 <__hrtimer_run_queues+133>: jl 0xffffffffac8c3d30 <__hrtimer_run_queues+432>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/arch/x86/include/asm/paravirt.h: 785
0xffffffffac8c3c0b <__hrtimer_run_queues+139>: pushfq
0xffffffffac8c3c0c <__hrtimer_run_queues+140>: pop %rax
0xffffffffac8c3c0d <__hrtimer_run_queues+141>: nopl 0x0(%rax,%rax,1)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1180
0xffffffffac8c3c12 <__hrtimer_run_queues+146>: test $0x2,%ah
0xffffffffac8c3c15 <__hrtimer_run_queues+149>: jne 0xffffffffac8c3d60 <__hrtimer_run_queues+480>
0xffffffffac8c3c1b <__hrtimer_run_queues+155>: nopl 0x0(%rax,%rax,1)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1183
0xffffffffac8c3c20 <__hrtimer_run_queues+160>: mov %rbx,%rdi
0xffffffffac8c3c23 <__hrtimer_run_queues+163>: xor %ecx,%ecx
0xffffffffac8c3c25 <__hrtimer_run_queues+165>: mov $0x2,%edx
0xffffffffac8c3c2a <__hrtimer_run_queues+170>: mov %r13,%rsi
0xffffffffac8c3c2d <__hrtimer_run_queues+173>: callq 0xffffffffac8c3730 <__remove_hrtimer>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1184
0xffffffffac8c3c32 <__hrtimer_run_queues+178>: mov 0x28(%rbx),%r14
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/arch/x86/include/asm/paravirt.h: 675
0xffffffffac8c3c36 <__hrtimer_run_queues+182>: mov %r12,%rdi
0xffffffffac8c3c39 <__hrtimer_run_queues+185>: movb $0x0,(%rdi)
0xffffffffac8c3c3c <__hrtimer_run_queues+188>: nopl 0x0(%rax)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/include/linux/spinlock_api_smp.h: 154
0xffffffffac8c3c40 <__hrtimer_run_queues+192>: nopl 0x0(%rax,%rax,1)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1193
0xffffffffac8c3c45 <__hrtimer_run_queues+197>: mov %rbx,%rdi
0xffffffffac8c3c48 <__hrtimer_run_queues+200>: callq 0xffffffffacb6d3b0 <__x86_indirect_thunk_r14>
0xffffffffac8c3c4d <__hrtimer_run_queues+205>: mov %eax,%r14d
0xffffffffac8c3c50 <__hrtimer_run_queues+208>: nopl 0x0(%rax,%rax,1)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1195
0xffffffffac8c3c55 <__hrtimer_run_queues+213>: mov %r12,%rdi
0xffffffffac8c3c58 <__hrtimer_run_queues+216>: callq 0xffffffffacf303e0 <_raw_qspin_lock>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1206
0xffffffffac8c3c5d <__hrtimer_run_queues+221>: test %r14d,%r14d
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1207
0xffffffffac8c3c60 <__hrtimer_run_queues+224>: mov 0x38(%rbx),%rax
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1206
0xffffffffac8c3c64 <__hrtimer_run_queues+228>: je 0xffffffffac8c3be0 <__hrtimer_run_queues+96>
0xffffffffac8c3c6a <__hrtimer_run_queues+234>: test $0x1,%al
0xffffffffac8c3c6c <__hrtimer_run_queues+236>: jne 0xffffffffac8c3be0 <__hrtimer_run_queues+96>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1208
0xffffffffac8c3c72 <__hrtimer_run_queues+242>: mov %r13,%rsi
0xffffffffac8c3c75 <__hrtimer_run_queues+245>: mov %rbx,%rdi
0xffffffffac8c3c78 <__hrtimer_run_queues+248>: callq 0xffffffffac8c32d0 <enqueue_hrtimer>
0xffffffffac8c3c7d <__hrtimer_run_queues+253>: mov 0x38(%rbx),%rax
0xffffffffac8c3c81 <__hrtimer_run_queues+257>: jmpq 0xffffffffac8c3be0 <__hrtimer_run_queues+96>
0xffffffffac8c3c86 <__hrtimer_run_queues+262>: nopw %cs:0x0(%rax,%rax,1)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/include/trace/events/timer.h: 242
0xffffffffac8c3c90 <__hrtimer_run_queues+272>: mov 0xc54c59(%rip),%r15 # 0xffffffffad5188f0
0xffffffffac8c3c97 <__hrtimer_run_queues+279>: test %r15,%r15
0xffffffffac8c3c9a <__hrtimer_run_queues+282>: je 0xffffffffac8c3cb8 <__hrtimer_run_queues+312>
0xffffffffac8c3c9c <__hrtimer_run_queues+284>: mov (%r15),%rdx
0xffffffffac8c3c9f <__hrtimer_run_queues+287>: nop
0xffffffffac8c3ca0 <__hrtimer_run_queues+288>: mov 0x8(%r15),%rdi
0xffffffffac8c3ca4 <__hrtimer_run_queues+292>: add $0x10,%r15
0xffffffffac8c3ca8 <__hrtimer_run_queues+296>: mov %rbx,%rsi
0xffffffffac8c3cab <__hrtimer_run_queues+299>: callq 0xffffffffacb6d270 <__x86_indirect_thunk_rdx>
0xffffffffac8c3cb0 <__hrtimer_run_queues+304>: mov (%r15),%rdx
0xffffffffac8c3cb3 <__hrtimer_run_queues+307>: test %rdx,%rdx
0xffffffffac8c3cb6 <__hrtimer_run_queues+310>: jne 0xffffffffac8c3ca0 <__hrtimer_run_queues+288>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/include/linux/rcupdate.h: 952
0xffffffffac8c3cb8 <__hrtimer_run_queues+312>: jmp 0xffffffffac8c3c55 <__hrtimer_run_queues+213>
0xffffffffac8c3cba <__hrtimer_run_queues+314>: nopw 0x0(%rax,%rax,1)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/include/trace/events/timer.h: 196
0xffffffffac8c3cc0 <__hrtimer_run_queues+320>: mov 0xc54c69(%rip),%r15 # 0xffffffffad518930
0xffffffffac8c3cc7 <__hrtimer_run_queues+327>: test %r15,%r15
0xffffffffac8c3cca <__hrtimer_run_queues+330>: je 0xffffffffac8c3cec <__hrtimer_run_queues+364>
0xffffffffac8c3ccc <__hrtimer_run_queues+332>: mov (%r15),%rcx
0xffffffffac8c3ccf <__hrtimer_run_queues+335>: nop
0xffffffffac8c3cd0 <__hrtimer_run_queues+336>: mov 0x8(%r15),%rdi
0xffffffffac8c3cd4 <__hrtimer_run_queues+340>: add $0x10,%r15
0xffffffffac8c3cd8 <__hrtimer_run_queues+344>: lea -0x38(%rbp),%rdx
0xffffffffac8c3cdc <__hrtimer_run_queues+348>: mov %rbx,%rsi
0xffffffffac8c3cdf <__hrtimer_run_queues+351>: callq 0xffffffffacb6d250 <__x86_indirect_thunk_rcx>
0xffffffffac8c3ce4 <__hrtimer_run_queues+356>: mov (%r15),%rcx
0xffffffffac8c3ce7 <__hrtimer_run_queues+359>: test %rcx,%rcx
0xffffffffac8c3cea <__hrtimer_run_queues+362>: jne 0xffffffffac8c3cd0 <__hrtimer_run_queues+336>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/include/linux/rcupdate.h: 952
0xffffffffac8c3cec <__hrtimer_run_queues+364>: jmpq 0xffffffffac8c3c45 <__hrtimer_run_queues+197>
0xffffffffac8c3cf1 <__hrtimer_run_queues+369>: nopl 0x0(%rax)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/include/trace/events/timer.h: 253
0xffffffffac8c3cf8 <__hrtimer_run_queues+376>: mov 0xc54bb1(%rip),%r14 # 0xffffffffad5188b0
0xffffffffac8c3cff <__hrtimer_run_queues+383>: test %r14,%r14
0xffffffffac8c3d02 <__hrtimer_run_queues+386>: je 0xffffffffac8c3d28 <__hrtimer_run_queues+424>
0xffffffffac8c3d04 <__hrtimer_run_queues+388>: mov (%r14),%rax
0xffffffffac8c3d07 <__hrtimer_run_queues+391>: nopw 0x0(%rax,%rax,1)
0xffffffffac8c3d10 <__hrtimer_run_queues+400>: mov 0x8(%r14),%rdi
0xffffffffac8c3d14 <__hrtimer_run_queues+404>: add $0x10,%r14
0xffffffffac8c3d18 <__hrtimer_run_queues+408>: mov %rbx,%rsi
0xffffffffac8c3d1b <__hrtimer_run_queues+411>: callq 0xffffffffacb6d210 <__x86_indirect_thunk_rax>
0xffffffffac8c3d20 <__hrtimer_run_queues+416>: mov (%r14),%rax
0xffffffffac8c3d23 <__hrtimer_run_queues+419>: test %rax,%rax
0xffffffffac8c3d26 <__hrtimer_run_queues+422>: jne 0xffffffffac8c3d10 <__hrtimer_run_queues+400>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/include/linux/rcupdate.h: 952
0xffffffffac8c3d28 <__hrtimer_run_queues+424>: jmpq 0xffffffffac8c3c20 <__hrtimer_run_queues+160>
0xffffffffac8c3d2d <__hrtimer_run_queues+429>: nopl (%rax)
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1219
0xffffffffac8c3d30 <__hrtimer_run_queues+432>: addl $0x1,-0x3c(%rbp)
0xffffffffac8c3d34 <__hrtimer_run_queues+436>: add $0x40,%r13
0xffffffffac8c3d38 <__hrtimer_run_queues+440>: cmpl $0x4,-0x3c(%rbp)
0xffffffffac8c3d3c <__hrtimer_run_queues+444>: jne 0xffffffffac8c3bb7 <__hrtimer_run_queues+55>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1253
0xffffffffac8c3d42 <__hrtimer_run_queues+450>: mov -0x30(%rbp),%rax
0xffffffffac8c3d46 <__hrtimer_run_queues+454>: xor %gs:0x28,%rax
0xffffffffac8c3d4f <__hrtimer_run_queues+463>: jne 0xffffffffac8c3da4 <__hrtimer_run_queues+548>
0xffffffffac8c3d51 <__hrtimer_run_queues+465>: add $0x20,%rsp
0xffffffffac8c3d55 <__hrtimer_run_queues+469>: pop %rbx
0xffffffffac8c3d56 <__hrtimer_run_queues+470>: pop %r12
0xffffffffac8c3d58 <__hrtimer_run_queues+472>: pop %r13
0xffffffffac8c3d5a <__hrtimer_run_queues+474>: pop %r14
0xffffffffac8c3d5c <__hrtimer_run_queues+476>: pop %r15
0xffffffffac8c3d5e <__hrtimer_run_queues+478>: pop %rbp
0xffffffffac8c3d5f <__hrtimer_run_queues+479>: retq
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1180
0xffffffffac8c3d60 <__hrtimer_run_queues+480>: mov $0x49c,%esi
0xffffffffac8c3d65 <__hrtimer_run_queues+485>: mov $0xffffffffad270f96,%rdi
0xffffffffac8c3d6c <__hrtimer_run_queues+492>: callq 0xffffffffac896070 <warn_slowpath_null>
0xffffffffac8c3d71 <__hrtimer_run_queues+497>: jmpq 0xffffffffac8c3c1b <__hrtimer_run_queues+155>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1210
0xffffffffac8c3d76 <__hrtimer_run_queues+502>: cmpb $0x0,0xc534a7(%rip) # 0xffffffffad517224
0xffffffffac8c3d7d <__hrtimer_run_queues+509>: jne 0xffffffffac8c3be8 <__hrtimer_run_queues+104>
0xffffffffac8c3d83 <__hrtimer_run_queues+515>: mov $0x4ba,%esi
0xffffffffac8c3d88 <__hrtimer_run_queues+520>: mov $0xffffffffad270f96,%rdi
0xffffffffac8c3d8f <__hrtimer_run_queues+527>: callq 0xffffffffac896070 <warn_slowpath_null>
0xffffffffac8c3d94 <__hrtimer_run_queues+532>: movb $0x1,0xc53489(%rip) # 0xffffffffad517224
0xffffffffac8c3d9b <__hrtimer_run_queues+539>: mov 0x38(%rbx),%rax
0xffffffffac8c3d9f <__hrtimer_run_queues+543>: jmpq 0xffffffffac8c3be8 <__hrtimer_run_queues+104>
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/hrtimer.c: 1253
0xffffffffac8c3da4 <__hrtimer_run_queues+548>: callq 0xffffffffac895ca0 <__stack_chk_fail>
0xffffffffac8c3da9 <__hrtimer_run_queues+553>: nopl 0x0(%rax)
We can see that in the line 0xffffffffac8c3b8f <__hrtimer_run_queues+15>: lea 0x40(%rdi),%r13, the value of base is put into r13.
In the 0xffffffffac8c3c72 <__hrtimer_run_queues+242>: mov %r13,%rsi line before calling the enqueue_hrtimer function, the value of base is copied from the r13 register to the rsi register.
The r13 register is not modified elsewhere. Therefore, we suspect that the stack may be destroyed during the call to the __remove_hrtimer function or the fn=tick_sched_timer function, resulting in that when the function returns, the value of the r13 register
The value is overwritten with the wrong value ffffffffac8d4385. Currently we have no evidence to prove.
Two phenomena can indirectly prove the above suspicion.
First, ffffffffac8d4385 is the address of a function, let's parse it. The results are as follows.
crash> dis -l ffffffffac8d4385
/usr/src/debug/kernel-3.10.0/linux-3.10.0-862.14.1.6_110.x86_64/kernel/sched/core.c: 1934
0xffffffffac8d4385 <wake_up_process+21>: pop %rbp
1931 int wake_up_process(struct task_struct *p)
1932 {
1933 return try_to_wake_up(p, TASK_NORMAL, 0);
1934 }
Second, we looked at the function stack. The result is as follows, you can see ffffffffac8d4385 on the stack, In the line ffff9f9ec0ac3f10.
crash> bt -c 3 -f
PID: 27797 TASK: ffff9f9e28805f40 CPU: 3 COMMAND: "ipmi_sim"
#0 [ffff9f9ec0ac3dd0] die at ffffffffac82f97b
ffff9f9ec0ac3dd8: ffff9f708e673f80 ffff9f9ec0ac3e38
ffff9f9ec0ac3de8: 0000000000000000 0000000000000000
ffff9f9ec0ac3df8: ffff9f9ec0ac3e28 ffffffffacf3211e
#1 [ffff9f9ec0ac3e00] do_general_protection at ffffffffacf3211e
ffff9f9ec0ac3e08: 0000000000000001 ffffffffac8d4395
ffff9f9ec0ac3e18: ffffffffac8d4385 0000000000000001
ffff9f9ec0ac3e28: ffff9f9ec0ac3ef0 ffffffffacf31718
#2 [ffff9f9ec0ac3e30] general_protection at ffffffffacf31718
[exception RIP: timerqueue_add+32]
RIP: ffffffffacb67340 RSP: ffff9f9ec0ac3ee0 RFLAGS: 00010006
RAX: 7401f88348078b48 RBX: ffff9f9ec0ad3fa0 RCX: 0000000000000000
RDX: ffffffffac8d4395 RSI: ffff9f9ec0ad3fa0 RDI: ffffffffac8d4395
RBP: ffff9f9ec0ac3ef0 R8: 00405b31f6958080 R9: ffff9f9ec0ac3de0
R10: 0000000000000002 R11: ffff9f9ec0ac3de8 R12: ffffffffac8d4395
R13: ffffffffac8d4385 R14: 0000000000000001 R15: ffff9f9ec0ad3b58
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
ffff9f9ec0ac3e38: ffff9f9ec0ad3b58 0000000000000001
ffff9f9ec0ac3e48: ffffffffac8d4385 ffffffffac8d4395
ffff9f9ec0ac3e58: ffff9f9ec0ac3ef0 ffff9f9ec0ad3fa0
ffff9f9ec0ac3e68: ffff9f9ec0ac3de8 0000000000000002
ffff9f9ec0ac3e78: ffff9f9ec0ac3de0 00405b31f6958080
ffff9f9ec0ac3e88: 7401f88348078b48 0000000000000000
ffff9f9ec0ac3e98: ffffffffac8d4395 ffff9f9ec0ad3fa0
ffff9f9ec0ac3ea8: ffffffffac8d4395 ffffffffffffffff
ffff9f9ec0ac3eb8: ffffffffacb67340 0000000000000010
ffff9f9ec0ac3ec8: 0000000000010006 ffff9f9ec0ac3ee0
ffff9f9ec0ac3ed8: 0000000000000018 ffff9f9ec0ad3fa0
ffff9f9ec0ac3ee8: ffff9f9ec0ad3fa0 ffff9f9ec0ac3f18
ffff9f9ec0ac3ef8: ffffffffac8c32f5
#3 [ffff9f9ec0ac3ef8] enqueue_hrtimer at ffffffffac8c32f5
ffff9f9ec0ac3f00: ffff9f9ec0ad3fa0 ffff9f9ec0ad3a20
ffff9f9ec0ac3f10: ffffffffac8d4385 ffff9f9ec0ac3f70
ffff9f9ec0ac3f20: ffffffffac8c3c7d
#4 [ffff9f9ec0ac3f20] __hrtimer_run_queues at ffffffffac8c3c7d
ffff9f9ec0ac3f28: 00405b31f695867a 00000000c0ad3b58
ffff9f9ec0ac3f38: 00405b31f695867a f8fbe5c575ba6923
ffff9f9ec0ac3f48: 0000000000000003 ffff9f9ec0ad3a20
ffff9f9ec0ac3f58: ffff9f9ec0ad3ad8 ffff9f9ec0ad3a60
ffff9f9ec0ac3f68: ffff9f9ec0ad3b58 ffff9f9ec0ac3fb8
ffff9f9ec0ac3f78: ffffffffac8c41af
#5 [ffff9f9ec0ac3f78] hrtimer_interrupt at ffffffffac8c41af
ffff9f9ec0ac3f80: 00405b31f695867a ffff9f9ec0ad3a28
ffff9f9ec0ac3f90: ffff9f9ec0ad1200 0000000000000003
ffff9f9ec0ac3fa0: ffff9f708e690000 ffff9f708e690000
ffff9f9ec0ac3fb0: ffff9f708e690000 ffff9f9ec0ac3fd0
ffff9f9ec0ac3fc0: ffffffffac85aeeb
#6 [ffff9f9ec0ac3fc0] local_apic_timer_interrupt at ffffffffac85aeeb
ffff9f9ec0ac3fc8: 0000000000000000 ffff9f9ec0ac3fe8
ffff9f9ec0ac3fd8: ffffffffacf3f0a3
#7 [ffff9f9ec0ac3fd8] smp_apic_timer_interrupt at ffffffffacf3f0a3
ffff9f9ec0ac3fe0: ffffffffad543a20 ffff9f708e693ea8
ffff9f9ec0ac3ff0: ffffffffacf3b7ba
#8 [ffff9f9ec0ac3ff0] apic_timer_interrupt at ffffffffacf3b7ba
--- <IRQ stack> ---
bt: cannot transition from IRQ stack to current process stack:
IRQ stack pointer: ffff9f9ec0ac3dd0
process stack pointer: ffff9f708e693df8
current stack base: ffff9f9e25764000
Has anyone encountered a similar problem? Hope to get your help.
--wangjian
Powered by blists - more mailing lists