Make btf_record_find() find the btf_field for an offset by comparing the offset with the offset of each element, rather than the offset of the entire array, if a btf_field represents an array. It is important to have support for btf_field arrays in the future. Signed-off-by: Kui-Feng Lee <thinker.li@xxxxxxxxx> --- kernel/bpf/syscall.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 543ff0d944e8..1a37731e632a 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -516,11 +516,18 @@ int bpf_map_alloc_pages(const struct bpf_map *map, gfp_t gfp, int nid, static int btf_field_cmp(const void *a, const void *b) { const struct btf_field *f1 = a, *f2 = b; + int gt = 1, lt = -1; + if (f2->nelems == 0) { + swap(f1, f2); + swap(gt, lt); + } if (f1->offset < f2->offset) - return -1; - else if (f1->offset > f2->offset) - return 1; + return lt; + else if (f1->offset >= f2->offset + f2->size) + return gt; + if ((f1->offset - f2->offset) % (f2->size / f2->nelems)) + return gt; return 0; } @@ -528,10 +535,14 @@ struct btf_field *btf_record_find(const struct btf_record *rec, u32 offset, u32 field_mask) { struct btf_field *field; + struct btf_field key = { + .offset = offset, + .size = 0, /* as a label for this key */ + }; if (IS_ERR_OR_NULL(rec) || !(rec->field_mask & field_mask)) return NULL; - field = bsearch(&offset, rec->fields, rec->cnt, sizeof(rec->fields[0]), btf_field_cmp); + field = bsearch(&key, rec->fields, rec->cnt, sizeof(rec->fields[0]), btf_field_cmp); if (!field || !(field->type & field_mask)) return NULL; return field; -- 2.34.1