Skip to content

Commit

Permalink
Merge branch 'selftests/bpf: Fixes for map_percpu_stats test'
Browse files Browse the repository at this point in the history
Hou Tao says:

====================
List-Subscribe: <mailto:[email protected]>
List-Unsubscribe: <mailto:[email protected]>
MIME-Version: 1.0
X-CM-TRANSID: gCh0CgCHHt6+xEFlSpMJEg--.58519S4
X-Coremail-Antispam: 1UD129KBjvJXoW7Jr1UJrW3JFyUXw4rJrWxCrg_yoW8JrW5pF
	WrK3WrKrZ7tryaqw13tanrW3yrtrs5W3WjkF13tr4YvF1UJ34xKr48KF1jgrZxCrZYqr1a
	yay8tF1xWa1xZrUanT9S1TB71UUUUUUqnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2
	9KBjDU0xBIdaVrnRJUUUk2b4IE77IF4wAFF20E14v26r4j6ryUM7CY07I20VC2zVCF04k2
	6cxKx2IYs7xG6rWj6s0DM7CIcVAFz4kK6r1j6r18M28lY4IEw2IIxxk0rwA2F7IY1VAKz4
	vEj48ve4kI8wA2z4x0Y4vE2Ix0cI8IcVAFwI0_tr0E3s1l84ACjcxK6xIIjxv20xvEc7Cj
	xVAFwI0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIE14v26rxl6s0DM28EF7xvwVC2z280aVCY1x
	0267AKxVW0oVCq3wAS0I0E0xvYzxvE52x082IY62kv0487Mc02F40EFcxC0VAKzVAqx4xG
	6I80ewAv7VC0I7IYx2IY67AKxVWUJVWUGwAv7VC2z280aVAFwI0_Jr0_Gr1lOx8S6xCaFV
	Cjc4AY6r1j6r4UM4x0Y48IcxkI7VAKI48JM4IIrI8v6xkF7I0E8cxan2IY04v7MxAIw28I
	cxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2
	IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUtVW8ZwCIc40Y0x0EwIxGrwCI
	42IY6xIIjxv20xvE14v26r1j6r1xMIIF0xvE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42
	IY6xAIw20EY4v20xvaj40_WFyUJVCq3wCI42IY6I8E87Iv67AKxVWUJVW8JwCI42IY6I8E
	87Iv6xkF7I0E14v26r4j6r4UJbIYCTnIWIevJa73UjIFyTuYvjxUrR6zUUUUU
X-CM-SenderInfo: xkrx3t3r6k3tpzhluzxrxghudrp/
X-Patchwork-Delegate: [email protected]

From: Hou Tao <[email protected]>

Hi,

BPF CI failed due to map_percpu_stats_percpu_hash from time to time [1].
It seems that the failure reason is per-cpu bpf memory allocator may not
be able to allocate per-cpu pointer successfully and it can not refill
free llist timely, and bpf_map_update_elem() will return -ENOMEM.

Patch #1 fixes the size of value passed to per-cpu map update API. The
problem was found when fixing the ENOMEM problem, so also post it in
this patchset. Patch #2 & #3 mitigates the ENOMEM problem by retrying
the update operation for non-preallocated per-cpu map.

Please see individual patches for more details. And comments are always
welcome.

Regards,
Tao

[1]: https://github.com/kernel-patches/bpf/actions/runs/6713177520/job/18244865326?pr=5909
====================

Signed-off-by: Andrii Nakryiko <[email protected]>
  • Loading branch information
anakryiko committed Nov 2, 2023
2 parents e68ed64 + 57688b2 commit e869ffc
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 8 deletions.
39 changes: 36 additions & 3 deletions tools/testing/selftests/bpf/map_tests/map_percpu_stats.c
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,17 @@ static bool is_lru(__u32 map_type)
map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH;
}

static bool is_percpu(__u32 map_type)
{
return map_type == BPF_MAP_TYPE_PERCPU_HASH ||
map_type == BPF_MAP_TYPE_LRU_PERCPU_HASH;
}

struct upsert_opts {
__u32 map_type;
int map_fd;
__u32 n;
bool retry_for_nomem;
};

static int create_small_hash(void)
Expand All @@ -148,19 +155,38 @@ static int create_small_hash(void)
return map_fd;
}

