On 08/29, Andrii Nakryiko wrote: > > On Thu, Aug 29, 2024 at 4:10 PM Jiri Olsa <olsajiri@xxxxxxxxx> wrote: > > > > > @@ -2101,17 +2110,24 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs) > > > need_prep = true; > > > > > > remove &= rc; > > > + has_consumers = true; > > > } > > > current->utask->auprobe = NULL; > > > > > > if (need_prep && !remove) > > > prepare_uretprobe(uprobe, regs); /* put bp at return */ > > > > > > - if (remove && uprobe->consumers) { > > > - WARN_ON(!uprobe_is_active(uprobe)); > > > - unapply_uprobe(uprobe, current->mm); > > > + if (remove && has_consumers) { > > > + down_read(&uprobe->register_rwsem); > > > + > > > + /* re-check that removal is still required, this time under lock */ > > > + if (!filter_chain(uprobe, current->mm)) { > > > > sorry for late question, but I do not follow this change.. > > > > at this point we got 1 as handler's return value from all the uprobe's consumers, > > why do we need to call filter_chain in here.. IIUC this will likely skip over > > the removal? > > > > Because we don't hold register_rwsem we are now racing with > registration. So while we can get all consumers at the time we were > iterating over the consumer list to request deletion, a parallel CPU > can add another consumer that needs this uprobe+PID combination. So if > we don't double-check, we are risking having a consumer that will not > be triggered for the desired process. Oh, yes, but this logic is wrong in that it assumes that uc->filter != NULL. At least it adds the noticeable change in behaviour. Suppose we have a singler consumer UC with ->filter == NULL. Now suppose that UC->handler() returns UPROBE_HANDLER_REMOVE. Before this patch handler_chain() calls unapply_uprobe(), and I think we should keep this behaviour. After this patch unapply_uprobe() won't be called: consumer_filter(UC) returns true, UC->filter == NULL means "probe everything". But I think that UPROBE_HANDLER_REMOVE must be respected in this case anyway. Thanks Jiri, I missed that too :/ Oleg.