Re: [PATCH v4] kernel/fork: beware of __put_task_struct calling context

From: Sebastian Andrzej Siewior
Date: Mon Feb 06 2023 - 09:57:03 EST


On 2023-02-06 10:04:47 [-0300], Wander Lairson Costa wrote:
> Under PREEMPT_RT, __put_task_struct() indirectly acquires sleeping
> locks. Therefore, it can't be called from an non-preemptible context.
>
> One practical example is splat inside inactive_task_timer(), which is
> called in a interrupt context:

Do you have more?
The inactive_task_timer() is marked as HRTIMER_MODE_REL_HARD which means
in runs in hardirq-context. The author of commit
850377a875a48 ("sched/deadline: Ensure inactive_timer runs in hardirq context")

should have been aware of that.
We have on workaround of that put_task() in sched-switch. I wasn't aware
of this shortcoming. So either we have more problems or potential
problems or this is the only finding so far.

> diff --git a/kernel/fork.c b/kernel/fork.c
> index 9f7fe3541897..532dd2ceb6a3 100644
> --- a/kernel/fork.c
> +++ b/kernel/fork.c
> @@ -857,6 +857,29 @@ void __put_task_struct(struct task_struct *tsk)

> +void __put_task_struct(struct task_struct *tsk)
> +{
> + if (IS_ENABLED(CONFIG_PREEMPT_RT) && (!preemptible() || !in_task()))

Is it safe to use the rcu member in any case? If so why not use it
unconditionally?

> + /*
> + * under PREEMPT_RT, we can't call put_task_struct
> + * in atomic context because it will indirectly
> + * acquire sleeping locks.
> + *
> + * call_rcu() will schedule delayed_put_task_struct_rcu()
> + * to be called in process context.
> + */
> + call_rcu(&tsk->rcu, delayed_put_task_struct_rcu);
> + else
> + ___put_task_struct(tsk);
> +}
> EXPORT_SYMBOL_GPL(__put_task_struct);
>
> void __init __weak arch_task_cache_init(void) { }

Sebastian