timers: Use proper base migration in add_timer_on()
Orabug
25079989 hit timer race condition which is fixed by upstream
commit
22b886dd (timers: Use proper base migration in add_timer_on()).
Commit
22b886dd is base on v4.4 code whose definition of timer_list
is different from uek4.
It'll have to modify the timer_list struct if backport it directly
with all his base commits. That's a big changeset and there will be
kABI check issue.
So this patch implements same logic (which is used in __mod_timer()
for the same race condition as well) as
22b886dd and works with uek4
timer_list struct.
Following is the description of commit
22b886dd:
timers: Use proper base migration in add_timer_on()
Regardless of the previous CPU a timer was on, add_timer_on()
currently simply sets timer->flags to the new CPU. As the caller must
be seeing the timer as idle, this is locally fine, but the timer
leaving the old base while unlocked can lead to race conditions as
follows.
Let's say timer was on cpu 0.
cpu 0 cpu 1
-----------------------------------------------------------------------------
del_timer(timer) succeeds
del_timer(timer)
lock_timer_base(timer) locks cpu_0_base
add_timer_on(timer, 1)
spin_lock(&cpu_1_base->lock)
timer->flags set to cpu_1_base
operates on @timer operates on @timer
This triggered with mod_delayed_work_on() which contains
"if (del_timer()) add_timer_on()" sequence eventually leading to the
following oops.
BUG: unable to handle kernel NULL pointer dereference at (null)
IP: [<
ffffffff810ca6e9>] detach_if_pending+0x69/0x1a0
...
Workqueue: wqthrash wqthrash_workfunc [wqthrash]
task:
ffff8800172ca680 ti:
ffff8800172d0000 task.ti:
ffff8800172d0000
RIP: 0010:[<
ffffffff810ca6e9>] [<
ffffffff810ca6e9>] detach_if_pending+0x69/0x1a0
...
Call Trace:
[<
ffffffff810cb0b4>] del_timer+0x44/0x60
[<
ffffffff8106e836>] try_to_grab_pending+0xb6/0x160
[<
ffffffff8106e913>] mod_delayed_work_on+0x33/0x80
[<
ffffffffa0000081>] wqthrash_workfunc+0x61/0x90 [wqthrash]
[<
ffffffff8106dba8>] process_one_work+0x1e8/0x650
[<
ffffffff8106e05e>] worker_thread+0x4e/0x450
[<
ffffffff810746af>] kthread+0xef/0x110
[<
ffffffff8185980f>] ret_from_fork+0x3f/0x70
Fix it by updating add_timer_on() to perform proper migration as
__mod_timer() does.
Orabug:
25079989
Signed-off-by: Honglei Wang <honglei.wang@oracle.com>
Acked-by: Joe Jin <joe.jin@oracle.com>