selftests/bpf: Work-around EBUSY errors from hashmap update/delete
20b6cc34ea
("bpf: Avoid hashtab deadlock with map_locked") introduced a possibility of getting EBUSY error on lock contention, which seems to happen very deterministically in test_maps when running 1024 threads on low-CPU machine. In libbpf CI case, it's a 2 CPU VM and it's hitting this 100% of the time. Work around by retrying on EBUSY (and EAGAIN, while we are at it) after a small sleep. sched_yield() is too agressive and fails even after 20 retries, so I went with usleep(1) for backoff. Also log actual error returned to make it easier to see what's going on. Fixes:20b6cc34ea
("bpf: Avoid hashtab deadlock with map_locked") Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Song Liu <songliubraving@fb.com> Link: https://lore.kernel.org/bpf/20201223200652.3417075-1-andrii@kernel.org
This commit is contained in:
parent
e7e518053c
commit
11b844b0b7
|
@ -1312,22 +1312,58 @@ static void test_map_stress(void)
|
|||
#define DO_UPDATE 1
|
||||
#define DO_DELETE 0
|
||||
|
||||
#define MAP_RETRIES 20
|
||||
|
||||
static int map_update_retriable(int map_fd, const void *key, const void *value,
|
||||
int flags, int attempts)
|
||||
{
|
||||
while (bpf_map_update_elem(map_fd, key, value, flags)) {
|
||||
if (!attempts || (errno != EAGAIN && errno != EBUSY))
|
||||
return -errno;
|
||||
|
||||
usleep(1);
|
||||
attempts--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int map_delete_retriable(int map_fd, const void *key, int attempts)
|
||||
{
|
||||
while (bpf_map_delete_elem(map_fd, key)) {
|
||||
if (!attempts || (errno != EAGAIN && errno != EBUSY))
|
||||
return -errno;
|
||||
|
||||
usleep(1);
|
||||
attempts--;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void test_update_delete(unsigned int fn, void *data)
|
||||
{
|
||||
int do_update = ((int *)data)[1];
|
||||
int fd = ((int *)data)[0];
|
||||
int i, key, value;
|
||||
int i, key, value, err;
|
||||
|
||||
for (i = fn; i < MAP_SIZE; i += TASKS) {
|
||||
key = value = i;
|
||||
|
||||
if (do_update) {
|
||||
assert(bpf_map_update_elem(fd, &key, &value,
|
||||
BPF_NOEXIST) == 0);
|
||||
assert(bpf_map_update_elem(fd, &key, &value,
|
||||
BPF_EXIST) == 0);
|
||||
err = map_update_retriable(fd, &key, &value, BPF_NOEXIST, MAP_RETRIES);
|
||||
if (err)
|
||||
printf("error %d %d\n", err, errno);
|
||||
assert(err == 0);
|
||||
err = map_update_retriable(fd, &key, &value, BPF_EXIST, MAP_RETRIES);
|
||||
if (err)
|
||||
printf("error %d %d\n", err, errno);
|
||||
assert(err == 0);
|
||||
} else {
|
||||
assert(bpf_map_delete_elem(fd, &key) == 0);
|
||||
err = map_delete_retriable(fd, &key, MAP_RETRIES);
|
||||
if (err)
|
||||
printf("error %d %d\n", err, errno);
|
||||
assert(err == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue