uprobes && pre-filtering
Hello.
There is a known (and by design) problem with uprobes. They act systemwide, there is no pre-filtering. Just some random thoughts to provoke the discussion.
- I think that the current uprobe_consumer->filter(task) should die.
It buys nothing. It is called right before ->handler() and this is pointless, ->handler() can call it itself.
And more importantly, I do not think this hook (with the same semantics) can/should be used by both register and handler_chain().
- We should change register_ and and mmap to filter out the tasks which we do not want to trace. To simplify, lets forget about multiple consumers first.
Everything is simple, install_breakpoint() callers should simply call consumer->filter(args) and do nothing if it returns false.
The main problem is, what should be passed as "args". I think it is pointless to use task_struct as an argument. And not because there is no simple way to find all tasks which use this particular mm in register_for_each_vma(), even if it was possible I think this makes no sense.
If 2 tasks/threads share the same mm they will share int3 as well, so I think we need
enum filter_mode {
UPROBE_FILTER_REGISTER,
UPROBE_FILTER_MMAP,
/* more */
};
consumer->filter(enum filter_mode mode, struct mm_struct *mm); Sure, this does not allow to, say, probe the tasks with the given uid. But once again, currently we do not have for_each_mm_user(task, mm) and even if we implement it
a) ->filter(mm) can use it itself)
b) I do not think register_for_each_vma() should call it.
Suppose that a consumer wants to track the task with the given pid PID. In this case ->filter() can simply check find_task_by_vpid(PID)->mm = mm. This is fast and simple.
Or you want to probe all instances of /bin/ls. In this case filter() can check mm->exe_file->f_path == saved_path, this is very cheap.
But if we add for_each_mm_user() into register_for_each_vma() it will be called even if the filtering is simple.
So. If filter(UPROBE_FILTER_REGISTER) needs to check task_uid(task) == UID it has to do for_each_process() until we have (if ever) for_each_mm_user().
Or it should always return true and remove the unnecessary breakpoints later, or use another API (see below).
Also. Who needs the "nontrivial" filtering? I do not see any potential in-kernel user. And the tools like systemtap can take another approach (perhaps).
- Perhaps we should extend the API. We can add
uprobe_apply(consumer, task, bool add_remove);
which adds/removes breakpoints to task->mm.
This way consumer can probe every task it wants to trace after uprobe_register().
Its ->filter(UPROBE_FILTER_REGISTER) should simply return false. Or, better, we can split uprobe_register() into 2 functions, __uprobe_register() and uprobe_apply_all() which actually does register_for_each_vma().
***** QUESTION *****: perhaps this is all systemtap needs? ignoring UPROBE_FILTER_MMAP.
- Multiple consumers. uprobe_register/uprobe_unregister should be modified so that register_for_each_vma() is called every time when the new consumer comes or consumer goes away.
uprobe_apply(add_remove => false) should obviously consult other consumers too.
- Perhaps we should teach handle_swbp() to remove the unwanted breakpoints.
If every ->handler() returns, say, UPROBE_GO_AWAY handle_swbp() should remove this breakpoint. Of course, a consumer must be sure that if it returns UPROBE_GO_AWAY this task can't share ->mm with another task it wants to trace.
Or consumer->handler() can do uprobe_apply(add_remove => false) itself, but this needs more discussion.
The point is that if the filtering at UPROBE_FILTER_REGISTER time is not possible, ->filter(UPROBE_FILTER_REGISTER) can return true. A "wrong" int3 doesn't hurt until the task actually hits the breakpoint, and I think that a single bp-hit is fine performance-wise.
- fork(). The child inherits all breakpoints from parent, and uprobes can't control this. What can we do?
* We can add another uprobe hook which does something like
for_each_uprobe_in_each_vma(child_mm) {
if (filter(UPROBE_FILTER_FORK))
install_breakoint();
else
remove_breakpoint();
}
But is is not clear where can we add this hook. dup_mmap() looks appealing, but at this time the child is still under construction, consumer->filter() can't look at task_struct.
And of course, it is not nice to slow down fork().
* If we only care about the unwanted breakpoints, perhaps it would be better to rely on UPROBE_GO_AWAY above?
* Finally, do we care at all? Again, who can ever need to re-install breakpoints after fork?
systemtap (iiuc) doesn't need this. And even if it does or will need, I guess it can hook fork itself and use uprobe_apply() ?
Please comment.
Oleg.
Quoted 11 lines
Hello.
There is a known (and by design) problem with uprobes. They act systemwide, there is no pre-filtering. Just some random thoughts to provoke the discussion.
- I think that the current
uprobe_consumer->filter(task)should die.It buys nothing. It is called right before ->handler() and this is pointless, ->handler() can call it itself.
I think it helps to call filter before handler.
When a tracer has specified a filter condition and then we run a handler for cases that dont fit the handler looks a little odd.
Another reason for having the filters in the current way was to have a set of standard filters in uprobes code so that all users dont need to recreate these filters.
Also please see below.
Quoted 7 lines
And more importantly, I do not think this hook (with the same semantics) can/should be used by both register and
handler_chain().- We should change
register_and and mmap to filter out the tasks which we do not want to trace. To simplify, lets forget about multiple consumers first.
Quoted 9 lines
Everything is simple,
install_breakpoint()callers should simply callconsumer->filter(args)and do nothing if it returns false.The main problem is, what should be passed as "args". I think it is pointless to use
task_structas an argument. And not because there is no simple way to find all tasks which use this particular mm inregister_for_each_vma(), even if it was possible I think this makes no sense.
Having mm instead of task is fine with me. But this would mostly mean that the prefilter, i.e filter at the time of registration and the filter at the time of handling should be different or we remove the handling time filtering and expect the handler to do the filtering.
Having a task instead of mm helps in having the same filter run at both places.
Quoted 10 lines
If 2 tasks/threads share the same mm they will share int3 as well, so I think we need
enum filter_mode { UPROBE_FILTER_REGISTER, UPROBE_FILTER_MMAP, /* more */ }; consumer->filter(enum filter_mode mode, struct mm_struct *mm);
what would a tracing session having filter_mode == UPROBE_FILTER_REGISTER mean?
Does that mean it can trace only instances in currently mapped vmas?
Would it handle a probe instance in a process that is already running but has not yet mapped a vma?
Also would a tracing session having filter_mode == UPROBE_FILTER_MMAP mean that it would only handle probepoints in only vmas that are going to be mapped in future?
Quoted 47 lines
Sure, this does not allow to, say, probe the tasks with the given uid. But once again, currently we do not have
for_each_mm_user(task, mm)and even if we implement ita) ->filter(mm) can use it itself)
b) I do not think
register_for_each_vma()should call it.Suppose that a consumer wants to track the task with the given pid PID. In this case ->filter() can simply check find_task_by_vpid(PID)->mm = mm. This is fast and simple.
Or you want to probe all instances of
/bin/ls. In this casefilter()can checkmm->exe_file->f_path==saved_path, this is very cheap.But if we add
for_each_mm_user()intoregister_for_each_vma()it will be called even if the filtering is simple.So. If
filter(UPROBE_FILTER_REGISTER)needs to checktask_uid(task)== UID it has to dofor_each_process()until we have (if ever)for_each_mm_user().Or it should always return true and remove the unnecessary breakpoints later, or use another API (see below).
Also. Who needs the "nontrivial" filtering? I do not see any potential in-kernel user. And the tools like systemtap can take another approach (perhaps).
- Perhaps we should extend the API. We can add
uprobe_apply(consumer, task, bool add_remove);which adds/removes breakpoints to
task->mm.This way consumer can probe every task it wants to trace after
uprobe_register().Its ->filter(UPROBE_FILTER_REGISTER) should simply return false. Or, better, we can split
uprobe_register()into 2 functions,__uprobe_register()anduprobe_apply_all()which actually doesregister_for_each_vma().***** QUESTION *****: perhaps this is all systemtap needs? ignoring
UPROBE_FILTER_MMAP.
Quoted 6 lines
- Multiple consumers. uprobe_register/uprobe_unregister should be modified so that
register_for_each_vma()is called every time when the new consumer comes or consumer goes away.
uprobe_apply(add_remove => false)should obviously consult other consumers too.
So in this case, would uprobe_register() just add a consumer to a new/existing uprobe. The actual probe insertion is done by the uprobe_apply()/uprobe_apply_all(). Also in this case, there is no filter element in the uprobe_consumer. Right?
I am just wondering if people could use/misuse this
for example: - somebody could keep modifying and reusing the consumers but one probe registration, with subsequent uprobe_apply(). Unlike now we could have lots of uprobes but all with defunct consumers.
Quoted 7 lines
- Perhaps we should teach
handle_swbp()to remove the unwanted breakpoints.If every ->handler() returns, say,
UPROBE_GO_AWAYhandle_swbp()should remove this breakpoint. Of course, a consumer must be sure that if it returnsUPROBE_GO_AWAYthis task can't share ->mm with another task it wants to trace.
Its a good idea to remove redundant probepoints from the breakpoint hit context. However,
- even from the handlers() perspective, if we have to identify that this consumer isnt looking at this mm, we need something like for_each_mm_user(). No?
- also if we are looking for removing a breakpoint, I would think its better done in common code, i.e uprobe code rather than keeping it in every handler. So I think keeping the filter logic before the handler is good.
Quoted 9 lines
Or
consumer->handler()can douprobe_apply(add_remove => false)itself, but this needs more discussion.The point is that if the filtering at
UPROBE_FILTER_REGISTERtime is not possible, ->filter(UPROBE_FILTER_REGISTER) can return true. A "wrong" int3 doesn't hurt until the task actually hits the breakpoint, and I think that a single bp-hit is fine performance-wise.
Agree. Also the reason why we inserted this probe in the current mm might have changed and we might no more need the probe.
For example, traced thread in a multithreaded process actually died and all other threads may not be interested
Quoted 22 lines
-
fork(). The child inherits all breakpoints from parent, and uprobes can't control this. What can we do?* We can add another uprobe hook which does something like
for_each_uprobe_in_each_vma(child_mm){
if (filter(UPROBE_FILTER_FORK))
install_breakoint();
else
remove_breakpoint();
}But is is not clear where can we add this hook.
dup_mmap()looks appealing, but at this time the child is still under construction,consumer->filter()can't look attask_struct.And of course, it is not nice to slow down
fork().* If we only care about the unwanted breakpoints, perhaps it would be better to rely on
UPROBE_GO_AWAYabove?
Quoted 6 lines
* Finally, do we care at all? Again, who can ever need to re-install breakpoints after fork?
systemtap (iiuc) doesn't need this. And even if it does or will need, I guess it can hook fork itself and use
uprobe_apply()?
I was thinking if we can implement for_each_mm_user() using additional mm->flags.
Would something like this work?
- Set a new MMF_REPARENTED flag for a mm, when its thread either gets reparented or is called with CLONE_PARENT.
- for_each_mm_users would only be needed during uprobe_register / uprobe_mmap() if and only if there are filters.
- for_each_mm_users would mostly boil down to searching in children, siblings unless MMF_REPARENTED flag is set.
- If MMF_REPARENTED flag is set for a mm, and probe needs filtering, then we look at do_each_thread ..for_each_thread. This would mostly not be the common case. So I hope this should be okay. Not sure if we could look at further optimizing like looking at parent's children, init's children to see if any of them refer to mm.
Signature · 2 lines
Thanks and Regards Srikar
Quoted 7 lines · Srikar Dronamraju
Quoted 7 lines
Hello.
There is a known (and by design) problem with uprobes. They act systemwide, there is no pre-filtering. Just some random thoughts to provoke the discussion.
Quoted 7 lines
Quoted 5 lines
- I think that the current
uprobe_consumer->filter(task)should die.It buys nothing. It is called right before ->handler() and this is pointless, ->handler() can call it itself.
I think it helps to call filter before handler.
How? The hanlder can simply call this function at the start.
But this is minor. I think this can double the work sometimes. If ->handler needs to do something nontrivial, it will probably look into my_traced_tasks database anyway to find the additional info which represents the tracee. And most probably ->filter() will do the same lookup unnecessary.
Quoted 6 lines
When a tracer has specified a filter condition and then we run a handler for cases that dont fit the handler looks a little odd.
Another reason for having the filters in the current way was to have a set of standard filters in uprobes code so that all users dont need to recreate these filters.
IOW, you mean that both register_for_each_vma() and handler_chain() should use the same ->filter() method? Personally I do not think they should.
Because the semantics is different imo. register_for_each_vma() needs to know if we should modify mm and insert the breakpoint. handler_chain() just tries to skip ->handler() (and for no reason, imho).
Quoted 17 lines
Quoted 7 lines
And more importantly, I do not think this hook (with the same semantics) can/should be used by both register and
handler_chain().- We should change
register_and and mmap to filter out the tasks which we do not want to trace. To simplify, lets forget about multiple consumers first.Quoted 9 lines
Everything is simple,
install_breakpoint()callers should simply callconsumer->filter(args)and do nothing if it returns false.The main problem is, what should be passed as "args". I think it is pointless to use
task_structas an argument. And not because there is no simple way to find all tasks which use this particular mm inregister_for_each_vma(), even if it was possible I think this makes no sense.
Quoted 3 lines
Having mm instead of task is fine with me. But this would mostly mean that the prefilter, i.e filter at the time of registration and the filter at the time of handling should be different
Yes, I think they should be different, please see above.
We need the pre-filtering to avoid the unnecessary traps, not to avoid the function call when the task already hit the breakpoint.
Quoted 2 lines
or we remove the
handling time filtering and expect the handler to do the filtering.
Yes. But once again, if ->handler() wants to use the same function it can simply call it.
Quoted 2 lines
Having a task instead of mm helps in having the same filter run at both places.
And this is where we start to disagree. Namely, I do not think that register_for_each_vma() should even try to find mm user(s).
Because once again, a) whater register_for_each_vma() can do to iterate the tasks can be done by ->filter, b) right now I do not see any potential user who will need this so we should not overdesign this.
Quoted 11 lines
Quoted 10 lines
If 2 tasks/threads share the same mm they will share int3 as well, so I think we need
enum filter_mode { UPROBE_FILTER_REGISTER, UPROBE_FILTER_MMAP, /* more */ }; consumer->filter(enum filter_mode mode, struct mm_struct *mm);
Quoted 7 lines
what would a tracing session having
filter_mode==UPROBE_FILTER_REGISTERmean?
Does that mean it can trace only instances in currently mapped vmas?
Would it handle a probe instance in a process that is already running but has not yet mapped a vma?Also would a tracing session having
filter_mode==UPROBE_FILTER_MMAPmean that it would only handle probepoints in only vmas that are going to be mapped in future?
No, no, you misunderstood. Sorry I was unclear and yes, the naming I used was confusing.
I meant that both register_for_each_vma() and uprobe_mmap() (lets ignore other callers and other modes) call the same ->filter() method but with the different "mode" argument, UPROBE_FILTER_REGISTER or UPROBE_FILTER_MMAP. This is only the hint, for example UPROBE_FILTER_MMAP can use current but UPROBE_FILTER_REGISTER obviously can't.
Quoted 21 lines
Quoted 21 lines
- Perhaps we should extend the API. We can add
uprobe_apply(consumer, task, bool add_remove);which adds/removes breakpoints to
task->mm.This way consumer can probe every task it wants to trace after
uprobe_register().Its ->filter(UPROBE_FILTER_REGISTER) should simply return false. Or, better, we can split
uprobe_register()into 2 functions,__uprobe_register()anduprobe_apply_all()which actually doesregister_for_each_vma().***** QUESTION *****: perhaps this is all systemtap needs? ignoring
UPROBE_FILTER_MMAP.- Multiple consumers. uprobe_register/uprobe_unregister should be modified so that
register_for_each_vma()is called every time when the new consumer comes or consumer goes away.
Quoted 7 lines
Quoted 2 lines
uprobe_apply(add_remove => false)should obviously consult other consumers too.So in this case, would
uprobe_register()just add a consumer to a new/existing uprobe. The actual probe insertion is done by the uprobe_apply()/uprobe_apply_all().
Yes. Not sure we really need this, but to me this extension looks natural.
Frank, Josh, do you think it can help systemtap ?
Suppose that the consumer no longer wants to trace the task T but it has other tasks to trace. If we only rely on ->filter, the tracer should do unregister + register, this doesn't look good. Or it wants to add the new task to its trace-list...
Quoted 2 lines
Also in this case, there is no
filter element in theuprobe_consumer. Right?
Why? it could be there.
Quoted 3 lines
I am just wondering if people could use/misuse this
for example: - somebody could keep modifying and reusing the consumers but one probe registration, with subsequentuprobe_apply().
Yes, exactly.
Quoted 1 line
Unlike now we could have lots of uprobes but all with defunct consumers.
sorry, can't understand...
Quoted 7 lines
Quoted 6 lines
- Perhaps we should teach
handle_swbp()to remove the unwanted breakpoints.If every ->handler() returns, say,
UPROBE_GO_AWAYhandle_swbp()should remove this breakpoint. Of course, a consumer must be sure that if it returnsUPROBE_GO_AWAYthis task can't share ->mm with another task it wants to trace.
Quoted 6 lines
Its a good idea to remove redundant probepoints from the breakpoint hit context. However,
- even from the
handlers()perspective, if we have to identify that this consumer isnt looking at this mm, we need something likefor_each_mm_user(). No?
Yes and no, I think.
Yes, _in general_ it is needed. (although once again, where is potential users?).
But in the simple case - no. For example, filter-by-pid should return UPROBE_GO_AWAY if current->mm != find_task_by_vpid(PID)->mm.
Quoted 4 lines
- also if we are looking for removing a breakpoint, I would think its better done in common code, i.e uprobe code rather than keeping it in every handler. So I think keeping the filter logic before the handler is good.
Again, I do not understand why do you think so. OK, I won't really insist, we can add UBPROBE_FILTER_BP_HIT or whatever. Still I do not understand why should we mix remove-this-breakpoint and do-not-call-hanlder. And note that ->handler() has to do addtional checks anyway.
Anyway. Do you agree that filter's arguments should be changed? If yes, then we should remove handler_chain()->filter(), then discuss why we should add it back and which semantics it should have. Agreed?
Quoted 9 lines
Quoted 8 lines
Or
consumer->handler()can douprobe_apply(add_remove => false)itself, but this needs more discussion.The point is that if the filtering at
UPROBE_FILTER_REGISTERtime is not possible, ->filter(UPROBE_FILTER_REGISTER) can return true. A "wrong" int3 doesn't hurt until the task actually hits the breakpoint, and I think that a single bp-hit is fine performance-wise.
Quoted 4 lines
Agree. Also the reason why we inserted this probe in the current mm might have changed and we might no more need the probe.
For example, traced thread in a multithreaded process actually died and all other threads may not be interested
Yes.
Quoted 25 lines
Quoted 25 lines
-
fork(). The child inherits all breakpoints from parent, and uprobes can't control this. What can we do?* We can add another uprobe hook which does something like
for_each_uprobe_in_each_vma(child_mm){
if (filter(UPROBE_FILTER_FORK))
install_breakoint();
else
remove_breakpoint();
}But is is not clear where can we add this hook.
dup_mmap()looks appealing, but at this time the child is still under construction,consumer->filter()can't look attask_struct.And of course, it is not nice to slow down
fork().* If we only care about the unwanted breakpoints, perhaps it would be better to rely on
UPROBE_GO_AWAYabove?* Finally, do we care at all? Again, who can ever need to re-install breakpoints after fork?
Quoted 7 lines
Quoted 3 lines
systemtap (iiuc) doesn't need this. And even if it does or will need, I guess it can hook fork itself and use
uprobe_apply()?I was thinking if we can implement
for_each_mm_user()using additionalmm->flags.
(I guess you didn't meant it can help to solve the problem with fork)
I do not know if we can (or should) implement for_each_mm_user().
My main point was, the core uprobes should not care. Once again, who do you think will need it? systemtap doesn't afaics, neither debug/tracing/uprobe_events.
And once again, even if we have to implement it for some new tricky tracer, why its ->filter can not do for_each_mm_user() itself?
Quoted 5 lines
Would something like this work?
...-
for_each_mm_userswould mostly boil down to searching in children, siblings unlessMMF_REPARENTEDflag is set.
Whose children? I don't think mm->owner is always the root of the tree. And what about the locking? I do not think we want to call ->filter under (say) tasklist.
But again, again. Why do you think register_for_each_vma() should do this? IOW, why should we think about for_each_mm_user() at all (at least right now) ?
Oleg.
Quoted 11 lines · Oleg Nesterov
Quoted 3 lines · Srikar Dronamraju
Another reason for having the filters in the current way was to have a set of standard filters in uprobes code so that all users dont need to recreate these filters.
IOW, you mean that both
register_for_each_vma()andhandler_chain()should use the same ->filter() method? Personally I do not think they should.Because the semantics is different imo.
register_for_each_vma()needs to know if we should modify mm and insert the breakpoint.handler_chain()just tries to skip ->handler() (and for no reason, imho).
I agree here - I don't see much use for filter(), and even if you have it, the semantics are definitely different than prefilter(). You could do all sorts of localized and temporal checks in filter() that make no sense for a prefilter(), like check for a particular thread id, filter every N hits, or filter only hits under calls to some foo().
[...]
Quoted 25 lines
Quoted 25 lines
Quoted 23 lines
- Perhaps we should extend the API. We can add
uprobe_apply(consumer, task, bool add_remove);which adds/removes breakpoints to
task->mm.This way consumer can probe every task it wants to trace after
uprobe_register().Its ->filter(UPROBE_FILTER_REGISTER) should simply return false. Or, better, we can split
uprobe_register()into 2 functions,__uprobe_register()anduprobe_apply_all()which actually doesregister_for_each_vma().***** QUESTION *****: perhaps this is all systemtap needs? ignoring
UPROBE_FILTER_MMAP.- Multiple consumers. uprobe_register/uprobe_unregister should be modified so that
register_for_each_vma()is called every time when the new consumer comes or consumer goes away.
uprobe_apply(add_remove => false)should obviously consult other consumers too.
Quoted 7 lines
Quoted 3 lines
So in this case, would
uprobe_register()just add a consumer to a new/existing uprobe. The actual probe insertion is done by the uprobe_apply()/uprobe_apply_all().Yes. Not sure we really need this, but to me this extension looks natural.
Frank, Josh, do you think it can help systemtap ?
Yes, I think this sounds closer to systemtap's model of probing. We already track tasks that come and go to see which are "interesting", so we could easily call apply() at that time. We actually watch mmaps too, so I think we could apply() for that case as well.
We wouldn't even need filtering functions at all in this mode. But maybe other consumers could still use it, like perf.
However, it's not clear to me what value there is in uprobe_register, if you always have to apply it too. The modes are something like:
1. uprobe_register(); uprobe_apply_all();
2. uprobe_register(); uprobe_apply(); [...]
And the second could have a bunch of idle registrations waiting for the first applicable task to come around. So why not instead:
1. uprobe_register_all();
2. uprobe_register_task(); [...]
In this case, the second would have to allow the same consumer to be repeated on different tasks, but it feels more natural to me.
Josh
Quoted 23 lines · Josh Stone
Quoted 21 lines · Oleg Nesterov
Quoted 20 lines
Quoted 9 lines
- Perhaps we should extend the API. We can add
uprobe_apply(consumer, task, bool add_remove);which adds/removes breakpoints to
task->mm.This way consumer can probe every task it wants to trace after
uprobe_register().Quoted 8 lines
Its ->filter(UPROBE_FILTER_REGISTER) should simply return false. Or, better, we can split
uprobe_register()into 2 functions,__uprobe_register()anduprobe_apply_all()which actually doesregister_for_each_vma().***** QUESTION *****: perhaps this is all systemtap needs? ignoring
UPROBE_FILTER_MMAP.So in this case, would
uprobe_register()just add a consumer to a new/existing uprobe. The actual probe insertion is done by the uprobe_apply()/uprobe_apply_all().
Quoted 8 lines
Quoted 3 lines
Yes. Not sure we really need this, but to me this extension looks natural.
Frank, Josh, do you think it can help systemtap ?
Yes, I think this sounds closer to systemtap's model of probing. We already track tasks that come and go to see which are "interesting", so we could easily call
apply()at that time. We actually watch mmaps too, so I think we couldapply()for that case as well.
OK, thanks.
(just in case, mmap is different, but lets ignore this now).
Quoted 2 lines
We wouldn't even need filtering functions at all in this mode. But maybe other consumers could still use it, like perf.
Of course, we need ->filter() anyway.
Quoted 5 lines
However, it's not clear to me what value there is in
uprobe_register, if you always have to apply it too. The modes are something like:1.
uprobe_register();uprobe_apply_all();
2.uprobe_register();uprobe_apply(); [...]
No, no, sorry for confusion.
I meant we could add __uprobe_register() (or whatever) which doesn't actually insert the breakpoint. So if the tracer relies on uprobe_apply() it can avoid the costly register_for_each_vma/filter and do __uprobe_register + apply.
This is not strictly necessary even if we add uprobe_apply*, and you can always use uprobe_register() (or uprobe_register_all as you denoted it below).
Quoted 7 lines
first applicable task to come around. So why not instead:
1.
uprobe_register_all();
2.uprobe_register_task(); [...]In this case, the second would have to allow the same consumer to be repeated on different tasks, but it feels more natural to me.
This can work too.
But uprobe_unregister_task() doesn't look very clear. What should it do? IOW, you still need uprobe_unregister_all() and this doesn't look symmetrical.
Oleg.