Re: [PATCH v2 bpf-next 1/4] bpf: Search for kptrs in prog BTF structs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, Aug 5, 2024 at 6:57 PM Hou Tao <houtao@xxxxxxxxxxxxxxx> wrote:
>
> Hi,
>
> On 8/6/2024 8:31 AM, Amery Hung wrote:
> > On Mon, Aug 5, 2024 at 3:25 PM Martin KaFai Lau <martin.lau@xxxxxxxxx> wrote:
> >> On 8/5/24 1:44 PM, Amery Hung wrote:
> >>>>>>> Maybe we should move the common btf used by kptr and graph_root into
> >>>>>>> btf_record and let the callers of btf_parse_fields() and
> >>>>>>> btf_record_free() to decide the life cycle of btf in btf_record.
> >>>>>> Could you maybe explain if and why moving btf of btf_field_kptr and
> >>>>>> btf_field_graph_root to btf_record is necessary? I think letting
> >>>>>> callers of btf_parse_fields() and btf_record_free() decide whether or
> >>>>>> not to change refcount should be enough. Besides, I personally would
> >>>>>> like to keep individual btf in btf_field_kptr and
> >>>>>> btf_field_graph_root, so that later we can have special fields
> >>>>>> referencing different btf.
> >>>>> Sorry, I didn't express the rough idea clearly enough. I didn't mean to
> >>>>> move btf of btf_field_kptr and btf_field_graph_root to btf_record,
> >>>>> because there are other btf-s which are different with the btf which
> >>>>> creates the struct_meta_tab. What I was trying to suggest is to save one
> >>>>> btf in btf_record and hope it will simplify the pin and the unpin of btf
> >>>>> in btf_record:
> >>>>>
> >>>>> 1) save the btf which owns the btf_record in btf_record.
> >>>>> 2) during btf_parse_kptr() or similar, if the used btf is the same as
> >>>>> the btf in btf_record, there is no need to pin the btf
> >>>> I assume the used btf is the one that btf_parse is working on.
> >>>>
> >>>>> 3) when freeing the btf_record, if the btf saved in btf_field is the
> >>>>> same as the btf in btf_record, there is no need to put it
> >>>> For btf_field_kptr.btf, is it the same as testing the btf_field_kptr.btf is
> >>>> btf_is_kernel() or not? How about only does btf_get/put for btf_is_kernel()?
> >>>>
> >>> IIUC. It will not be the same. For a map referencing prog btf, I
> >>> suppose we should still do btf_get().
> >>>
> >>> I think the core idea is since a btf_record and the prog btf
> >>> containing it has the same life time, we don't need to
> >>> btf_get()/btf_put() in btf_parse_kptr()/btf_record_free() when a
> >>> btf_field_kptr.btf is referencing itself.
> >>>
> >>> However, since btf_parse_kptr() called from btf_parse() and
> >>> map_check_btf() all use prog btf, we need a way to differentiate the
> >>> two. Hence Hou suggested saving the owner's btf in btf_record, and
> >> map_check_btf() calls btf_parse_kptr(map->btf).
> >>
> >> I am missing how it is different from the
> >> btf_new_fd()=>btf_parse()=>btf_parse_kptr(new_btf).
> >>
> >> akaik, the map->record has no issue now because bpf_map_free_deferred() does
> >> btf_record_free(map->record) before btf_put(map->btf). In the map->record case,
> >> does the map->record need to take a refcnt of the btf_field_kptr.btf if the
> >> btf_field_kptr.btf is pointing back to itself (map->btf) which is not a kernel btf?
>
> I think you are right. For both callees of btf_parse_kptr() when the btf
> saved in btf_field_kptr.btf is the same as the passed btf, there is no
> need to call btf_get(). For bpf map case, just as you remained, map->btf
> has already pin the btf passed to btf_parse_kptr() in map_create().
> >>> then check if btf_record->btf is the same as the btf_field_kptr.btf in
> >>> btf_parse_kptr()/btf_record_free().
> >> I suspect it will have the same end result? The btf_field_kptr.btf is only the
> >> same as the owner's btf when btf_parse_kptr() cannot found the kptr type from a
> >> kernel's btf (the id == -ENOENT case in btf_parse_kptr).
>
> It seems your suggestion of using btf_is_kernel() is much simpler:
>
> (1) btf_parse_kptr():  doesn't invoke btf_get() when bpf_find_btf_id()
> returns -ENOENT and let the caller ensure the life cycle of the passed btf.
> (2) btf_record_free(): only invoke btf_put() if the saved btf is a
> kernel btf.
> (3) btf_record_dup(): only invoke btf_get() if the saved btf is a kernel
> btf.

I see. It is much simpler. I will send a new version using this approach.

Thank you,
Amery

> > I added some code to better explain how I think it could work.
> >
> > I am thinking about adding a struct btf* under struct btf_record, and
> > then adding an argument in btf_parse_fields:
> >
> > btf_parse_fields(const struct btf *btf,..., bool btf_is_owner)
> > {
> >         ...
> >         /* Before the for loop that goes through info_arr */
> >         rec->btf = btf_is_owner ? btf : NULL;
> >         ...
> > }
> >
> > The btf_is_owner indicates whether the btf_record returned by the
> > function will be part of the btf. So map_check_btf() will set it to
> > false while btf_parse() will set it to true. Maybe "owner" is what
> > makes it confusing? (btf_record for a map belongs to bpf_map but not
> > map->btf. On the other hand, btf_record for a prog btf is part of it.)
> >
> > Then, in btf_record_free(), we can do:
> >
> > case BPF_KPTR_XXX:
> >         ...
> >         if (rec->btf != rec->fields[i].kptr.btf)
> >                 btf_put(rec->fields[i].kptr.btf);
> >
> > In btf_parse_kptr(), we also do similar things. We just need to pass
> > btf_record into it.
>





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux