> But more importantly, I think utrace_reap() never needs to synchronize > with utrace_barrier(). Once we drop utrace->lock, any other caller which > takes this lock must see both ->exit_state and utrace->reap. This means > utrace_control() or utrace_set_events() which sets/clears REAP must not > succeed.
Right. So this doesn't matter for the primary original purpose of utrace_barrier, i.e.: * A successful return from utrace_barrier() guarantees its ordering * with respect to utrace_set_events() and utrace_control() calls. But IMHO it would be nice (and the least surprising thing) if this statement were really true too: * A return value of zero means no callback from @target to @engine was * in progress. Since commit ac6e19c (my equivalent to your 3/4), utrace_barrier will no longer return -ESRCH while your report_reap callback might be running. I think its doing so before was not really ideal, because it still gave no positive indication that the callback *couldn't* still be running, which is what a caller of utrace_barrier is really there for. It seems best to me that utrace_barrier block while the engine's report_reap callback could be running, just like for all other callbacks. Then a 0 return means unequivocally that no callback is in progress, and so does an -ESRCH return. So maybe we want this? I'm not really sure about the barriers, maybe we don't need both or any at all. My thinking about that is just to keep uniform across all callbacks what kind of guarantees the caller of utrace_barrier has about the ordering of any effects its report_reap callback can have. Other callbacks always have an smp_mb() between setting ->reporting and calling the engine's code. Thanks, Roland diff --git a/kernel/utrace.c b/kernel/utrace.c index 6036764..3bec3be 100644 --- a/kernel/utrace.c +++ b/kernel/utrace.c @@ -426,8 +426,19 @@ static void utrace_reap(struct task_stru spin_unlock(&utrace->lock); list_for_each_entry_safe(engine, next, &utrace->attached, entry) { - if (engine->flags & UTRACE_EVENT(REAP)) + if (engine->flags & UTRACE_EVENT(REAP)) { + /* + * These barriers order anything ->report_reap() + * does to be while ->reporting is set. That way + * any utrace_barrier() call that returns 0 is + * guaranteeing that the callback is complete. + */ + utrace->reporting = engine; + smp_mb(); engine->ops->report_reap(engine, target); + smp_mb(); + utrace->reporting = NULL; + } engine->ops = NULL; engine->flags = 0;