Skip to content

Commit

Permalink
libbpf: Support pre-initializing .bss global variables
Browse files Browse the repository at this point in the history
Remove invalid assumption in libbpf that .bss map doesn't have to be updated
in kernel. With addition of skeleton and memory-mapped initialization image,
.bss doesn't have to be all zeroes when BPF map is created, because user-code
might have initialized those variables from user-space.

Fixes: eba9c5f ("libbpf: Refactor global data map initialization")
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200612194504.557844-1-andriin@fb.com
  • Loading branch information
Andrii Nakryiko authored and Alexei Starovoitov committed Jun 12, 2020
1 parent 22eb787 commit caf6249
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 13 deletions.
4 changes: 0 additions & 4 deletions tools/lib/bpf/libbpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -3564,10 +3564,6 @@ bpf_object__populate_internal_map(struct bpf_object *obj, struct bpf_map *map)
char *cp, errmsg[STRERR_BUFSIZE];
int err, zero = 0;

/* kernel already zero-initializes .bss map. */
if (map_type == LIBBPF_MAP_BSS)
return 0;

err = bpf_map_update_elem(map->fd, &zero, map->mmaped, 0);
if (err) {
err = -errno;
Expand Down
45 changes: 40 additions & 5 deletions tools/testing/selftests/bpf/prog_tests/skeleton.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ void test_skeleton(void)
int duration = 0, err;
struct test_skeleton* skel;
struct test_skeleton__bss *bss;
struct test_skeleton__data *data;
struct test_skeleton__rodata *rodata;
struct test_skeleton__kconfig *kcfg;

skel = test_skeleton__open();
Expand All @@ -24,13 +26,45 @@ void test_skeleton(void)
if (CHECK(skel->kconfig, "skel_kconfig", "kconfig is mmaped()!\n"))
goto cleanup;

bss = skel->bss;
data = skel->data;
rodata = skel->rodata;

/* validate values are pre-initialized correctly */
CHECK(data->in1 != -1, "in1", "got %d != exp %d\n", data->in1, -1);
CHECK(data->out1 != -1, "out1", "got %d != exp %d\n", data->out1, -1);
CHECK(data->in2 != -1, "in2", "got %lld != exp %lld\n", data->in2, -1LL);
CHECK(data->out2 != -1, "out2", "got %lld != exp %lld\n", data->out2, -1LL);

CHECK(bss->in3 != 0, "in3", "got %d != exp %d\n", bss->in3, 0);
CHECK(bss->out3 != 0, "out3", "got %d != exp %d\n", bss->out3, 0);
CHECK(bss->in4 != 0, "in4", "got %lld != exp %lld\n", bss->in4, 0LL);
CHECK(bss->out4 != 0, "out4", "got %lld != exp %lld\n", bss->out4, 0LL);

CHECK(rodata->in6 != 0, "in6", "got %d != exp %d\n", rodata->in6, 0);
CHECK(bss->out6 != 0, "out6", "got %d != exp %d\n", bss->out6, 0);

/* validate we can pre-setup global variables, even in .bss */
data->in1 = 10;
data->in2 = 11;
bss->in3 = 12;
bss->in4 = 13;
rodata->in6 = 14;

err = test_skeleton__load(skel);
if (CHECK(err, "skel_load", "failed to load skeleton: %d\n", err))
goto cleanup;

bss = skel->bss;
bss->in1 = 1;
bss->in2 = 2;
/* validate pre-setup values are still there */
CHECK(data->in1 != 10, "in1", "got %d != exp %d\n", data->in1, 10);
CHECK(data->in2 != 11, "in2", "got %lld != exp %lld\n", data->in2, 11LL);
CHECK(bss->in3 != 12, "in3", "got %d != exp %d\n", bss->in3, 12);
CHECK(bss->in4 != 13, "in4", "got %lld != exp %lld\n", bss->in4, 13LL);
CHECK(rodata->in6 != 14, "in6", "got %d != exp %d\n", rodata->in6, 14);

/* now set new values and attach to get them into outX variables */
data->in1 = 1;
data->in2 = 2;
bss->in3 = 3;
bss->in4 = 4;
bss->in5.a = 5;
Expand All @@ -44,14 +78,15 @@ void test_skeleton(void)
/* trigger tracepoint */
usleep(1);

CHECK(bss->out1 != 1, "res1", "got %d != exp %d\n", bss->out1, 1);
CHECK(bss->out2 != 2, "res2", "got %lld != exp %d\n", bss->out2, 2);
CHECK(data->out1 != 1, "res1", "got %d != exp %d\n", data->out1, 1);
CHECK(data->out2 != 2, "res2", "got %lld != exp %d\n", data->out2, 2);
CHECK(bss->out3 != 3, "res3", "got %d != exp %d\n", (int)bss->out3, 3);
CHECK(bss->out4 != 4, "res4", "got %lld != exp %d\n", bss->out4, 4);
CHECK(bss->handler_out5.a != 5, "res5", "got %d != exp %d\n",
bss->handler_out5.a, 5);
CHECK(bss->handler_out5.b != 6, "res6", "got %lld != exp %d\n",
bss->handler_out5.b, 6);
CHECK(bss->out6 != 14, "res7", "got %d != exp %d\n", bss->out6, 14);

CHECK(bss->bpf_syscall != kcfg->CONFIG_BPF_SYSCALL, "ext1",
"got %d != exp %d\n", bss->bpf_syscall, kcfg->CONFIG_BPF_SYSCALL);
Expand Down
19 changes: 15 additions & 4 deletions tools/testing/selftests/bpf/progs/test_skeleton.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,26 @@ struct s {
long long b;
} __attribute__((packed));

int in1 = 0;
long long in2 = 0;
/* .data section */
int in1 = -1;
long long in2 = -1;

/* .bss section */
char in3 = '\0';
long long in4 __attribute__((aligned(64))) = 0;
struct s in5 = {};

long long out2 = 0;
/* .rodata section */
const volatile int in6 = 0;

/* .data section */
int out1 = -1;
long long out2 = -1;

/* .bss section */
char out3 = 0;
long long out4 = 0;
int out1 = 0;
int out6 = 0;

extern bool CONFIG_BPF_SYSCALL __kconfig;
extern int LINUX_KERNEL_VERSION __kconfig;
Expand All @@ -36,6 +46,7 @@ int handler(const void *ctx)
out3 = in3;
out4 = in4;
out5 = in5;
out6 = in6;

bpf_syscall = CONFIG_BPF_SYSCALL;
kern_ver = LINUX_KERNEL_VERSION;
Expand Down

0 comments on commit caf6249

Please sign in to comment.