Accept additional fields of a struct_ops type with all zero values even if these fields are not in the corresponding type in the kernel. This provides a way to be backward compatible. User space programs can use the same map on a machine running an old kernel by clearing fields that do not exist in the kernel. Signed-off-by: Kui-Feng Lee <thinker.li@xxxxxxxxx> --- tools/lib/bpf/libbpf.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index efab29b8935b..715879796046 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1131,11 +1131,33 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map) __u32 kern_member_idx; const char *mname; + mtype = skip_mods_and_typedefs(btf, member->type, &mtype_id); mname = btf__name_by_offset(btf, member->name_off); + moff = member->offset / 8; + mdata = data + moff; + msize = btf__resolve_size(btf, mtype_id); + if (msize < 0) { + pr_warn("struct_ops init_kern %s: fails to resolve the size of member %s\n", + map->name, mname); + return msize; + } + kern_member = find_member_by_name(kern_btf, kern_type, mname); if (!kern_member) { pr_warn("struct_ops init_kern %s: Cannot find member %s in kernel BTF\n", map->name, mname); + + /* Skip all zeros or null fields if they are not + * presented in the kernel BTF. + */ + if (btf_is_ptr(mtype)) { + if (!st_ops->progs[i]) + continue; + } else { + if (libbpf_is_mem_zeroed(mdata, msize)) + continue; + } + return -ENOTSUP; } @@ -1147,13 +1169,8 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map) return -ENOTSUP; } - moff = member->offset / 8; kern_moff = kern_member->offset / 8; - - mdata = data + moff; kern_mdata = kern_data + kern_moff; - - mtype = skip_mods_and_typedefs(btf, member->type, &mtype_id); kern_mtype = skip_mods_and_typedefs(kern_btf, kern_member->type, &kern_mtype_id); if (BTF_INFO_KIND(mtype->info) != @@ -1230,9 +1247,8 @@ static int bpf_map__init_kern_struct_ops(struct bpf_map *map) continue; } - msize = btf__resolve_size(btf, mtype_id); kern_msize = btf__resolve_size(kern_btf, kern_mtype_id); - if (msize < 0 || kern_msize < 0 || msize != kern_msize) { + if (kern_msize < 0 || msize != kern_msize) { pr_warn("struct_ops init_kern %s: Error in size of member %s: %zd != %zd(kernel)\n", map->name, mname, (ssize_t)msize, (ssize_t)kern_msize); -- 2.34.1