git: 1bb1d38e4160 - stable/15 - Revert "atomic: Implement atomic_{set,clear}_8 in _atomic_subword.h"

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Mon, 24 Aug 2026 17:07:08 UTC
The branch stable/15 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=1bb1d38e4160836c048b79b922a1a3f980e9128b

commit 1bb1d38e4160836c048b79b922a1a3f980e9128b
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2026-08-24 17:05:28 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2026-08-24 17:06:24 +0000

    Revert "atomic: Implement atomic_{set,clear}_8 in _atomic_subword.h"
    
    This commit fails to compile for powerpc64le.  Just revert it as it's
    only a cleanup motivated by adding support for KASAN to riscv.
    
    This is a direct commit to stable/15.
    
    This reverts commit 318915568443f1fdb65faab0f559c872f09628c6.
    
    Reported by:    jenkins
---
 sys/sys/_atomic_subword.h | 54 ++++++++++-----------------------
 sys/vm/vm_page.c          | 76 +++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 82 insertions(+), 48 deletions(-)

diff --git a/sys/sys/_atomic_subword.h b/sys/sys/_atomic_subword.h
index 907fef0bb193..284e2bfa340f 100644
--- a/sys/sys/_atomic_subword.h
+++ b/sys/sys/_atomic_subword.h
@@ -201,42 +201,21 @@ atomic_load_acq_16(const volatile uint16_t *p)
 }
 #endif
 
-#ifndef atomic_set_8
-static __inline void
-atomic_set_8(volatile uint8_t *p, uint8_t bit)
-{
-	uint32_t *addr;
-	int shift;
-
-	addr = _ATOMIC_WORD_ALIGNED(p);
-	shift = _ATOMIC_BYTE_SHIFT(p);
-	atomic_set_32(addr, (uint32_t)bit << shift);
-}
-#endif
+#undef _ATOMIC_WORD_ALIGNED
+#undef _ATOMIC_BYTE_SHIFT
+#undef _ATOMIC_HWORD_SHIFT
 
 #ifndef atomic_set_16
 static __inline void
 atomic_set_16(volatile uint16_t *p, uint16_t bit)
 {
-	uint32_t *addr;
-	int shift;
-
-	addr = _ATOMIC_WORD_ALIGNED(p);
-	shift = _ATOMIC_HWORD_SHIFT(p);
-	atomic_set_32(addr, (uint32_t)bit << shift);
-}
-#endif
-
-#ifndef atomic_clear_8
-static __inline void
-atomic_clear_8(volatile uint8_t *p, uint8_t bit)
-{
-	uint32_t *addr;
-	int shift;
+	uint16_t v;
 
-	addr = _ATOMIC_WORD_ALIGNED(p);
-	shift = _ATOMIC_BYTE_SHIFT(p);
-	atomic_clear_32(addr, (uint32_t)bit << shift);
+	v = atomic_load_16(p);
+	for (;;) {
+		if (atomic_fcmpset_16(p, &v, v | bit))
+			break;
+	}
 }
 #endif
 
@@ -244,17 +223,14 @@ atomic_clear_8(volatile uint8_t *p, uint8_t bit)
 static __inline void
 atomic_clear_16(volatile uint16_t *p, uint16_t bit)
 {
-	uint32_t *addr;
-	int shift;
+	uint16_t v;
 
-	addr = _ATOMIC_WORD_ALIGNED(p);
-	shift = _ATOMIC_HWORD_SHIFT(p);
-	atomic_clear_32(addr, (uint32_t)bit << shift);
+	v = atomic_load_16(p);
+	for (;;) {
+		if (atomic_fcmpset_16(p, &v, v & ~bit))
+			break;
+	}
 }
 #endif
 
