Something that's always been an issue in the utrace interface is the
management of struct utrace_attached_engine.  It's tricky that you have to
use RCU and/or follow picayune rules in the attach+set_events->callbacks
sequence to be sure your engine pointer is valid.  From the beginning, I
expected to revisit this aspect of the interface and think it through again
at some point.  But I hadn't really thought about it in a long time now.

The discussion here on the asynchronous detach problem has helped me think
through the details that impinge on the concerns that had led me to write
it this way originally.  I'm grateful to David and Ananth for the detailed
exchange that helps air these things out.  Please keep it up!

We've been talking about all these corner cases with races, where I list
all the caveats for interactions with detach.  What these all come down to
is that your engine pointer might have been freed.  RCU can protect against
that, but it gets sticky if you want to block.  The common mechanism for
dealing with this kind of issue in interfaces is reference counted objects.
In the original implementation, I was resistant to using reference counts
on engines for a few reasons.

One reason was the idea that the interface could make it hard to leak.
I do still think it's good that e.g. the interface not encourage you to
hold task refs (i.e. you don't need them because you'll get a final
report_reap callback before the struct goes away).  But for the engine
structs, the option opposite leaks is to make the failure mode likely in
sloppy modules that they use a dangling engine pointer.  That is most
likely more dangerous than leaks, and especially likely to do something
bad to someone else's engine (since the pointer will be reused).  So
that objection to reference counts just doesn't hold any water.

Other concerns had to do with having lockless reporting loops, and
originally that seemed to require RCU for the structs anyway.  But that
part of the implementation has been straightened out since.  How we
manage the lockless list now is completely independent of RCU lists.
I've also objected to reference counts being touched for reporting,
and I still do.  But they don't have to be.

The callback synchronization thing is simpler when we have an engine
pointer that can be relied on, even when you block.  I'm guessing
everyone will be happy to see reference counts replace RCU in the
interface for dealing with struct utrace_attached_engine.

So here is what I'm thinking:

utrace_attach returns a ref for the caller.  You can use
utrace_engine_get(engine) and utrace_engine_put(engine) to manage the
pointer.  When you drop the last ref, the struct is freed.  There are no
release/destructor callbacks for that, the refcount is purely for the
purpose of keeping the pointer valid.  

An implicit ref is held while the engine is attached.  The engine
pointer can always be used during a callback because of this ref.  Your
callback can add a new ref even if you had dropped all other refs.  If a
callback returns UTRACE_DETACH, then this ref will be dropped (and might
be the last).

Since it's easy to keep the engine pointer on hand, we really only need
one synchronizing call.  So now there will be no *_sync calls after all.
utrace_set_events and utrace_control(,UTRACE_DETACH) can return
-EINPROGRESS as I described before.  This means the change of event
mask, or the detach, will take effect--but there might be a callback
already in progress or unavoidably on its way.  To block until that
callback is done, you can call utrace_barrier.

So now the safe detach procedure would be:

        ret = utrace_control(task, engine, UTRACE_DETACH);
        if (ret == -EINPROGRESS)
                ret = utrace_barrier(task, engine);
        if (ret == -ERESTARTSYS) /* interrupted wait, maybe callback pending */
                return ret;
        utrace_engine_put(engine);

I haven't really tested the new code at all.  But this took not much
work at all to change in the implementation.  If this is the right
direction, I'll give the code a modicum of testing and update the
documentation bits after another once-over on Monday.


Thanks,
Roland

Reply via email to