Skip to content

Commit 8f91efd

Browse files
Zhaoyang HuangPeter Zijlstra
authored andcommitted
psi: Fix race between psi_trigger_create/destroy
Race detected between psi_trigger_destroy/create as shown below, which cause panic by accessing invalid psi_system->poll_wait->wait_queue_entry and psi_system->poll_timer->entry->next. Under this modification, the race window is removed by initialising poll_wait and poll_timer in group_init which are executed only once at beginning. psi_trigger_destroy() psi_trigger_create() mutex_lock(trigger_lock); rcu_assign_pointer(poll_task, NULL); mutex_unlock(trigger_lock); mutex_lock(trigger_lock); if (!rcu_access_pointer(group->poll_task)) { timer_setup(poll_timer, poll_timer_fn, 0); rcu_assign_pointer(poll_task, task); } mutex_unlock(trigger_lock); synchronize_rcu(); del_timer_sync(poll_timer); <-- poll_timer has been reinitialized by psi_trigger_create() So, trigger_lock/RCU correctly protects destruction of group->poll_task but misses this race affecting poll_timer and poll_wait. Fixes: 461daba ("psi: eliminate kthread_worker from psi trigger scheduling mechanism") Co-developed-by: ziwei.dai <[email protected]> Signed-off-by: ziwei.dai <[email protected]> Co-developed-by: ke.wang <[email protected]> Signed-off-by: ke.wang <[email protected]> Signed-off-by: Zhaoyang Huang <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Reviewed-by: Suren Baghdasaryan <[email protected]> Acked-by: Johannes Weiner <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent f418371 commit 8f91efd

File tree

1 file changed

+6
-6
lines changed

1 file changed

+6
-6
lines changed

kernel/sched/psi.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ struct psi_group psi_system = {
182182

183183
static void psi_avgs_work(struct work_struct *work);
184184

185+
static void poll_timer_fn(struct timer_list *t);
186+
185187
static void group_init(struct psi_group *group)
186188
{
187189
int cpu;
@@ -201,6 +203,8 @@ static void group_init(struct psi_group *group)
201203
memset(group->polling_total, 0, sizeof(group->polling_total));
202204
group->polling_next_update = ULLONG_MAX;
203205
group->polling_until = 0;
206+
init_waitqueue_head(&group->poll_wait);
207+
timer_setup(&group->poll_timer, poll_timer_fn, 0);
204208
rcu_assign_pointer(group->poll_task, NULL);
205209
}
206210

@@ -1157,9 +1161,7 @@ struct psi_trigger *psi_trigger_create(struct psi_group *group,
11571161
return ERR_CAST(task);
11581162
}
11591163
atomic_set(&group->poll_wakeup, 0);
1160-
init_waitqueue_head(&group->poll_wait);
11611164
wake_up_process(task);
1162-
timer_setup(&group->poll_timer, poll_timer_fn, 0);
11631165
rcu_assign_pointer(group->poll_task, task);
11641166
}
11651167

@@ -1211,6 +1213,7 @@ static void psi_trigger_destroy(struct kref *ref)
12111213
group->poll_task,
12121214
lockdep_is_held(&group->trigger_lock));
12131215
rcu_assign_pointer(group->poll_task, NULL);
1216+
del_timer(&group->poll_timer);
12141217
}
12151218
}
12161219

@@ -1223,17 +1226,14 @@ static void psi_trigger_destroy(struct kref *ref)
12231226
*/
12241227
synchronize_rcu();
12251228
/*
1226-
* Destroy the kworker after releasing trigger_lock to prevent a
1229+
* Stop kthread 'psimon' after releasing trigger_lock to prevent a
12271230
* deadlock while waiting for psi_poll_work to acquire trigger_lock
12281231
*/
12291232
if (task_to_destroy) {
12301233
/*
12311234
* After the RCU grace period has expired, the worker
12321235
* can no longer be found through group->poll_task.
1233-
* But it might have been already scheduled before
1234-
* that - deschedule it cleanly before destroying it.
12351236
*/
1236-
del_timer_sync(&group->poll_timer);
12371237
kthread_stop(task_to_destroy);
12381238
}
12391239
kfree(t);

0 commit comments

Comments
 (0)