[PATCH] utrace: utrace_attach_task() forgets to return when ->utrace == NULL
Oleg Nesterov
oleg at redhat.com
Mon Nov 16 23:21:49 UTC 2009
On 11/16, Roland McGrath wrote:
>
> > But read_barrier_depends() does nothig except on alpha, why should we
> > care?
>
> I thought this was the barrier you were talking about. Anyway, we should
> be pedantically correct about these. (People do even still build Linux/Alpha.)
Yes, sure. I meant, we shouldn't worry that this barrier adds too much
overhead to task_utrace_struct().
> > This reminds me, utrace_interrupt_pending() and similar code needs rmb()
> > or task->utrace != NULL check.
>
> I take it you mean that:
>
> if (task->utrace_flags)
> ... use task->utrace ...
>
> paths need a barrier to ensure task->utrace_flags read nonzero implies
> task->utrace will be read non-null when racing with the first attach.
> Right?
Yes,
> This only needs smp_rmb(), right?
I think yes.
> Is there an existing explicit barrier
> this pairs with? The corresponding smp_wmb() needs to be somewhere between
> utrace_task_alloc()'s "task->utrace = utrace;" and utrace_add_engine():
>
> if (!target->utrace_flags) {
> target->utrace_flags = UTRACE_EVENT(REAP);
We don't have the explicit barrier, but I think it is not needed.
In this case utrace_attach_task() does unlock+lock at least once
before changing ->utrace_flags, this implies mb().
> static inline struct utrace *task_utrace_struct(struct task_struct *task)
> {
> - struct utrace *utrace = task->utrace;
> + struct utrace *utrace;
> +
> + /*
> + * This barrier ensures that any prior load of task->utrace_flags
> + * is ordered before this load of task->utrace. We use those
> + * utrace_flags checks in the hot path to decide to call into
> + * the utrace code. The first attach installs task->utrace before
> + * setting task->utrace_flags nonzero, with a barrier between.
> + */
> + smp_rmb();
> + utrace = task->utrace;
> +
> read_barrier_depends(); /* See utrace_task_alloc(). */
> return utrace;
> }
Yes, I think this patch should close this (pure theoretical) problem.
But this smp_rmb() in task_utrace_struct() is only needed when the
caller does something like
if (task_utrace_flags(tsk))
do_something(task_utrace_struct());
it would be more logical to move this rmb() info task_utrace_flags().
However task_utrace_flags() must be fast.
Perhaps, to avoid this smp_rmb(), we can change
bool utrace_interrupt_pending(void)
{
struct utrace *utrace = task_utrace_struct(current);
return utrace && utrace->resume == UTRACE_INTERRUPT;
}
I dunno.
Oleg.
More information about the utrace-devel
mailing list