1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 // Copyright (c) 2020 Anton Protopopov
3 #ifndef __MAPS_BPF_H
4 #define __MAPS_BPF_H
5
6 #include <bpf/bpf_helpers.h>
7 #include <asm-generic/errno.h>
8
9 static __always_inline void *
bpf_map_lookup_or_try_init(void * map,const void * key,const void * init)10 bpf_map_lookup_or_try_init(void *map, const void *key, const void *init)
11 {
12 void *val;
13 /* bpf helper functions like bpf_map_update_elem() below normally return
14 * long, but using int instead of long to store the result is a workaround
15 * to avoid incorrectly evaluating err in cases where the following criteria
16 * is met:
17 * the architecture is 64-bit
18 * the helper function return type is long
19 * the helper function returns the value of a call to a bpf_map_ops func
20 * the bpf_map_ops function return type is int
21 * the compiler inlines the helper function
22 * the compiler does not sign extend the result of the bpf_map_ops func
23 *
24 * if this criteria is met, at best an error can only be checked as zero or
25 * non-zero. it will not be possible to check for a negative value or a
26 * specific error value. this is because the sign bit would have been stuck
27 * at the 32nd bit of a 64-bit long int.
28 */
29 int err;
30
31 val = bpf_map_lookup_elem(map, key);
32 if (val)
33 return val;
34
35 err = bpf_map_update_elem(map, key, init, BPF_NOEXIST);
36 if (err && err != -EEXIST)
37 return 0;
38
39 return bpf_map_lookup_elem(map, key);
40 }
41
42 #endif /* __MAPS_BPF_H */
43