-#undef _ATOMIC_WORD_ALIGNED
-#undef _ATOMIC_BYTE_SHIFT
-#undef _ATOMIC_HWORD_SHIFT
-
 #endif	/* _SYS__ATOMIC_SUBWORD_H_ */
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index fdf63b2160f6..ce5748bd5f33 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -5363,33 +5363,67 @@ vm_page_bits(int base, int size)
 void
 vm_page_bits_set(vm_page_t m, vm_page_bits_t *bits, vm_page_bits_t set)
 {
+
 #if PAGE_SIZE == 32768
 	atomic_set_64((uint64_t *)bits, set);
 #elif PAGE_SIZE == 16384
 	atomic_set_32((uint32_t *)bits, set);
-#elif PAGE_SIZE == 8192
+#elif (PAGE_SIZE == 8192) && defined(atomic_set_16)
 	atomic_set_16((uint16_t *)bits, set);
-#elif PAGE_SIZE == 4096
+#elif (PAGE_SIZE == 4096) && defined(atomic_set_8)
 	atomic_set_8((uint8_t *)bits, set);
+#else		/* PAGE_SIZE <= 8192 */
+	uintptr_t addr;
+	int shift;
+
+	addr = (uintptr_t)bits;
+	/*
+	 * Use a trick to perform a 32-bit atomic on the
+	 * containing aligned word, to not depend on the existence
+	 * of atomic_{set, clear}_{8, 16}.
+	 */
+	shift = addr & (sizeof(uint32_t) - 1);
+#if BYTE_ORDER == BIG_ENDIAN
+	shift = (sizeof(uint32_t) - sizeof(vm_page_bits_t) - shift) * NBBY;
 #else
-#error unhandled page size
+	shift *= NBBY;
 #endif
+	addr &= ~(sizeof(uint32_t) - 1);
+	atomic_set_32((uint32_t *)addr, set << shift);
+#endif		/* PAGE_SIZE */
 }
 
 static inline void
 vm_page_bits_clear(vm_page_t m, vm_page_bits_t *bits, vm_page_bits_t clear)
 {
+
 #if PAGE_SIZE == 32768
 	atomic_clear_64((uint64_t *)bits, clear);
 #elif PAGE_SIZE == 16384
 	atomic_clear_32((uint32_t *)bits, clear);
-#elif PAGE_SIZE == 8192
+#elif (PAGE_SIZE == 8192) && defined(atomic_clear_16)
 	atomic_clear_16((uint16_t *)bits, clear);
-#elif PAGE_SIZE == 4096
+#elif (PAGE_SIZE == 4096) && defined(atomic_clear_8)
 	atomic_clear_8((uint8_t *)bits, clear);
+#else		/* PAGE_SIZE <= 8192 */
+	uintptr_t addr;
+	int shift;
+
+	addr = (uintptr_t)bits;
+	/*
+	 * Use a trick to perform a 32-bit atomic on the
+	 * containing aligned word, to not depend on the existence
+	 * of atomic_{set, clear}_{8, 16}.
+	 */
+	shift = addr & (sizeof(uint32_t) - 1);
+#if BYTE_ORDER == BIG_ENDIAN
+	shift = (sizeof(uint32_t) - sizeof(vm_page_bits_t) - shift) * NBBY;
 #else
-#error unhandled page size
+	shift *= NBBY;
 #endif
+	addr &= ~(sizeof(uint32_t) - 1);
+	atomic_clear_32((uint32_t *)addr, clear << shift);
+#endif		/* PAGE_SIZE */
 }
 
 static inline vm_page_bits_t
@@ -5407,21 +5441,45 @@ vm_page_bits_swap(vm_page_t m, vm_page_bits_t *bits, vm_page_bits_t newbits)
 	old = *bits;
 	while (atomic_fcmpset_32(bits, &old, newbits) == 0);
 	return (old);
-#elif PAGE_SIZE == 8192
+#elif (PAGE_SIZE == 8192) && defined(atomic_fcmpset_16)
 	uint16_t old;
 
 	old = *bits;
 	while (atomic_fcmpset_16(bits, &old, newbits) == 0);
 	return (old);
-#elif PAGE_SIZE == 4096
+#elif (PAGE_SIZE == 4096) && defined(atomic_fcmpset_8)
 	uint8_t old;
 
 	old = *bits;
 	while (atomic_fcmpset_8(bits, &old, newbits) == 0);
 	return (old);
+#else		/* PAGE_SIZE <= 4096*/
+	uintptr_t addr;
+	uint32_t old, new, mask;
+	int shift;
+
+	addr = (uintptr_t)bits;
+	/*
+	 * Use a trick to perform a 32-bit atomic on the
+	 * containing aligned word, to not depend on the existence
+	 * of atomic_{set, swap, clear}_{8, 16}.
+	 */
+	shift = addr & (sizeof(uint32_t) - 1);
+#if BYTE_ORDER == BIG_ENDIAN
+	shift = (sizeof(uint32_t) - sizeof(vm_page_bits_t) - shift) * NBBY;
 #else
-#error unhandled page size
+	shift *= NBBY;
 #endif
+	addr &= ~(sizeof(uint32_t) - 1);
+	mask = VM_PAGE_BITS_ALL << shift;
+
+	old = *bits;
+	do {
+		new = old & ~mask;
+		new |= newbits << shift;
+	} while (atomic_fcmpset_32((uint32_t *)addr, &old, new) == 0);
+	return (old >> shift);
+#endif		/* PAGE_SIZE */
 }
 
 /*