bpf: refactor btf_find_struct_field() and btf_find_datasec_var().
authorKui-Feng Lee <thinker.li@gmail.com>
Thu, 23 May 2024 17:41:56 +0000 (10:41 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Tue, 4 Jun 2024 03:52:42 +0000 (20:52 -0700)
Move common code of the two functions to btf_find_field_one().

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Kui-Feng Lee <thinker.li@gmail.com>
Link: https://lore.kernel.org/r/20240523174202.461236-4-thinker.li@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/btf.c

index 226138b..2ce61c3 100644 (file)
@@ -3494,72 +3494,95 @@ end:
 
 #undef field_mask_test_name
 
+static int btf_find_field_one(const struct btf *btf,
+                             const struct btf_type *var,
+                             const struct btf_type *var_type,
+                             int var_idx,
+                             u32 off, u32 expected_size,
+                             u32 field_mask, u32 *seen_mask,
+                             struct btf_field_info *info, int info_cnt)
+{
+       int ret, align, sz, field_type;
+       struct btf_field_info tmp;
+
+       field_type = btf_get_field_type(__btf_name_by_offset(btf, var_type->name_off),
+                                       field_mask, seen_mask, &align, &sz);
+       if (field_type == 0)
+               return 0;
+       if (field_type < 0)
+               return field_type;
+
+       if (expected_size && expected_size != sz)
+               return 0;
+       if (off % align)
+               return 0;
+
+       switch (field_type) {
+       case BPF_SPIN_LOCK:
+       case BPF_TIMER:
+       case BPF_WORKQUEUE:
+       case BPF_LIST_NODE:
+       case BPF_RB_NODE:
+       case BPF_REFCOUNT:
+               ret = btf_find_struct(btf, var_type, off, sz, field_type,
+                                     info_cnt ? &info[0] : &tmp);
+               if (ret < 0)
+                       return ret;
+               break;
+       case BPF_KPTR_UNREF:
+       case BPF_KPTR_REF:
+       case BPF_KPTR_PERCPU:
+               ret = btf_find_kptr(btf, var_type, off, sz,
+                                   info_cnt ? &info[0] : &tmp);
+               if (ret < 0)
+                       return ret;
+               break;
+       case BPF_LIST_HEAD:
+       case BPF_RB_ROOT:
+               ret = btf_find_graph_root(btf, var, var_type,
+                                         var_idx, off, sz,
+                                         info_cnt ? &info[0] : &tmp,
+                                         field_type);
+               if (ret < 0)
+                       return ret;
+               break;
+       default:
+               return -EFAULT;
+       }
+
+       if (ret == BTF_FIELD_IGNORE)
+               return 0;
+       if (!info_cnt)
+               return -E2BIG;
+
+       return 1;
+}
+
 static int btf_find_struct_field(const struct btf *btf,
                                 const struct btf_type *t, u32 field_mask,
                                 struct btf_field_info *info, int info_cnt)
 {
-       int ret, idx = 0, align, sz, field_type;
+       int ret, idx = 0;
        const struct btf_member *member;
-       struct btf_field_info tmp;
        u32 i, off, seen_mask = 0;
 
        for_each_member(i, t, member) {
                const struct btf_type *member_type = btf_type_by_id(btf,
                                                                    member->type);
 
-               field_type = btf_get_field_type(__btf_name_by_offset(btf, member_type->name_off),
-                                               field_mask, &seen_mask, &align, &sz);
-               if (field_type == 0)
-                       continue;
-               if (field_type < 0)
-                       return field_type;
-
                off = __btf_member_bit_offset(t, member);
                if (off % 8)
                        /* valid C code cannot generate such BTF */
                        return -EINVAL;
                off /= 8;
-               if (off % align)
-                       continue;
-
-               switch (field_type) {
-               case BPF_SPIN_LOCK:
-               case BPF_TIMER:
-               case BPF_WORKQUEUE:
-               case BPF_LIST_NODE:
-               case BPF_RB_NODE:
-               case BPF_REFCOUNT:
-                       ret = btf_find_struct(btf, member_type, off, sz, field_type,
-                                             idx < info_cnt ? &info[idx] : &tmp);
-                       if (ret < 0)
-                               return ret;
-                       break;
-               case BPF_KPTR_UNREF:
-               case BPF_KPTR_REF:
-               case BPF_KPTR_PERCPU:
-                       ret = btf_find_kptr(btf, member_type, off, sz,
-                                           idx < info_cnt ? &info[idx] : &tmp);
-                       if (ret < 0)
-                               return ret;
-                       break;
-               case BPF_LIST_HEAD:
-               case BPF_RB_ROOT:
-                       ret = btf_find_graph_root(btf, t, member_type,
-                                                 i, off, sz,
-                                                 idx < info_cnt ? &info[idx] : &tmp,
-                                                 field_type);
-                       if (ret < 0)
-                               return ret;
-                       break;
-               default:
-                       return -EFAULT;
-               }
 
-               if (ret == BTF_FIELD_IGNORE)
-                       continue;
-               if (idx >= info_cnt)
-                       return -E2BIG;
-               ++idx;
+               ret = btf_find_field_one(btf, t, member_type, i,
+                                        off, 0,
+                                        field_mask, &seen_mask,
+                                        &info[idx], info_cnt - idx);
+               if (ret < 0)
+                       return ret;
+               idx += ret;
        }
        return idx;
 }
@@ -3568,66 +3591,21 @@ static int btf_find_datasec_var(const struct btf *btf, const struct btf_type *t,
                                u32 field_mask, struct btf_field_info *info,
                                int info_cnt)
 {
-       int ret, idx = 0, align, sz, field_type;
+       int ret, idx = 0;
        const struct btf_var_secinfo *vsi;
-       struct btf_field_info tmp;
        u32 i, off, seen_mask = 0;
 
        for_each_vsi(i, t, vsi) {
                const struct btf_type *var = btf_type_by_id(btf, vsi->type);
                const struct btf_type *var_type = btf_type_by_id(btf, var->type);
 
-               field_type = btf_get_field_type(__btf_name_by_offset(btf, var_type->name_off),
-                                               field_mask, &seen_mask, &align, &sz);
-               if (field_type == 0)
-                       continue;
-               if (field_type < 0)
-                       return field_type;
-
                off = vsi->offset;
-               if (vsi->size != sz)
-                       continue;
-               if (off % align)
-                       continue;
-
-               switch (field_type) {
-               case BPF_SPIN_LOCK:
-               case BPF_TIMER:
-               case BPF_WORKQUEUE:
-               case BPF_LIST_NODE:
-               case BPF_RB_NODE:
-               case BPF_REFCOUNT:
-                       ret = btf_find_struct(btf, var_type, off, sz, field_type,
-                                             idx < info_cnt ? &info[idx] : &tmp);
-                       if (ret < 0)
-                               return ret;
-                       break;
-               case BPF_KPTR_UNREF:
-               case BPF_KPTR_REF:
-               case BPF_KPTR_PERCPU:
-                       ret = btf_find_kptr(btf, var_type, off, sz,
-                                           idx < info_cnt ? &info[idx] : &tmp);
-                       if (ret < 0)
-                               return ret;
-                       break;
-               case BPF_LIST_HEAD:
-               case BPF_RB_ROOT:
-                       ret = btf_find_graph_root(btf, var, var_type,
-                                                 -1, off, sz,
-                                                 idx < info_cnt ? &info[idx] : &tmp,
-                                                 field_type);
-                       if (ret < 0)
-                               return ret;
-                       break;
-               default:
-                       return -EFAULT;
-               }
-
-               if (ret == BTF_FIELD_IGNORE)
-                       continue;
-               if (idx >= info_cnt)
-                       return -E2BIG;
-               ++idx;
+               ret = btf_find_field_one(btf, var, var_type, -1, off, vsi->size,
+                                        field_mask, &seen_mask,
+                                        &info[idx], info_cnt - idx);
+               if (ret < 0)
+                       return ret;
+               idx += ret;
        }
        return idx;
 }