I still need to review (and understand ;) the ->reporting logic/barriers and continue the related discussion.
But can't we move ->reporting from utrace to engine? This saves a word in task_struct. Yes, this adds the same word to engine, but we should optimize the common untraced case. Or do you have other plans for utrace->reporting? Signed-off-by: Oleg Nesterov <o...@redhat.com> --- include/linux/utrace_struct.h | 2 -- include/linux/utrace.h | 1 + kernel/utrace.c | 38 +++++++++++++++++++------------------- 3 files changed, 20 insertions(+), 21 deletions(-) --- __UTRACE/include/linux/utrace_struct.h~1_MV_REPORTING 2009-09-08 18:15:38.000000000 +0200 +++ __UTRACE/include/linux/utrace_struct.h 2009-09-12 02:07:30.000000000 +0200 @@ -30,8 +30,6 @@ struct utrace { struct list_head attached, attaching; spinlock_t lock; - struct utrace_engine *reporting; - unsigned int stopped:1; unsigned int report:1; unsigned int interrupt:1; --- __UTRACE/include/linux/utrace.h~1_MV_REPORTING 2009-09-12 02:02:45.000000000 +0200 +++ __UTRACE/include/linux/utrace.h 2009-09-12 02:09:37.000000000 +0200 @@ -327,6 +327,7 @@ struct utrace_engine { /* public: */ const struct utrace_engine_ops *ops; + bool reporting; void *data; unsigned long flags; --- __UTRACE/kernel/utrace.c~1_MV_REPORTING 2009-09-12 02:03:21.000000000 +0200 +++ __UTRACE/kernel/utrace.c 2009-09-12 02:24:27.000000000 +0200 @@ -584,14 +584,14 @@ int utrace_set_events(struct task_struct if (!utrace->stopped && target != current && !target->exit_state) { /* * This barrier ensures that our engine->flags changes - * have hit before we examine utrace->reporting, + * have hit before we examine engine->reporting, * pairing with the barrier in start_callback(). If * @target has not yet hit finish_callback() to clear - * utrace->reporting, we might be in the middle of a + * engine->reporting, we might be in the middle of a * callback to @engine. */ smp_mb(); - if (utrace->reporting == engine) + if (engine->reporting) ret = -EINPROGRESS; } @@ -1065,13 +1065,13 @@ int utrace_control(struct task_struct *t /* * As in utrace_set_events(), this barrier ensures * that our engine->flags changes have hit before we - * examine utrace->reporting, pairing with the barrier + * examine engine->reporting, pairing with the barrier * in start_callback(). If @target has not yet hit - * finish_callback() to clear utrace->reporting, we + * finish_callback() to clear engine->reporting, we * might be in the middle of a callback to @engine. */ smp_mb(); - if (utrace->reporting == engine) + if (engine->reporting) ret = -EINPROGRESS; } break; @@ -1228,12 +1228,12 @@ int utrace_barrier(struct task_struct *t * worry about @target making a callback. * When it has entered start_callback() but * not yet gotten to finish_callback(), we - * will see utrace->reporting == @engine. + * will see @engine->reporting == true. * When @target doesn't take the lock, it uses - * barriers to order setting utrace->reporting + * barriers to order setting engine->reporting * before it examines the engine state. */ - if (utrace->reporting != engine) + if (!engine->reporting) ret = 0; spin_unlock(&utrace->lock); if (!ret) @@ -1384,9 +1384,9 @@ static bool finish_callback(struct task_ * We don't need any barriers here because utrace_barrier() * takes utrace->lock. If we touched engine->flags above, * the lock guaranteed this change was before utrace_barrier() - * examined utrace->reporting. + * examined engine->reporting. */ - utrace->reporting = NULL; + engine->reporting = false; /* * This is a good place to make sure tracing engines don't @@ -1414,13 +1414,13 @@ static const struct utrace_engine_ops *s unsigned long want; /* - * This barrier ensures that we've set utrace->reporting before + * This barrier ensures that we've set engine->reporting before * we examine engine->flags or engine->ops. utrace_barrier() * relies on this ordering to indicate that the effect of any * utrace_control() and utrace_set_events() calls is in place - * by the time utrace->reporting can be seen to be NULL. + * by the time engine->reporting can be seen to be NULL. */ - utrace->reporting = engine; + engine->reporting = true; smp_mb(); /* @@ -1440,13 +1440,13 @@ static const struct utrace_engine_ops *s return NULL; /* - * finish_callback() reset utrace->reporting after the + * finish_callback() reset engine->reporting after the * quiesce callback. Now we set it again (as above) * before re-examining engine->flags, which could have * been changed synchronously by ->report_quiesce or * asynchronously by utrace_control() or utrace_set_events(). */ - utrace->reporting = engine; + engine->reporting = true; smp_mb(); want = engine->flags; } @@ -1459,7 +1459,7 @@ static const struct utrace_engine_ops *s return ops; } - utrace->reporting = NULL; + engine->reporting = false; return NULL; } @@ -2013,7 +2013,7 @@ int utrace_get_signal(struct task_struct /* * See start_callback() comment about this barrier. */ - utrace->reporting = engine; + engine->reporting = true; smp_mb(); /* @@ -2025,7 +2025,7 @@ int utrace_get_signal(struct task_struct ops = engine->ops; if ((want & (event | UTRACE_EVENT(QUIESCE))) == 0) { - utrace->reporting = NULL; + engine->reporting = false; continue; }