> On Nov 10, 2020, at 10:31 AM, Andrii Nakryiko <andrii.nakryiko@xxxxxxxxx> wrote: > > On Tue, Nov 10, 2020 at 9:50 AM Song Liu <songliubraving@xxxxxx> wrote: >> >> >> >>> On Nov 9, 2020, at 5:19 PM, Andrii Nakryiko <andrii@xxxxxxxxxx> wrote: >>> >>> Adjust in-kernel BTF implementation to support a split BTF mode of operation. >>> Changes are mostly mirroring libbpf split BTF changes, with the exception of >>> start_id being 0 for in-kernel implementation due to simpler read-only mode. >>> >>> Otherwise, for split BTF logic, most of the logic of jumping to base BTF, >>> where necessary, is encapsulated in few helper functions. Type numbering and >>> string offset in a split BTF are logically continuing where base BTF ends, so >>> most of the high-level logic is kept without changes. >>> >>> Type verification and size resolution is only doing an added resolution of new >>> split BTF types and relies on already cached size and type resolution results >>> in the base BTF. >>> >>> Signed-off-by: Andrii Nakryiko <andrii@xxxxxxxxxx> >>> --- >>> kernel/bpf/btf.c | 171 +++++++++++++++++++++++++++++++++-------------- >>> 1 file changed, 119 insertions(+), 52 deletions(-) >>> >>> diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c >>> index 6324de8c59f7..727c1c27053f 100644 >>> --- a/kernel/bpf/btf.c >>> +++ b/kernel/bpf/btf.c >>> @@ -203,12 +203,17 @@ struct btf { >>> const char *strings; >>> void *nohdr_data; >>> struct btf_header hdr; >>> - u32 nr_types; >>> + u32 nr_types; /* includes VOID for base BTF */ >>> u32 types_size; >>> u32 data_size; >>> refcount_t refcnt; >>> u32 id; >>> struct rcu_head rcu; >>> + >>> + /* split BTF support */ >>> + struct btf *base_btf; >>> + u32 start_id; /* first type ID in this BTF (0 for base BTF) */ >>> + u32 start_str_off; /* first string offset (0 for base BTF) */ >>> }; >>> >>> enum verifier_phase { >>> @@ -449,14 +454,27 @@ static bool btf_type_is_datasec(const struct btf_type *t) >>> return BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC; >>> } >>> >>> +static u32 btf_nr_types_total(const struct btf *btf) >>> +{ >>> + u32 total = 0; >>> + >>> + while (btf) { >>> + total += btf->nr_types; >>> + btf = btf->base_btf; >>> + } >>> + >>> + return total; >>> +} >>> + >>> s32 btf_find_by_name_kind(const struct btf *btf, const char *name, u8 kind) >>> { >>> const struct btf_type *t; >>> const char *tname; >>> - u32 i; >>> + u32 i, total; >>> >>> - for (i = 1; i <= btf->nr_types; i++) { >>> - t = btf->types[i]; >>> + total = btf_nr_types_total(btf); >>> + for (i = 1; i < total; i++) { >>> + t = btf_type_by_id(btf, i); >>> if (BTF_INFO_KIND(t->info) != kind) >>> continue; >>> >>> @@ -599,8 +617,14 @@ static const struct btf_kind_operations *btf_type_ops(const struct btf_type *t) >>> >>> static bool btf_name_offset_valid(const struct btf *btf, u32 offset) >>> { >>> - return BTF_STR_OFFSET_VALID(offset) && >>> - offset < btf->hdr.str_len; >>> + if (!BTF_STR_OFFSET_VALID(offset)) >>> + return false; >>> + >>> + while (offset < btf->start_str_off) >>> + btf = btf->base_btf; >> >> Do we need "if (!btf) return false;" in the while loop? (and some other loops below) > > No, because for base btf start_str_off and start_type_id are always > zero, so loop condition is always false. Ah, I misread the code. Thanks for the explanation. Acked-by: Song Liu <songliubraving@xxxxxx>