On Tue, Jun 3, 2025 at 2:45 PM Andrii Nakryiko <andrii.nakryiko@xxxxxxxxx> wrote: > > On Tue, Jun 3, 2025 at 2:09 PM Song Liu <song@xxxxxxxxxx> wrote: > > > > On Tue, Jun 3, 2025 at 11:40 AM Andrii Nakryiko > > <andrii.nakryiko@xxxxxxxxx> wrote: > > [...] > > > > +__bpf_kfunc struct path *bpf_iter_path_next(struct bpf_iter_path *it) > > > > +{ > > > > + struct bpf_iter_path_kern *kit = (void *)it; > > > > + struct path root = {}; > > > > + > > > > + if (!path_walk_parent(&kit->path, &root)) > > > > + return NULL; > > > > + return &kit->path; > > > > +} > > > > + > > > > +__bpf_kfunc void bpf_iter_path_destroy(struct bpf_iter_path *it) > > > > +{ > > > > + struct bpf_iter_path_kern *kit = (void *)it; > > > > + > > > > + path_put(&kit->path); > > > > > > note, destroy() will be called even if construction of iterator fails > > > or we exhausted iterator. So you need to make sure that you have > > > bpf_iter_path state where you can detect that there is no path present > > > and skip path_put(). > > > > In bpf_iter_path_next(), when path_walk_parent() returns false, we > > still hold reference to kit->path, then _destroy() will release it. So we > > should be fine, no? > > you still need to handle iterators that failed to be initialized, > though? And one can argue that if path_walk_parent() returns false, we > need to put that last path before returning NULL, no? kit->path is zero'ed on initialization failures, so we can path_put() it safely. For _next() returns NULL case, we can either put kit->path in _destroy(), which is the logic now, or put kit->path in the last _next() call and make _destroy() a no-op in that case. I don't have a strong preference either way. Thanks, Song