Hmm. For unknown reason I do not see this 2/4 patch on utrace-devel,
strange.

So I am attaching it in case my email was really lost and you didn't
get it.

Oleg.
[PATCH 2/4] utrace_set_events: consolidate "setting _UTRACE_DEATH_EVENTS" checks

utrace_set_events() checks the "setting _UTRACE_DEATH_EVENTS" case twice,
and it is not immediately obvious why the first check is needed, and why
it is not racy (we are checking exit_state without tasklist). The code is
correct, but looks confusing.

The first check covers the case when target->utrace_flags already has
_UTRACE_DEATH_EVENTS and thus tracehook_report_death() can't bypass
utrace_report_death(), but we should ensure that REPORT_CALLBACKS() was
not called yet. We can check ->exit_state lockless because it must be
visible when utrace_report_death() unlocks utrace->lock.

The second check ensures we can't race with tracehook_report_death()
which checks task_utrace_flags(), so if we add _UTRACE_DEATH_EVENTS to
->utrace_flags we have to take tasklist.

In short: this double check allows to avoid tasklist when utrace_flags
already has these bits while engine->flags doesn't.

But multitracing is unlikely case, in the likely case if we add
_UTRACE_DEATH_EVENTS to engine->flags we set these bits in utrace_flags
too. I think it makes sense to consolidate these checks to make the
code a bit more understandable.

Also, add the small comment to explain the lockless exit_state check.

Signed-off-by: Oleg Nesterov <o...@redhat.com>
---

 kernel/utrace.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

--- kstub/kernel/utrace.c~2_consolidate_death_events_checks     2010-08-14 
04:30:28.000000000 +0200
+++ kstub/kernel/utrace.c       2010-08-14 04:30:28.000000000 +0200
@@ -539,11 +539,11 @@ int utrace_set_events(struct task_struct
        old_utrace_flags = target->utrace_flags;
        old_flags = engine->flags & ~ENGINE_STOP;
 
+       /* If ->death or ->reap is true we must see exit_state != 0. */
        if (target->exit_state) {
                unsigned long cleared = (old_flags & ~events);
 
-               if (((events & ~old_flags) & _UTRACE_DEATH_EVENTS) ||
-                   (utrace->death && (cleared & _UTRACE_DEATH_EVENTS)) ||
+               if ((utrace->death && (cleared & _UTRACE_DEATH_EVENTS)) ||
                    (utrace->reap  && (cleared &  UTRACE_EVENT(REAP)))) {
                        spin_unlock(&utrace->lock);
                        return -EALREADY;
@@ -560,7 +560,7 @@ int utrace_set_events(struct task_struct
         * knows positively that utrace_report_death() will be called or
         * that it won't.
         */
-       if ((events & ~old_utrace_flags) & _UTRACE_DEATH_EVENTS) {
+       if ((events & ~old_flags) & _UTRACE_DEATH_EVENTS) {
                read_lock(&tasklist_lock);
                if (unlikely(target->exit_state)) {
                        read_unlock(&tasklist_lock);

Reply via email to