[PATCH 18/21] Fix atomic_inc_unless_negative()

Valerie Aurora val at versity.com
Tue Feb 11 13:19:15 PST 2025


atomic_inc_unless_negative() is intended to implement the acquistion
of a read lock on a shared reader/exclusive writer lock. The value of
the atomic counter is either positive, meaning that number of readers
are active, or negative, meaning that there is a single writer. A read
lock is acquired by reading the value of the lock, and if it is
positive, adding one to the value and doing a cmpxchg. The cmpxchg
returns the value of the counter at the time the cmpxchg was
attempted. If we acquired the reader lock, then this value should be
the same as the value we originally read. Due to a copy-and-paste
error, it was instead checking if the value was 0 - which works until
there is a long-lived read reference, such as while a block is being
flushed. Effectively it was an exclusive reader lock. Fix the
comparison to be against the previous value, not 0.

Signed-off-by: Valerie Aurora <val at versity.com>
---
 shared/lk/atomic.h | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/shared/lk/atomic.h b/shared/lk/atomic.h
index d8972ad..4fad3cc 100644
--- a/shared/lk/atomic.h
+++ b/shared/lk/atomic.h
@@ -77,12 +77,14 @@ static inline TYPE PREFIX##cmpxchg(ATOMIC *v, TYPE old, TYPE new)	\
 									\
 static inline bool PREFIX##inc_unless_negative(ATOMIC *v)		\
 {									\
-	TYPE c = PREFIX##read(v);					\
+	TYPE read = PREFIX##read(v);					\
+	TYPE old;							\
 									\
-	do {								\
-		if (c < 0)						\
-			return false;					\
-	} while (PREFIX##cmpxchg(v, c, c + 1));				\
+        do {                            				\
+		if (read < 0)           				\
+			return false;   				\
+		old = read;             				\
+	} while ((read = PREFIX##cmpxchg(v, old, old + 1)) != old);	\
 									\
 	return true;							\
 }
-- 
2.48.1




More information about the ngnfs-devel mailing list