From 74135ad22264541c41b13745a44e139fa15dda9f Mon Sep 17 00:00:00 2001 From: Tomasz Gromadzki Date: Sat, 25 Apr 2026 08:55:42 +0200 Subject: [PATCH 1/2] obj: recalculate curr_allocated on underflow - 2nd Avoid statistic overflow in case underflow is already detected Signed-off-by: Tomasz Gromadzki --- src/libpmemobj/stats.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libpmemobj/stats.h b/src/libpmemobj/stats.h index 213e727d3..5dd580773 100644 --- a/src/libpmemobj/stats.h +++ b/src/libpmemobj/stats.h @@ -47,8 +47,13 @@ struct stats { util_atomic_load_explicit64((&(stats)->persistent->name),\ &curr_value, memory_order_acquire);\ if (curr_value != UINT64_MAX) {\ - util_fetch_and_add64(\ + curr_value = util_fetch_and_add64(\ (&(stats)->persistent->name), (value));\ + if (curr_value > UINT64_MAX - (value)) {\ + util_atomic_store_explicit64(\ + (&(stats)->persistent->name),\ + UINT64_MAX, memory_order_release);\ + }\ }\ }\ } while (0) From 11226cb643728245423740e191b8c4d50d95d533 Mon Sep 17 00:00:00 2001 From: Tomasz Gromadzki Date: Mon, 27 Apr 2026 09:53:30 +0200 Subject: [PATCH 2/2] use CAS loop in STATS_INC/DEC_persistent use CAS loop in STATS_INC/DEC_persistent to prevent spurious writes on overflow/unerflow Signed-off-by: Tomasz Gromadzki --- src/libpmemobj/stats.h | 48 +++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/libpmemobj/stats.h b/src/libpmemobj/stats.h index 5dd580773..9a3350b39 100644 --- a/src/libpmemobj/stats.h +++ b/src/libpmemobj/stats.h @@ -43,18 +43,18 @@ struct stats { #define STATS_INC_persistent(stats, name, value) do {\ if ((stats)->enabled == POBJ_STATS_ENABLED_PERSISTENT ||\ (stats)->enabled == POBJ_STATS_ENABLED_BOTH) {\ - uint64_t curr_value;\ - util_atomic_load_explicit64((&(stats)->persistent->name),\ - &curr_value, memory_order_acquire);\ - if (curr_value != UINT64_MAX) {\ - curr_value = util_fetch_and_add64(\ - (&(stats)->persistent->name), (value));\ - if (curr_value > UINT64_MAX - (value)) {\ - util_atomic_store_explicit64(\ - (&(stats)->persistent->name),\ - UINT64_MAX, memory_order_release);\ - }\ - }\ + uint64_t old;\ + uint64_t new_val;\ + do {\ + util_atomic_load_explicit64(\ + (&(stats)->persistent->name),\ + &old, memory_order_acquire);\ + if (old == UINT64_MAX)\ + break;\ + new_val = (old > UINT64_MAX - (value)) ?\ + UINT64_MAX : (old + (value));\ + } while (!util_bool_compare_and_swap64(\ + (&(stats)->persistent->name), old, new_val));\ }\ } while (0) @@ -78,18 +78,18 @@ struct stats { #define STATS_SUB_persistent(stats, name, value) do {\ if ((stats)->enabled == POBJ_STATS_ENABLED_PERSISTENT ||\ (stats)->enabled == POBJ_STATS_ENABLED_BOTH) {\ - uint64_t curr_value;\ - util_atomic_load_explicit64((&(stats)->persistent->name),\ - &curr_value, memory_order_acquire);\ - if (curr_value != UINT64_MAX) {\ - curr_value = util_fetch_and_sub64(\ - (&(stats)->persistent->name), (value));\ - if (curr_value < value || curr_value == UINT64_MAX) {\ - util_atomic_store_explicit64(\ - (&(stats)->persistent->name),\ - UINT64_MAX, memory_order_release);\ - }\ - }\ + uint64_t old;\ + uint64_t new_val;\ + do {\ + util_atomic_load_explicit64(\ + (&(stats)->persistent->name),\ + &old, memory_order_acquire);\ + if (old == UINT64_MAX)\ + break;\ + new_val = (old < (value)) ?\ + UINT64_MAX : (old - (value));\ + } while (!util_bool_compare_and_swap64(\ + (&(stats)->persistent->name), old, new_val));\ }\ } while (0)