On 08/17, Roland McGrath wrote:
>
> > Now. we should make sure that every user of UTRACE_DETACH frees
> > engine->data. And, we have to introduce ptrace_report_reap() which
> > should free it too.
>
> Right, or you can have a report_death callback

Ah sorry, I meant ->report_death, not _reap.

> (or even just report_quiesce
> when passed UTRACE_EVENT(DEATH)) that always detaches.

Hmm. Not sure I understand how can we do without hooking death or reap...

> synchronizing with de_thread(), which is the one place that
> ordinarily preempts the ptrace wait interference.)

Not only de_thread(). If the tracee is killed, another thread can
do wait()->release_task(). This means even _reap (instead of _death)
can't save us.

> I see two basic models for handling the engine lifetime issues in a utrace
> engine.
>
> One way is where you do not normally hold a utrace_engine reference.
> You get an initial one from UTRACE_ATTACH_CREATE when you do setup.
> Once you have done utrace_set_events() and maybe utrace_control(), you
> do utrace_engine_put() immediately.  Then if you have callbacks that
> use UTRACE_DETACH (or else have report_reap, where it's implicit) they
> are responsible for engine->data.  And indeed you must have some such
> if you have an engine->data pointer that needs cleanup.  This model is
> probably a good fit for "passive" tracing, where the only thing you
> really come back and do later is disable it (or for something simple
> enough it doesn't need any cleanup for engine->data).  Then you can do:
>
>       engine = utrace_attach_task(task, UTRACE_ATTACH_MATCH_OPS,
>                                  &my_ops, NULL);
>       if (IS_ERR(engine)) ...
>       ret = utrace_control(task, engine, UTRACE_DETACH);
>       if (ret) ...
>       clean_up(engine->data);
>
> where -ESRCH/-EALREADY tell you that your report_reap/report_death
> (also counts for report_quiesce in the report_death pass) either will
> run, has run, or is running, so in that case you rely on them to do:
>
>       clean_up(engine->data);
>       return UTRACE_DETACH;

I must have missed something.

Sure, it is more or less trivial to free engine->data safely. I mean,
it is easy to avoid the double-free/etc problems.

But I can't understand how the tracer can use ->data safely. Whatever
the tracer does, the tracee can be killed at any moment. It can
pass ->report_death/reap events under us.

The tracer has 2 references, one to task_struct, another one to engine.
That is why I still think a reference to engine should also pin
engine->data, and I like very much the patch you sent.

> The second model is where you normally hold a utrace_engine reference
> to represent the life of your data structure, separate from the
> implicit utrace_engine reference for being attached. The engine uses
> the rule that the code that drops the last engine reference cleans up
> the data structure, rather than the code that detaches doing that.

And this means we need some hairy tricks.

Perhaps I am overestimating this problem and these tricks are not
that hairy. But still engine->release method is much simpler.

> But I'm always open to adding things to make it easier
> to write modules (and with fewer bugs),

Yes!

> > I strongly believe that ->data should be freed by utrace_engine_put().
> > If you have the reference to engine, engine->data must be stable.
>
> Well, that's a rule you can decide you want for your engine's handling
> of its ->data, sure.  You can in fact do that already, since you really
> are in control of all the gets and puts.  There is one put that's
> implicit in detach, but you always either choose to detach or at least
> could be notified.  All other gets and puts are what your engine's code
> chose to do.

Yes sure. If you don't apply your patch which uses ops->release(), then I
am going to add engine->data->in_use for reports which return UTRACE_DETACH
or ->report_death. If the tracer needs engine->data it should use
ptrace_get_context/ptrace_put_context. I am not sure we can avoid taking
utrace->lock for that...

> > So, this patch adds engine->dtor and utrace_engine_set_dtor() helper.
>
> The proper interface for this is just to add .release to utrace_engine_ops.
> Because of how we fiddle the fields in detach, we'd still need to put the
> function pointer into struct utrace_engine at some point in the
> implementation.  But the API doesn't really need to know about that.

Yes, agreed.

> > Afaics, unless a module intentionally leaks utrace_engine, it can safely
> > use ->dtor() which lives in ->module_core. But at least it can always
> > use ->dtor = kfree.
>
> I've never really figured out all the issues about module unloading for
> utrace.  I assume that's what you're referring to here.  The two obvious
> safe paths would seem to be either holding module refs whenever an
> engine is attached (or now, until your release hook is called), or
> synchronously detaching all engines (plus utrace_barrier et al) in the
> module_exit function.

Yes.

Oleg.

Reply via email to