The whole premise is broken, any trace usage outside of RCU is a BUG and should be fixed. Notable all code prior (and a fair bit after) ct_user_exit() is noinstr and explicitly doesn't allow any tracing. Use regular RCU, which has the benefit of actually respecting NOHZ_FULL. Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx> --- kernel/livepatch/transition.c | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) --- a/kernel/livepatch/transition.c +++ b/kernel/livepatch/transition.c @@ -42,28 +42,6 @@ static void klp_transition_work_fn(struc static DECLARE_DELAYED_WORK(klp_transition_work, klp_transition_work_fn); /* - * This function is just a stub to implement a hard force - * of synchronize_rcu(). This requires synchronizing - * tasks even in userspace and idle. - */ -static void klp_sync(struct work_struct *work) -{ -} - -/* - * We allow to patch also functions where RCU is not watching, - * e.g. before ct_user_exit(). We can not rely on the RCU infrastructure - * to do the synchronization. Instead hard force the sched synchronization. - * - * This approach allows to use RCU functions for manipulating func_stack - * safely. - */ -static void klp_synchronize_transition(void) -{ - schedule_on_each_cpu(klp_sync); -} - -/* * The transition to the target patch state is complete. Clean up the data * structures. */ @@ -96,7 +74,7 @@ static void klp_complete_transition(void * func->transition gets cleared, the handler may choose a * removed function. */ - klp_synchronize_transition(); + synchronize_rcu(); } klp_for_each_object(klp_transition_patch, obj) @@ -105,7 +83,7 @@ static void klp_complete_transition(void /* Prevent klp_ftrace_handler() from seeing KLP_UNDEFINED state */ if (klp_target_state == KLP_PATCHED) - klp_synchronize_transition(); + synchronize_rcu(); read_lock(&tasklist_lock); for_each_process_thread(g, task) { @@ -168,10 +146,6 @@ noinstr void __klp_update_patch_state(st */ void klp_update_patch_state(struct task_struct *task) { - /* - * A variant of synchronize_rcu() is used to allow patching functions - * where RCU is not watching, see klp_synchronize_transition(). - */ preempt_disable_notrace(); /* @@ -626,7 +600,7 @@ void klp_reverse_transition(void) clear_tsk_thread_flag(idle_task(cpu), TIF_PATCH_PENDING); /* Let any remaining calls to klp_update_patch_state() complete */ - klp_synchronize_transition(); + synchronize_rcu(); klp_start_transition(); }