|
192 | 192 | */ |
193 | 193 | #define BTF_MAX_SIZE (16 * 1024 * 1024) |
194 | 194 |
|
| 195 | +#define BTF_NEED_SORT_CHECK ((u32)-1) |
| 196 | + |
195 | 197 | #define for_each_member_from(i, from, struct_type, member) \ |
196 | 198 | for (i = from, member = btf_type_member(struct_type) + from; \ |
197 | 199 | i < btf_type_vlen(struct_type); \ |
@@ -259,6 +261,7 @@ struct btf { |
259 | 261 | void *nohdr_data; |
260 | 262 | struct btf_header hdr; |
261 | 263 | u32 nr_types; /* includes VOID for base BTF */ |
| 264 | + u32 nr_sorted_types; /* exclude VOID for base BTF */ |
262 | 265 | u32 types_size; |
263 | 266 | u32 data_size; |
264 | 267 | refcount_t refcnt; |
@@ -494,6 +497,11 @@ static bool btf_type_is_modifier(const struct btf_type *t) |
494 | 497 | return false; |
495 | 498 | } |
496 | 499 |
|
| 500 | +static int btf_start_id(const struct btf *btf) |
| 501 | +{ |
| 502 | + return btf->start_id + (btf->base_btf ? 0 : 1); |
| 503 | +} |
| 504 | + |
497 | 505 | bool btf_type_is_void(const struct btf_type *t) |
498 | 506 | { |
499 | 507 | return t == &btf_void; |
@@ -544,24 +552,110 @@ u32 btf_nr_types(const struct btf *btf) |
544 | 552 | return total; |
545 | 553 | } |
546 | 554 |
|
| 555 | +/* Performs binary search within specified type ID range to find the leftmost |
| 556 | + * BTF type matching the given name. The search assumes types are sorted by |
| 557 | + * name in lexicographical order within the specified range. |
| 558 | + * |
| 559 | + * Return: Type ID of leftmost matching type, or -ENOENT if not found |
| 560 | + */ |
| 561 | +static s32 btf_find_by_name_kind_bsearch(const struct btf *btf, const char *name, |
| 562 | + s32 start_id, s32 end_id) |
| 563 | +{ |
| 564 | + const struct btf_type *t; |
| 565 | + const char *tname; |
| 566 | + s32 l, r, m, lmost = -ENOENT; |
| 567 | + int ret; |
| 568 | + |
| 569 | + l = start_id; |
| 570 | + r = end_id; |
| 571 | + while (l <= r) { |
| 572 | + m = l + (r - l) / 2; |
| 573 | + t = btf_type_by_id(btf, m); |
| 574 | + tname = btf_name_by_offset(btf, t->name_off); |
| 575 | + ret = strcmp(tname, name); |
| 576 | + if (ret < 0) { |
| 577 | + l = m + 1; |
| 578 | + } else { |
| 579 | + if (ret == 0) |
| 580 | + lmost = m; |
| 581 | + r = m - 1; |
| 582 | + } |
| 583 | + } |
| 584 | + |
| 585 | + return lmost; |
| 586 | +} |
| 587 | + |
| 588 | +/* Searches for a BTF type with the specified name and kind. The function |
| 589 | + * first recursively searches in the base BTF (if present), then searches |
| 590 | + * in the current BTF using either binary search (if types are sorted) |
| 591 | + * or linear search. |
| 592 | + * |
| 593 | + * Binary search is used when types are name-sorted (nr_sorted_types > 0). |
| 594 | + * After finding a name match, it scans forward to find the first type |
| 595 | + * that also matches the specified kind. Linear search is used for unsorted |
| 596 | + * types, checking each type sequentially. |
| 597 | + * |
| 598 | + * Return: Type ID of matching type on success, -ENOENT if not found |
| 599 | + */ |
547 | 600 | s32 btf_find_by_name_kind(const struct btf *btf, const char *name, u8 kind) |
548 | 601 | { |
| 602 | + const struct btf *base_btf = btf_base_btf(btf);; |
549 | 603 | const struct btf_type *t; |
550 | 604 | const char *tname; |
551 | | - u32 i, total; |
| 605 | + int err = -ENOENT; |
552 | 606 |
|
553 | | - total = btf_nr_types(btf); |
554 | | - for (i = 1; i < total; i++) { |
555 | | - t = btf_type_by_id(btf, i); |
556 | | - if (BTF_INFO_KIND(t->info) != kind) |
557 | | - continue; |
| 607 | + if (base_btf) { |
| 608 | + err = btf_find_by_name_kind(base_btf, name, kind); |
| 609 | + if (err > 0) |
| 610 | + goto out; |
| 611 | + } |
558 | 612 |
|
559 | | - tname = btf_name_by_offset(btf, t->name_off); |
560 | | - if (!strcmp(tname, name)) |
561 | | - return i; |
| 613 | + if (btf->nr_sorted_types != BTF_NEED_SORT_CHECK) { |
| 614 | + /* binary search */ |
| 615 | + bool skip_first; |
| 616 | + s32 start_id, end_id;; |
| 617 | + int ret; |
| 618 | + |
| 619 | + start_id = btf_start_id(btf); |
| 620 | + end_id = start_id + btf->nr_sorted_types - 1; |
| 621 | + ret = btf_find_by_name_kind_bsearch(btf, name, start_id, end_id); |
| 622 | + if (ret < 0) |
| 623 | + goto out; |
| 624 | + skip_first = true; |
| 625 | + do { |
| 626 | + t = btf_type_by_id(btf, ret); |
| 627 | + if (BTF_INFO_KIND(t->info) != kind) { |
| 628 | + if (skip_first) { |
| 629 | + skip_first = false; |
| 630 | + continue; |
| 631 | + } |
| 632 | + } else if (skip_first) { |
| 633 | + return ret; |
| 634 | + } |
| 635 | + tname = btf_name_by_offset(btf, t->name_off); |
| 636 | + if (!strcmp(tname, name)) |
| 637 | + return ret; |
| 638 | + else |
| 639 | + break; |
| 640 | + } while (++ret <= end_id); |
| 641 | + } else { |
| 642 | + /* linear search */ |
| 643 | + u32 i, total; |
| 644 | + |
| 645 | + total = btf_nr_types(btf); |
| 646 | + for (i = btf_start_id(btf); i < total; i++) { |
| 647 | + t = btf_type_by_id(btf, i); |
| 648 | + if (BTF_INFO_KIND(t->info) != kind) |
| 649 | + continue; |
| 650 | + |
| 651 | + tname = btf_name_by_offset(btf, t->name_off); |
| 652 | + if (!strcmp(tname, name)) |
| 653 | + return i; |
| 654 | + } |
562 | 655 | } |
563 | 656 |
|
564 | | - return -ENOENT; |
| 657 | +out: |
| 658 | + return err; |
565 | 659 | } |
566 | 660 |
|
567 | 661 | s32 bpf_find_btf_id(const char *name, u32 kind, struct btf **btf_p) |
@@ -5791,6 +5885,7 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uat |
5791 | 5885 | goto errout; |
5792 | 5886 | } |
5793 | 5887 | env->btf = btf; |
| 5888 | + btf->nr_sorted_types = BTF_NEED_SORT_CHECK; |
5794 | 5889 |
|
5795 | 5890 | data = kvmalloc(attr->btf_size, GFP_KERNEL | __GFP_NOWARN); |
5796 | 5891 | if (!data) { |
@@ -6210,6 +6305,7 @@ static struct btf *btf_parse_base(struct btf_verifier_env *env, const char *name |
6210 | 6305 | btf->data = data; |
6211 | 6306 | btf->data_size = data_size; |
6212 | 6307 | btf->kernel_btf = true; |
| 6308 | + btf->nr_sorted_types = BTF_NEED_SORT_CHECK; |
6213 | 6309 | snprintf(btf->name, sizeof(btf->name), "%s", name); |
6214 | 6310 |
|
6215 | 6311 | err = btf_parse_hdr(env); |
@@ -6327,6 +6423,7 @@ static struct btf *btf_parse_module(const char *module_name, const void *data, |
6327 | 6423 | btf->start_id = base_btf->nr_types; |
6328 | 6424 | btf->start_str_off = base_btf->hdr.str_len; |
6329 | 6425 | btf->kernel_btf = true; |
| 6426 | + btf->nr_sorted_types = BTF_NEED_SORT_CHECK; |
6330 | 6427 | snprintf(btf->name, sizeof(btf->name), "%s", module_name); |
6331 | 6428 |
|
6332 | 6429 | btf->data = kvmemdup(data, data_size, GFP_KERNEL | __GFP_NOWARN); |
|
0 commit comments