libbpf: Fix libbpf hashmap on (I)LP32 architectures
authorJakub Bogusz <qboosh@pld-linux.org>
Thu, 9 Jul 2020 22:57:23 +0000 (15:57 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Fri, 10 Jul 2020 02:38:55 +0000 (19:38 -0700)
On ILP32, 64-bit result was shifted by value calculated for 32-bit long type
and returned value was much outside hashmap capacity.
As advised by Andrii Nakryiko, this patch uses different hashing variant for
architectures with size_t shorter than long long.

Fixes: e3b924224028 ("libbpf: add resizable non-thread safe internal hashmap")
Signed-off-by: Jakub Bogusz <qboosh@pld-linux.org>
Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://lore.kernel.org/bpf/20200709225723.1069937-1-andriin@fb.com
tools/lib/bpf/hashmap.h

index df59fd4fc95ba82c2f0ceb3caa7ef6a8ce75082a..e0af36b0e5d839e2fdd57f0f921c8ba17e4a3629 100644 (file)
 #include <stdbool.h>
 #include <stddef.h>
 #include <limits.h>
-#ifndef __WORDSIZE
-#define __WORDSIZE (__SIZEOF_LONG__ * 8)
-#endif
 
 static inline size_t hash_bits(size_t h, int bits)
 {
        /* shuffle bits and return requested number of upper bits */
-       return (h * 11400714819323198485llu) >> (__WORDSIZE - bits);
+#if (__SIZEOF_SIZE_T__ == __SIZEOF_LONG_LONG__)
+       /* LP64 case */
+       return (h * 11400714819323198485llu) >> (__SIZEOF_LONG_LONG__ * 8 - bits);
+#elif (__SIZEOF_SIZE_T__ <= __SIZEOF_LONG__)
+       return (h * 2654435769lu) >> (__SIZEOF_LONG__ * 8 - bits);
+#else
+#      error "Unsupported size_t size"
+#endif
 }
 
 typedef size_t (*hashmap_hash_fn)(const void *key, void *ctx);