On Fri, Sep 13, 2024 at 12:57:51PM +0200, Oleg Nesterov wrote:
> On 09/13, Jiri Olsa wrote:
> >
> > I'm not sure the realloc will help, I feel like we need to allocate return
> > consumer for each called handler separately to be safe
> 
> How about something like the (pseudo) code below? Note that this way
> we do not need uprobe->consumers_cnt. Note also that krealloc() should
> be unlikely and it checks ksize() before it does another allocation.
> 
> Oleg.
> 
> static size_t ri_size(int consumers_cnt)
> {
>       return sizeof(struct return_instance) +
>                     sizeof(struct return_consumer) * consumers_cnt;
> }
> 
> #define DEF_CNT       4       // arbitrary value
> 
> static struct return_instance *alloc_return_instance(void)
> {
>       struct return_instance *ri;
> 
>       ri = kzalloc(ri_size(DEF_CNT), GFP_KERNEL);
>       if (!ri)
>               return ZERO_SIZE_PTR;
> 
>       ri->consumers_cnt = DEF_CNT;
>       return ri;
> }
> 
> static struct return_instance *push_id_cookie(struct return_instance *ri, int 
> idx,
>                                               __u64 id, __u64 cookie)
> {
>       if (unlikely(ri == ZERO_SIZE_PTR))
>               return ri;
> 
>       if (unlikely(idx >= ri->consumers_cnt)) {
>               ri->consumers_cnt += DEF_CNT;
>               ri = krealloc(ri, ri_size(ri->consumers_cnt), GFP_KERNEL);
>               if (!ri) {
>                       kfree(ri);
>                       return ZERO_SIZE_PTR;
>               }
>       }
> 
>       ri->consumers[idx].id = id;
>       ri->consumers[idx].cookie = cookie;
>       return ri;
> }
> 
> static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
> {
>       ...
>       struct return_instance *ri = NULL;
>       int push_idx = 0;
> 
>       list_for_each_entry_rcu(uc, &uprobe->consumers, cons_node, 
> rcu_read_lock_trace_held()) {
>               __u64 cookie = 0;
>               int rc = 0;
> 
>               if (uc->handler)
>                       rc = uc->handler(uc, regs, &cookie);
> 
>               remove &= rc;
>               has_consumers = true;
> 
>               if (!uc->ret_handler || rc == UPROBE_HANDLER_REMOVE || rc == 2)
>                       continue;
> 
>               if (!ri)
>                       ri = alloc_return_instance();
> 
>               // or, better if (rc = UPROBE_HANDLER_I_WANT_MY_COOKIE)
>               if (uc->handler))
>                       ri = push_id_cookie(ri, push_idx++, uc->id, cookie);
>       }
> 
>       if (!ZERO_OR_NULL_PTR(ri)) {

should we rather bail out right after we fail to allocate ri above?

>               ri->consumers_cnt = push_idx;
>               prepare_uretprobe(uprobe, regs, ri);
>       }
> 
>       ...
> }
> 

nice, I like that, will try to to plug it with the rest

thanks,
jirka

Reply via email to