Skip to content

Commit

Permalink
Merge branch 'bpf-volatile-compare'
Browse files Browse the repository at this point in the history
Alexei Starovoitov says:

====================
bpf: volatile compare

From: Alexei Starovoitov <ast@kernel.org>

v2->v3:
Debugged profiler.c regression. It was caused by basic block layout.
Introduce bpf_cmp_likely() and bpf_cmp_unlikely() macros.
Debugged redundant <<=32, >>=32 with u32 variables. Added cast workaround.

v1->v2:
Fixed issues pointed out by Daniel, added more tests, attempted to convert profiler.c,
but barrier_var() wins vs bpf_cmp(). To be investigated.
Patches 1-4 are good to go, but 5 needs more work.
====================

Link: https://lore.kernel.org/r/20231226191148.48536-1-alexei.starovoitov@gmail.com
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
  • Loading branch information
anakryiko committed Jan 3, 2024
2 parents a640de4 + 7e3811c commit b456005
Show file tree
Hide file tree
Showing 29 changed files with 171 additions and 275 deletions.
1 change: 1 addition & 0 deletions tools/testing/selftests/bpf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ CLANG_SYS_INCLUDES = $(call get_sys_includes,$(CLANG),$(CLANG_TARGET_ARCH))
BPF_CFLAGS = -g -Wall -Werror -D__TARGET_ARCH_$(SRCARCH) $(MENDIAN) \
-I$(INCLUDE_DIR) -I$(CURDIR) -I$(APIDIR) \
-I$(abspath $(OUTPUT)/../usr/include)
# TODO: enable me -Wsign-compare

CLANG_CFLAGS = $(CLANG_SYS_INCLUDES) \
-Wno-compare-distinct-pointer-types
Expand Down
220 changes: 72 additions & 148 deletions tools/testing/selftests/bpf/bpf_experimental.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,173 +254,97 @@ extern void bpf_throw(u64 cookie) __ksym;
} \
})

/* Description
* Assert that a conditional expression is true.
* Returns
* Void.
* Throws
* An exception with the value zero when the assertion fails.
*/
#define bpf_assert(cond) if (!(cond)) bpf_throw(0);

/* Description
* Assert that a conditional expression is true.
* Returns
* Void.
* Throws
* An exception with the specified value when the assertion fails.
*/
#define bpf_assert_with(cond, value) if (!(cond)) bpf_throw(value);

/* Description
* Assert that LHS is equal to RHS. This statement updates the known value
* of LHS during verification. Note that RHS must be a constant value, and
* must fit within the data type of LHS.
* Returns
* Void.
* Throws
* An exception with the value zero when the assertion fails.
*/
#define bpf_assert_eq(LHS, RHS) \
({ \
barrier_var(LHS); \
__bpf_assert_op(LHS, ==, RHS, 0, true); \
})

/* Description
* Assert that LHS is equal to RHS. This statement updates the known value
* of LHS during verification. Note that RHS must be a constant value, and
* must fit within the data type of LHS.
* Returns
* Void.
* Throws
* An exception with the specified value when the assertion fails.
*/
#define bpf_assert_eq_with(LHS, RHS, value) \
({ \
barrier_var(LHS); \
__bpf_assert_op(LHS, ==, RHS, value, true); \
})

/* Description
* Assert that LHS is less than RHS. This statement updates the known
* bounds of LHS during verification. Note that RHS must be a constant
* value, and must fit within the data type of LHS.
* Returns
* Void.
* Throws
* An exception with the value zero when the assertion fails.
*/
#define bpf_assert_lt(LHS, RHS) \
({ \
barrier_var(LHS); \
__bpf_assert_op(LHS, <, RHS, 0, false); \
})

/* Description
* Assert that LHS is less than RHS. This statement updates the known
* bounds of LHS during verification. Note that RHS must be a constant
* value, and must fit within the data type of LHS.
* Returns
* Void.
* Throws
* An exception with the specified value when the assertion fails.
*/
#define bpf_assert_lt_with(LHS, RHS, value) \
({ \
barrier_var(LHS); \
__bpf_assert_op(LHS, <, RHS, value, false); \
})
#define __cmp_cannot_be_signed(x) \
__builtin_strcmp(#x, "==") == 0 || __builtin_strcmp(#x, "!=") == 0 || \
__builtin_strcmp(#x, "&") == 0

/* Description
* Assert that LHS is greater than RHS. This statement updates the known
* bounds of LHS during verification. Note that RHS must be a constant
* value, and must fit within the data type of LHS.
* Returns
* Void.
* Throws
* An exception with the value zero when the assertion fails.
*/
#define bpf_assert_gt(LHS, RHS) \
({ \
barrier_var(LHS); \
__bpf_assert_op(LHS, >, RHS, 0, false); \
})
#define __is_signed_type(type) (((type)(-1)) < (type)1)

/* Description
* Assert that LHS is greater than RHS. This statement updates the known
* bounds of LHS during verification. Note that RHS must be a constant
* value, and must fit within the data type of LHS.
* Returns
* Void.
* Throws
* An exception with the specified value when the assertion fails.
#define __bpf_cmp(LHS, OP, SIGN, PRED, RHS, DEFAULT) \
({ \
__label__ l_true; \
bool ret = DEFAULT; \
asm volatile goto("if %[lhs] " SIGN #OP " %[rhs] goto %l[l_true]" \
:: [lhs] "r"((short)LHS), [rhs] PRED (RHS) :: l_true); \
ret = !DEFAULT; \
l_true: \
ret; \
})

/* C type conversions coupled with comparison operator are tricky.
* Make sure BPF program is compiled with -Wsign-compare then
* __lhs OP __rhs below will catch the mistake.
* Be aware that we check only __lhs to figure out the sign of compare.
*/
#define bpf_assert_gt_with(LHS, RHS, value) \
({ \
barrier_var(LHS); \
__bpf_assert_op(LHS, >, RHS, value, false); \
})
#define _bpf_cmp(LHS, OP, RHS, NOFLIP) \
({ \
typeof(LHS) __lhs = (LHS); \
typeof(RHS) __rhs = (RHS); \
bool ret; \
_Static_assert(sizeof(&(LHS)), "1st argument must be an lvalue expression"); \
(void)(__lhs OP __rhs); \
if (__cmp_cannot_be_signed(OP) || !__is_signed_type(typeof(__lhs))) { \
if (sizeof(__rhs) == 8) \
ret = __bpf_cmp(__lhs, OP, "", "r", __rhs, NOFLIP); \
else \
ret = __bpf_cmp(__lhs, OP, "", "i", __rhs, NOFLIP); \
} else { \
if (sizeof(__rhs) == 8) \
ret = __bpf_cmp(__lhs, OP, "s", "r", __rhs, NOFLIP); \
else \
ret = __bpf_cmp(__lhs, OP, "s", "i", __rhs, NOFLIP); \
} \
ret; \
})

#ifndef bpf_cmp_unlikely
#define bpf_cmp_unlikely(LHS, OP, RHS) _bpf_cmp(LHS, OP, RHS, true)
#endif

/* Description
* Assert that LHS is less than or equal to RHS. This statement updates the
* known bounds of LHS during verification. Note that RHS must be a
* constant value, and must fit within the data type of LHS.
* Returns
* Void.
* Throws
* An exception with the value zero when the assertion fails.
*/
#define bpf_assert_le(LHS, RHS) \
({ \
barrier_var(LHS); \
__bpf_assert_op(LHS, <=, RHS, 0, false); \
})
#ifndef bpf_cmp_likely
#define bpf_cmp_likely(LHS, OP, RHS) \
({ \
bool ret; \
if (__builtin_strcmp(#OP, "==") == 0) \
ret = _bpf_cmp(LHS, !=, RHS, false); \
else if (__builtin_strcmp(#OP, "!=") == 0) \
ret = _bpf_cmp(LHS, ==, RHS, false); \
else if (__builtin_strcmp(#OP, "<=") == 0) \
ret = _bpf_cmp(LHS, >, RHS, false); \
else if (__builtin_strcmp(#OP, "<") == 0) \
ret = _bpf_cmp(LHS, >=, RHS, false); \
else if (__builtin_strcmp(#OP, ">") == 0) \
ret = _bpf_cmp(LHS, <=, RHS, false); \
else if (__builtin_strcmp(#OP, ">=") == 0) \
ret = _bpf_cmp(LHS, <, RHS, false); \
else \
(void) "bug"; \
ret; \
})
#endif

/* Description
* Assert that LHS is less than or equal to RHS. This statement updates the
* known bounds of LHS during verification. Note that RHS must be a
* constant value, and must fit within the data type of LHS.
* Returns
* Void.
* Throws
* An exception with the specified value when the assertion fails.
*/
#define bpf_assert_le_with(LHS, RHS, value) \
({ \
barrier_var(LHS); \
__bpf_assert_op(LHS, <=, RHS, value, false); \
})
#ifndef bpf_nop_mov
#define bpf_nop_mov(var) \
asm volatile("%[reg]=%[reg]"::[reg]"r"((short)var))
#endif

/* Description
* Assert that LHS is greater than or equal to RHS. This statement updates
* the known bounds of LHS during verification. Note that RHS must be a
* constant value, and must fit within the data type of LHS.
* Assert that a conditional expression is true.
* Returns
* Void.
* Throws
* An exception with the value zero when the assertion fails.
*/
#define bpf_assert_ge(LHS, RHS) \
({ \
barrier_var(LHS); \
__bpf_assert_op(LHS, >=, RHS, 0, false); \
})
#define bpf_assert(cond) if (!(cond)) bpf_throw(0);

/* Description
* Assert that LHS is greater than or equal to RHS. This statement updates
* the known bounds of LHS during verification. Note that RHS must be a
* constant value, and must fit within the data type of LHS.
* Assert that a conditional expression is true.
* Returns
* Void.
* Throws
* An exception with the specified value when the assertion fails.
*/
#define bpf_assert_ge_with(LHS, RHS, value) \
({ \
barrier_var(LHS); \
__bpf_assert_op(LHS, >=, RHS, value, false); \
})
#define bpf_assert_with(cond, value) if (!(cond)) bpf_throw(value);

/* Description
* Assert that LHS is in the range [BEG, END] (inclusive of both). This
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ struct {
} hashmap1 SEC(".maps");

/* will set before prog run */
volatile const __u32 num_cpus = 0;
volatile const __s32 num_cpus = 0;

/* will collect results during prog run */
__u32 key_sum_a = 0, key_sum_b = 0, key_sum_c = 0;
Expand Down
2 changes: 1 addition & 1 deletion tools/testing/selftests/bpf/progs/bpf_iter_task_vmas.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ SEC("iter/task_vma") int proc_maps(struct bpf_iter__task_vma *ctx)
return 0;

file = vma->vm_file;
if (task->tgid != pid) {
if (task->tgid != (pid_t)pid) {
if (one_task)
one_task_error = 1;
return 0;
Expand Down
2 changes: 1 addition & 1 deletion tools/testing/selftests/bpf/progs/bpf_iter_tasks.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ int dump_task(struct bpf_iter__task *ctx)
return 0;
}

if (task->pid != tid)
if (task->pid != (pid_t)tid)
num_unknown_tid++;
else
num_known_tid++;
Expand Down
2 changes: 1 addition & 1 deletion tools/testing/selftests/bpf/progs/bpf_iter_test_kern4.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ int dump_bpf_map(struct bpf_iter__bpf_map *ctx)
}

/* fill seq_file buffer */
for (i = 0; i < print_len; i++)
for (i = 0; i < (int)print_len; i++)
bpf_seq_write(seq, &seq_num, sizeof(seq_num));

return ret;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
__u32 invocations = 0;
__u32 assertion_error = 0;
__u32 retval_value = 0;
__u32 page_size = 0;
__s32 page_size = 0;

SEC("cgroup/setsockopt")
int get_retval(struct bpf_sockopt *ctx)
Expand Down
2 changes: 1 addition & 1 deletion tools/testing/selftests/bpf/progs/cgrp_ls_sleepable.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct {
__type(value, long);
} map_a SEC(".maps");

__u32 target_pid;
__s32 target_pid;
__u64 cgroup_id;
int target_hid;
bool is_cgroup1;
Expand Down
2 changes: 1 addition & 1 deletion tools/testing/selftests/bpf/progs/cpumask_success.c
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ SEC("tp_btf/task_newtask")
int BPF_PROG(test_copy_any_anyand, struct task_struct *task, u64 clone_flags)
{
struct bpf_cpumask *mask1, *mask2, *dst1, *dst2;
u32 cpu;
int cpu;

if (!is_test_task())
return 0;
Expand Down

0 comments on commit b456005

Please sign in to comment.