On Fri, Dec 07, 2018 at 07:37:35PM -0800, Yonghong Song wrote: > > > On 12/7/18 4:53 PM, Roman Gushchin wrote: > > Implement bpffs pretty printing for cgroup local storage maps > > (both shared and per-cpu). > > Output example (captured for tools/testing/selftests/bpf/netcnt_prog.c): > > > > Shared: > > $ cat /sys/fs/bpf/map_2 > > # WARNING!! The output is for debug purpose only > > # WARNING!! The output format will change > > {4294968594,1}: {9999,1039896} > > > > Per-cpu: > > $ cat /sys/fs/bpf/map_1 > > # WARNING!! The output is for debug purpose only > > # WARNING!! The output format will change > > {4294968594,1}: { > > cpu0: {0,0,0,0,0} > > cpu1: {0,0,0,0,0} > > cpu2: {1,104,0,0,0} > > cpu3: {0,0,0,0,0} > > } > > > > Signed-off-by: Roman Gushchin <g...@fb.com> > > Cc: Alexei Starovoitov <a...@kernel.org> > > Cc: Daniel Borkmann <dan...@iogearbox.net> > > --- > > include/linux/btf.h | 10 +++++ > > kernel/bpf/local_storage.c | 90 +++++++++++++++++++++++++++++++++++++- > > 2 files changed, 99 insertions(+), 1 deletion(-) > > > > diff --git a/include/linux/btf.h b/include/linux/btf.h > > index 8c2199b5d250..ac67bc4cbfd9 100644 > > --- a/include/linux/btf.h > > +++ b/include/linux/btf.h > > @@ -5,6 +5,7 @@ > > #define _LINUX_BTF_H 1 > > > > #include <linux/types.h> > > +#include <uapi/linux/btf.h> > > > > struct btf; > > struct btf_type; > > @@ -63,4 +64,13 @@ static inline const char *btf_name_by_offset(const > > struct btf *btf, > > } > > #endif > > > > +static inline const struct btf_type *btf_orig_type(const struct btf *btf, > > + const struct btf_type *t) > > +{ > > + while (t && BTF_INFO_KIND(t->info) == BTF_KIND_TYPEDEF) > > + t = btf_type_by_id(btf, t->type); > technically, type modifier "const" and "volatile" can apply to member > type as well. But these modifiers really don't make sense here. > Could you add a comment here to mention that they will be treated > as an error since such a programming is not really recommended?
Switched over to btf_type_id_size() based on Martin's suggestion. > > > + > > + return t; > > +} > > + > > #endif > > diff --git a/kernel/bpf/local_storage.c b/kernel/bpf/local_storage.c > > index b65017dead44..7b51fe1aba3c 100644 > > --- a/kernel/bpf/local_storage.c > > +++ b/kernel/bpf/local_storage.c > > @@ -1,11 +1,13 @@ > > //SPDX-License-Identifier: GPL-2.0 > > #include <linux/bpf-cgroup.h> > > #include <linux/bpf.h> > > +#include <linux/btf.h> > > #include <linux/bug.h> > > #include <linux/filter.h> > > #include <linux/mm.h> > > #include <linux/rbtree.h> > > #include <linux/slab.h> > > +#include <uapi/linux/btf.h> > > > > DEFINE_PER_CPU(struct bpf_cgroup_storage*, > > bpf_cgroup_storage[MAX_BPF_CGROUP_STORAGE_TYPE]); > > > > @@ -308,6 +310,91 @@ static int cgroup_storage_delete_elem(struct bpf_map > > *map, void *key) > > return -EINVAL; > > } > > > > +static int cgroup_storage_check_btf(const struct bpf_map *map, > > + const struct btf *btf, > > + const struct btf_type *key_type, > > + const struct btf_type *value_type) > > +{ > > + const struct btf_type *st, *t; > > + struct btf_member *m; > > + > > + /* Key is expected to be of struct bpf_cgroup_storage_key type, > > + * which is: > > + * struct bpf_cgroup_storage_key { > > + * __u64 cgroup_inode_id; > > + * __u32 attach_type; > > + * }; > > + */ > > + > > + /* > > + * Key_type must be a structure (or a typedef of a structure) with > > + * two members. > > + */ > > + st = btf_orig_type(btf, key_type); > > + if (BTF_INFO_KIND(st->info) != BTF_KIND_STRUCT || > > + BTF_INFO_VLEN(st->info) != 2) > > + return -EINVAL; > > + > > + /* > > + * The first field must be a 64 bit integer at 0 offset. > > + */ > > + m = (struct btf_member *)(st + 1); > > + t = btf_orig_type(btf, btf_type_by_id(btf, m->type)); > > + if (!t || BTF_INFO_KIND(t->info) != BTF_KIND_INT || m->offset || > > + t->size != > > + FIELD_SIZEOF(struct bpf_cgroup_storage_key, cgroup_inode_id)) > > + return -EINVAL; > > We should not use t->size here. The "t->size" is the type size, and the > real number of bits held by the member is BTF_INT_BITS(...) with the > argument of the u32 int value after "t". > > > + > > + /* > > + * The second field must be a 32 bit integer at 0 offset. > > + */ > > + m = m + 1; > > + t = btf_orig_type(btf, btf_type_by_id(btf, m->type)); > > + if (!t || BTF_INFO_KIND(t->info) != BTF_KIND_INT || > > + m->offset != offsetof(struct bpf_cgroup_storage_key, attach_type) * > > + BITS_PER_BYTE || t->size != > > + FIELD_SIZEOF(struct bpf_cgroup_storage_key, attach_type)) > > + return -EINVAL; > > The same is here. t->size should not be used. > BTF_INT_BITS(...) should be used. Fixed in v2, which I'll send soon. Thank you for the review!