Skip to content

Commit d83caf7

Browse files
aspskAlexei Starovoitov
authored andcommitted
bpf: add btf_type_is_i{32,64} helpers
There are places in BPF code which check if a BTF type is an integer of particular size. This code can be made simpler by using helpers. Add new btf_type_is_i{32,64} helpers, and simplify code in a few files. (Suggested by Eduard for a patch which copy-pasted such a check [1].) v1 -> v2: * export less generic helpers (Eduard) * make subject less generic than in [v1] (Eduard) [1] https://lore.kernel.org/bpf/[email protected]/ [v1] https://lore.kernel.org/bpf/[email protected]/ Suggested-by: Eduard Zingerman <[email protected]> Signed-off-by: Anton Protopopov <[email protected]> Acked-by: Eduard Zingerman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 0ed5f79 commit d83caf7

File tree

5 files changed

+33
-38
lines changed

5 files changed

+33
-38
lines changed

include/linux/btf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,8 @@ bool btf_is_vmlinux(const struct btf *btf);
221221
struct module *btf_try_get_module(const struct btf *btf);
222222
u32 btf_nr_types(const struct btf *btf);
223223
struct btf *btf_base_btf(const struct btf *btf);
224+
bool btf_type_is_i32(const struct btf_type *t);
225+
bool btf_type_is_i64(const struct btf_type *t);
224226
bool btf_member_is_reg_int(const struct btf *btf, const struct btf_type *s,
225227
const struct btf_member *m,
226228
u32 expected_offset, u32 expected_size);

kernel/bpf/arraymap.c

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -530,8 +530,6 @@ static int array_map_check_btf(const struct bpf_map *map,
530530
const struct btf_type *key_type,
531531
const struct btf_type *value_type)
532532
{
533-
u32 int_data;
534-
535533
/* One exception for keyless BTF: .bss/.data/.rodata map */
536534
if (btf_type_is_void(key_type)) {
537535
if (map->map_type != BPF_MAP_TYPE_ARRAY ||
@@ -544,14 +542,11 @@ static int array_map_check_btf(const struct bpf_map *map,
544542
return 0;
545543
}
546544

547-
if (BTF_INFO_KIND(key_type->info) != BTF_KIND_INT)
548-
return -EINVAL;
549-
550-
int_data = *(u32 *)(key_type + 1);
551-
/* bpf array can only take a u32 key. This check makes sure
545+
/*
546+
* Bpf array can only take a u32 key. This check makes sure
552547
* that the btf matches the attr used during map_create.
553548
*/
554-
if (BTF_INT_BITS(int_data) != 32 || BTF_INT_OFFSET(int_data))
549+
if (!btf_type_is_i32(key_type))
555550
return -EINVAL;
556551

557552
return 0;

kernel/bpf/bpf_local_storage.c

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -722,13 +722,7 @@ int bpf_local_storage_map_check_btf(const struct bpf_map *map,
722722
const struct btf_type *key_type,
723723
const struct btf_type *value_type)
724724
{
725-
u32 int_data;
726-
727-
if (BTF_INFO_KIND(key_type->info) != BTF_KIND_INT)
728-
return -EINVAL;
729-
730-
int_data = *(u32 *)(key_type + 1);
731-
if (BTF_INT_BITS(int_data) != 32 || BTF_INT_OFFSET(int_data))
725+
if (!btf_type_is_i32(key_type))
732726
return -EINVAL;
733727

734728
return 0;

kernel/bpf/btf.c

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -858,26 +858,37 @@ const struct btf_type *btf_type_by_id(const struct btf *btf, u32 type_id)
858858
EXPORT_SYMBOL_GPL(btf_type_by_id);
859859

860860
/*
861-
* Regular int is not a bit field and it must be either
862-
* u8/u16/u32/u64 or __int128.
861+
* Check that the type @t is a regular int. This means that @t is not
862+
* a bit field and it has the same size as either of u8/u16/u32/u64
863+
* or __int128. If @expected_size is not zero, then size of @t should
864+
* be the same. A caller should already have checked that the type @t
865+
* is an integer.
863866
*/
867+
static bool __btf_type_int_is_regular(const struct btf_type *t, size_t expected_size)
868+
{
869+
u32 int_data = btf_type_int(t);
870+
u8 nr_bits = BTF_INT_BITS(int_data);
871+
u8 nr_bytes = BITS_ROUNDUP_BYTES(nr_bits);
872+
873+
return BITS_PER_BYTE_MASKED(nr_bits) == 0 &&
874+
BTF_INT_OFFSET(int_data) == 0 &&
875+
(nr_bytes <= 16 && is_power_of_2(nr_bytes)) &&
876+
(expected_size == 0 || nr_bytes == expected_size);
877+
}
878+
864879
static bool btf_type_int_is_regular(const struct btf_type *t)
865880
{
866-
u8 nr_bits, nr_bytes;
867-
u32 int_data;
881+
return __btf_type_int_is_regular(t, 0);
882+
}
868883

869-
int_data = btf_type_int(t);
870-
nr_bits = BTF_INT_BITS(int_data);
871-
nr_bytes = BITS_ROUNDUP_BYTES(nr_bits);
872-
if (BITS_PER_BYTE_MASKED(nr_bits) ||
873-
BTF_INT_OFFSET(int_data) ||
874-
(nr_bytes != sizeof(u8) && nr_bytes != sizeof(u16) &&
875-
nr_bytes != sizeof(u32) && nr_bytes != sizeof(u64) &&
876-
nr_bytes != (2 * sizeof(u64)))) {
877-
return false;
878-
}
884+
bool btf_type_is_i32(const struct btf_type *t)
885+
{
886+
return btf_type_is_int(t) && __btf_type_int_is_regular(t, 4);
887+
}
879888

880-
return true;
889+
bool btf_type_is_i64(const struct btf_type *t)
890+
{
891+
return btf_type_is_int(t) && __btf_type_int_is_regular(t, 8);
881892
}
882893

883894
/*

kernel/bpf/local_storage.c

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -394,17 +394,10 @@ static int cgroup_storage_check_btf(const struct bpf_map *map,
394394
if (!btf_member_is_reg_int(btf, key_type, m, offset, size))
395395
return -EINVAL;
396396
} else {
397-
u32 int_data;
398-
399397
/*
400398
* Key is expected to be u64, which stores the cgroup_inode_id
401399
*/
402-
403-
if (BTF_INFO_KIND(key_type->info) != BTF_KIND_INT)
404-
return -EINVAL;
405-
406-
int_data = *(u32 *)(key_type + 1);
407-
if (BTF_INT_BITS(int_data) != 64 || BTF_INT_OFFSET(int_data))
400+
if (!btf_type_is_i64(key_type))
408401
return -EINVAL;
409402
}
410403

0 commit comments

Comments
 (0)