static bool retry_for_nomem_fn(int err)
{
return err == ENOMEM;
}

static void *patch_map_thread(void *arg)
{
/* 8KB is enough for 1024 CPUs. And it is shared between N_THREADS. */
static __u8 blob[8 << 10];
struct upsert_opts *opts = arg;
void *val_ptr;
int val;
int ret;
int i;

for (i = 0; i < opts->n; i++) {
if (opts->map_type == BPF_MAP_TYPE_HASH_OF_MAPS)
if (opts->map_type == BPF_MAP_TYPE_HASH_OF_MAPS) {
val = create_small_hash();
else
val_ptr = &val;
} else if (is_percpu(opts->map_type)) {
val_ptr = blob;
} else {
val = rand();
ret = bpf_map_update_elem(opts->map_fd, &i, &val, 0);
val_ptr = &val;
}

/* 2 seconds may be enough ? */
if (opts->retry_for_nomem)
ret = map_update_retriable(opts->map_fd, &i, val_ptr, 0,
40, retry_for_nomem_fn);
else
ret = bpf_map_update_elem(opts->map_fd, &i, val_ptr, 0);
CHECK(ret < 0, "bpf_map_update_elem", "key=%d error: %s\n", i, strerror(errno));

if (opts->map_type == BPF_MAP_TYPE_HASH_OF_MAPS)
Expand Down Expand Up @@ -281,6 +307,13 @@ static void __test(int map_fd)
else
opts.n /= 2;

/* per-cpu bpf memory allocator may not be able to allocate per-cpu
* pointer successfully and it can not refill free llist timely, and
* bpf_map_update_elem() will return -ENOMEM. so just retry to mitigate
* the problem temporarily.
*/
opts.retry_for_nomem = is_percpu(opts.map_type) && (info.map_flags & BPF_F_NO_PREALLOC);

/*
* Upsert keys [0, n) under some competition: with random values from
* N_THREADS threads. Check values, then delete all elements and check
Expand Down
17 changes: 12 additions & 5 deletions tools/testing/selftests/bpf/test_maps.c
Original file line number Diff line number Diff line change
Expand Up @@ -1396,13 +1396,18 @@ static void test_map_stress(void)
#define MAX_DELAY_US 50000
#define MIN_DELAY_RANGE_US 5000

static int map_update_retriable(int map_fd, const void *key, const void *value,
int flags, int attempts)
static bool retry_for_again_or_busy(int err)
{
return (err == EAGAIN || err == EBUSY);
}

int map_update_retriable(int map_fd, const void *key, const void *value, int flags, int attempts,
retry_for_error_fn need_retry)
{
int delay = rand() % MIN_DELAY_RANGE_US;

while (bpf_map_update_elem(map_fd, key, value, flags)) {
if (!attempts || (errno != EAGAIN && errno != EBUSY))
if (!attempts || !need_retry(errno))
return -errno;

if (delay <= MAX_DELAY_US / 2)
Expand Down Expand Up @@ -1445,11 +1450,13 @@ static void test_update_delete(unsigned int fn, void *data)
key = value = i;

if (do_update) {
err = map_update_retriable(fd, &key, &value, BPF_NOEXIST, MAP_RETRIES);
err = map_update_retriable(fd, &key, &value, BPF_NOEXIST, MAP_RETRIES,
retry_for_again_or_busy);
if (err)
printf("error %d %d\n", err, errno);
assert(err == 0);
err = map_update_retriable(fd, &key, &value, BPF_EXIST, MAP_RETRIES);
err = map_update_retriable(fd, &key, &value, BPF_EXIST, MAP_RETRIES,
retry_for_again_or_busy);
if (err)
printf("error %d %d\n", err, errno);
assert(err == 0);
Expand Down
5 changes: 5 additions & 0 deletions tools/testing/selftests/bpf/test_maps.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

#define CHECK(condition, tag, format...) ({ \
int __ret = !!(condition); \
Expand All @@ -16,4 +17,8 @@

extern int skips;

typedef bool (*retry_for_error_fn)(int err);
int map_update_retriable(int map_fd, const void *key, const void *value, int flags, int attempts,
retry_for_error_fn need_retry);

#endif

0 comments on commit e869ffc

Please sign in to comment.