Commit cd70182e authored by Alexei Starovoitov's avatar Alexei Starovoitov

Merge branch 'fix-fwd-enum-resolution'

Andrii Nakryiko says:

====================
This patchset adds ability to resolve forward-declared enums into their
corresponding full enum definition types during type deduplication,
eliminating one of the reasons for having duplicated graphs of types.
====================
Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
parents f48a9205 8fd7a61a
...@@ -1602,16 +1602,12 @@ static bool btf_equal_int(struct btf_type *t1, struct btf_type *t2) ...@@ -1602,16 +1602,12 @@ static bool btf_equal_int(struct btf_type *t1, struct btf_type *t2)
/* Calculate type signature hash of ENUM. */ /* Calculate type signature hash of ENUM. */
static __u32 btf_hash_enum(struct btf_type *t) static __u32 btf_hash_enum(struct btf_type *t)
{ {
struct btf_enum *member = (struct btf_enum *)(t + 1); __u32 h;
__u32 vlen = BTF_INFO_VLEN(t->info);
__u32 h = btf_hash_common(t);
int i;
for (i = 0; i < vlen; i++) { /* don't hash vlen and enum members to support enum fwd resolving */
h = hash_combine(h, member->name_off); h = hash_combine(0, t->name_off);
h = hash_combine(h, member->val); h = hash_combine(h, t->info & ~0xffff);
member++; h = hash_combine(h, t->size);
}
return h; return h;
} }
...@@ -1637,6 +1633,22 @@ static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2) ...@@ -1637,6 +1633,22 @@ static bool btf_equal_enum(struct btf_type *t1, struct btf_type *t2)
return true; return true;
} }
static inline bool btf_is_enum_fwd(struct btf_type *t)
{
return BTF_INFO_KIND(t->info) == BTF_KIND_ENUM &&
BTF_INFO_VLEN(t->info) == 0;
}
static bool btf_compat_enum(struct btf_type *t1, struct btf_type *t2)
{
if (!btf_is_enum_fwd(t1) && !btf_is_enum_fwd(t2))
return btf_equal_enum(t1, t2);
/* ignore vlen when comparing */
return t1->name_off == t2->name_off &&
(t1->info & ~0xffff) == (t2->info & ~0xffff) &&
t1->size == t2->size;
}
/* /*
* Calculate type signature hash of STRUCT/UNION, ignoring referenced type IDs, * Calculate type signature hash of STRUCT/UNION, ignoring referenced type IDs,
* as referenced type IDs equivalence is established separately during type * as referenced type IDs equivalence is established separately during type
...@@ -1860,6 +1872,17 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id) ...@@ -1860,6 +1872,17 @@ static int btf_dedup_prim_type(struct btf_dedup *d, __u32 type_id)
new_id = cand_node->type_id; new_id = cand_node->type_id;
break; break;
} }
if (d->opts.dont_resolve_fwds)
continue;
if (btf_compat_enum(t, cand)) {
if (btf_is_enum_fwd(t)) {
/* resolve fwd to full enum */
new_id = cand_node->type_id;
break;
}
/* resolve canonical enum fwd to full enum */
d->map[cand_node->type_id] = type_id;
}
} }
break; break;
...@@ -2084,15 +2107,15 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id, ...@@ -2084,15 +2107,15 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
return fwd_kind == real_kind; return fwd_kind == real_kind;
} }
if (cand_type->info != canon_type->info)
return 0;
switch (cand_kind) { switch (cand_kind) {
case BTF_KIND_INT: case BTF_KIND_INT:
return btf_equal_int(cand_type, canon_type); return btf_equal_int(cand_type, canon_type);
case BTF_KIND_ENUM: case BTF_KIND_ENUM:
return btf_equal_enum(cand_type, canon_type); if (d->opts.dont_resolve_fwds)
return btf_equal_enum(cand_type, canon_type);
else
return btf_compat_enum(cand_type, canon_type);
case BTF_KIND_FWD: case BTF_KIND_FWD:
return btf_equal_common(cand_type, canon_type); return btf_equal_common(cand_type, canon_type);
...@@ -2103,6 +2126,8 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id, ...@@ -2103,6 +2126,8 @@ static int btf_dedup_is_equiv(struct btf_dedup *d, __u32 cand_id,
case BTF_KIND_PTR: case BTF_KIND_PTR:
case BTF_KIND_TYPEDEF: case BTF_KIND_TYPEDEF:
case BTF_KIND_FUNC: case BTF_KIND_FUNC:
if (cand_type->info != canon_type->info)
return 0;
return btf_dedup_is_equiv(d, cand_type->type, canon_type->type); return btf_dedup_is_equiv(d, cand_type->type, canon_type->type);
case BTF_KIND_ARRAY: { case BTF_KIND_ARRAY: {
......
...@@ -5874,6 +5874,50 @@ const struct btf_dedup_test dedup_tests[] = { ...@@ -5874,6 +5874,50 @@ const struct btf_dedup_test dedup_tests[] = {
.dont_resolve_fwds = false, .dont_resolve_fwds = false,
}, },
}, },
{
.descr = "dedup: enum fwd resolution",
.input = {
.raw_types = {
/* [1] fwd enum 'e1' before full enum */
BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM, 0, 0), 4),
/* [2] full enum 'e1' after fwd */
BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4),
BTF_ENUM_ENC(NAME_NTH(2), 123),
/* [3] full enum 'e2' before fwd */
BTF_TYPE_ENC(NAME_NTH(3), BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4),
BTF_ENUM_ENC(NAME_NTH(4), 456),
/* [4] fwd enum 'e2' after full enum */
BTF_TYPE_ENC(NAME_NTH(3), BTF_INFO_ENC(BTF_KIND_ENUM, 0, 0), 4),
/* [5] incompatible fwd enum with different size */
BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM, 0, 0), 1),
/* [6] incompatible full enum with different value */
BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4),
BTF_ENUM_ENC(NAME_NTH(2), 321),
BTF_END_RAW,
},
BTF_STR_SEC("\0e1\0e1_val\0e2\0e2_val"),
},
.expect = {
.raw_types = {
/* [1] full enum 'e1' */
BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4),
BTF_ENUM_ENC(NAME_NTH(2), 123),
/* [2] full enum 'e2' */
BTF_TYPE_ENC(NAME_NTH(3), BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4),
BTF_ENUM_ENC(NAME_NTH(4), 456),
/* [3] incompatible fwd enum with different size */
BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM, 0, 0), 1),
/* [4] incompatible full enum with different value */
BTF_TYPE_ENC(NAME_NTH(1), BTF_INFO_ENC(BTF_KIND_ENUM, 0, 1), 4),
BTF_ENUM_ENC(NAME_NTH(2), 321),
BTF_END_RAW,
},
BTF_STR_SEC("\0e1\0e1_val\0e2\0e2_val"),
},
.opts = {
.dont_resolve_fwds = false,
},
},
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment