summaryrefslogtreecommitdiff
path: root/lib/hash.c
diff options
context:
space:
mode:
authorQuentin Young <qlyoung@nvidia.com>2020-09-02 16:02:55 -0400
committerQuentin Young <qlyoung@nvidia.com>2020-09-02 16:54:41 -0400
commite6464fdc184e4b0a4032286c8fae245dcdb03d8f (patch)
treee08ad3607c4046c5f83bc3d32f4f4c914a51559b /lib/hash.c
parente9faf4be72294fccd9f7bd21b62473d408c80a37 (diff)
lib: remove overflow arithmetic from hash stats
Signed values get converted to unsigned for addition, so when the value to adjust a stats variable for hash tables was negative this resulted in overflow arithmetic, which we generally don't want. Signed-off-by: Quentin Young <qlyoung@nvidia.com>
Diffstat (limited to 'lib/hash.c')
-rw-r--r--lib/hash.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/lib/hash.c b/lib/hash.c
index 7f8a237047..85982774ac 100644
--- a/lib/hash.c
+++ b/lib/hash.c
@@ -77,9 +77,20 @@ void *hash_alloc_intern(void *arg)
return arg;
}
+/*
+ * ssq = ssq + (new^2 - old^2)
+ * = ssq + ((new + old) * (new - old))
+ */
#define hash_update_ssq(hz, old, new) \
- atomic_fetch_add_explicit(&hz->stats.ssq, (new + old) * (new - old), \
- memory_order_relaxed);
+ do { \
+ int _adjust = (new + old) * (new - old); \
+ if (_adjust < 0) \
+ atomic_fetch_sub_explicit(&hz->stats.ssq, -_adjust, \
+ memory_order_relaxed); \
+ else \
+ atomic_fetch_add_explicit(&hz->stats.ssq, _adjust, \
+ memory_order_relaxed); \
+ } while (0)
/* Expand hash if the chain length exceeds the threshold. */
static void hash_expand(struct hash *hash)