include/linux/atomic/atomic-arch-fallback.h | 38 ++++++++++++++++++--- scripts/atomic/fallbacks/read_acquire | 11 +++++- scripts/atomic/fallbacks/set_release | 7 +++- 3 files changed, 49 insertions(+), 7 deletions(-)
Arnd reports that on 32-bit architectures, the fallbacks for
atomic64_read_acquire and atomic64_set_release() are broken as they use
smp_load_acquire() and smp_store_release() respectively, which do not
work on types larger than the native word size.
Since those contain compiletime_assert_atomic_type(), any attempt to use
those fallbacks will result in a build-time error. e.g. with the
following added to arch/arm/kernel/setup.c:
| void test_atomic64(atomic64_t *v)
| {
| atomic64_set_release(v, 5);
| atomic64_read_acquire(v);
| }
The compiler will complain as follows:
| In file included from <command-line>:
| In function 'arch_atomic64_set_release',
| inlined from 'test_atomic64' at ./include/linux/atomic/atomic-instrumented.h:669:2:
| ././include/linux/compiler_types.h:346:38: error: call to '__compiletime_assert_9' declared with attribute error: Need native word sized stores/loads for atomicity.
| 346 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| | ^
| ././include/linux/compiler_types.h:327:4: note: in definition of macro '__compiletime_assert'
| 327 | prefix ## suffix(); \
| | ^~~~~~
| ././include/linux/compiler_types.h:346:2: note: in expansion of macro '_compiletime_assert'
| 346 | _compiletime_assert(condition, msg, __compiletime_assert_, __COUNTER__)
| | ^~~~~~~~~~~~~~~~~~~
| ././include/linux/compiler_types.h:349:2: note: in expansion of macro 'compiletime_assert'
| 349 | compiletime_assert(__native_word(t), \
| | ^~~~~~~~~~~~~~~~~~
| ./include/asm-generic/barrier.h:133:2: note: in expansion of macro 'compiletime_assert_atomic_type'
| 133 | compiletime_assert_atomic_type(*p); \
| | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| ./include/asm-generic/barrier.h:164:55: note: in expansion of macro '__smp_store_release'
| 164 | #define smp_store_release(p, v) do { kcsan_release(); __smp_store_release(p, v); } while (0)
| | ^~~~~~~~~~~~~~~~~~~
| ./include/linux/atomic/atomic-arch-fallback.h:1270:2: note: in expansion of macro 'smp_store_release'
| 1270 | smp_store_release(&(v)->counter, i);
| | ^~~~~~~~~~~~~~~~~
| make[2]: *** [scripts/Makefile.build:288: arch/arm/kernel/setup.o] Error 1
| make[1]: *** [scripts/Makefile.build:550: arch/arm/kernel] Error 2
| make: *** [Makefile:1831: arch/arm] Error 2
Fix this by only using smp_load_acquire() and smp_store_release() for
native atomic types, and otherwise falling back to the regular barriers
necessary for acquire/release semantics, as we do in the more generic
acquire and release fallbacks.
For the example above this works as expected on 32-bit, e.g.
| <test_atomic64>:
| dmb ish
| mov r2, #5
| mov r3, #0
| strd r2, [r0]
| ldrd r2, [r0]
| dmb ish
| bx lr
... and also on 64-bit, e.g.
| <test_atomic64>:
| bti c
| paciasp
| mov x1, #0x5
| stlr x1, [x0]
| ldar x0, [x0]
| autiasp
| ret
Reported-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will@kernel.org>
---
include/linux/atomic/atomic-arch-fallback.h | 38 ++++++++++++++++++---
scripts/atomic/fallbacks/read_acquire | 11 +++++-
scripts/atomic/fallbacks/set_release | 7 +++-
3 files changed, 49 insertions(+), 7 deletions(-)
diff --git a/include/linux/atomic/atomic-arch-fallback.h b/include/linux/atomic/atomic-arch-fallback.h
index a3dba31df01e..8dfb03317f2a 100644
--- a/include/linux/atomic/atomic-arch-fallback.h
+++ b/include/linux/atomic/atomic-arch-fallback.h
@@ -151,7 +151,16 @@
static __always_inline int
arch_atomic_read_acquire(const atomic_t *v)
{
- return smp_load_acquire(&(v)->counter);
+ int ret;
+
+ if (__native_word(atomic_t)) {
+ ret = smp_load_acquire(&(v)->counter);
+ } else {
+ ret = arch_atomic_read(v);
+ __atomic_acquire_fence();
+ }
+
+ return ret;
}
#define arch_atomic_read_acquire arch_atomic_read_acquire
#endif
@@ -160,7 +169,12 @@ arch_atomic_read_acquire(const atomic_t *v)
static __always_inline void
arch_atomic_set_release(atomic_t *v, int i)
{
- smp_store_release(&(v)->counter, i);
+ if (__native_word(atomic_t)) {
+ smp_store_release(&(v)->counter, i);
+ } else {
+ __atomic_release_fence();
+ arch_atomic_set(v, i);
+ }
}
#define arch_atomic_set_release arch_atomic_set_release
#endif
@@ -1258,7 +1272,16 @@ arch_atomic_dec_if_positive(atomic_t *v)
static __always_inline s64
arch_atomic64_read_acquire(const atomic64_t *v)
{
- return smp_load_acquire(&(v)->counter);
+ s64 ret;
+
+ if (__native_word(atomic64_t)) {
+ ret = smp_load_acquire(&(v)->counter);
+ } else {
+ ret = arch_atomic_read(v);
+ __atomic_acquire_fence();
+ }
+
+ return ret;
}
#define arch_atomic64_read_acquire arch_atomic64_read_acquire
#endif
@@ -1267,7 +1290,12 @@ arch_atomic64_read_acquire(const atomic64_t *v)
static __always_inline void
arch_atomic64_set_release(atomic64_t *v, s64 i)
{
- smp_store_release(&(v)->counter, i);
+ if (__native_word(atomic64_t)) {
+ smp_store_release(&(v)->counter, i);
+ } else {
+ __atomic_release_fence();
+ arch_atomic_set(v, i);
+ }
}
#define arch_atomic64_set_release arch_atomic64_set_release
#endif
@@ -2358,4 +2386,4 @@ arch_atomic64_dec_if_positive(atomic64_t *v)
#endif
#endif /* _LINUX_ATOMIC_FALLBACK_H */
-// cca554917d7ea73d5e3e7397dd70c484cad9b2c4
+// ba488b6398359cb776d457971f30cef78d0d36dc
diff --git a/scripts/atomic/fallbacks/read_acquire b/scripts/atomic/fallbacks/read_acquire
index 803ba7561076..7b8b87143c0c 100755
--- a/scripts/atomic/fallbacks/read_acquire
+++ b/scripts/atomic/fallbacks/read_acquire
@@ -2,6 +2,15 @@ cat <<EOF
static __always_inline ${ret}
arch_${atomic}_read_acquire(const ${atomic}_t *v)
{
- return smp_load_acquire(&(v)->counter);
+ ${int} ret;
+
+ if (__native_word(${atomic}_t)) {
+ ret = smp_load_acquire(&(v)->counter);
+ } else {
+ ret = arch_atomic_read(v);
+ __atomic_acquire_fence();
+ }
+
+ return ret;
}
EOF
diff --git a/scripts/atomic/fallbacks/set_release b/scripts/atomic/fallbacks/set_release
index 86ede759f24e..5f692db3ce29 100755
--- a/scripts/atomic/fallbacks/set_release
+++ b/scripts/atomic/fallbacks/set_release
@@ -2,6 +2,11 @@ cat <<EOF
static __always_inline void
arch_${atomic}_set_release(${atomic}_t *v, ${int} i)
{
- smp_store_release(&(v)->counter, i);
+ if (__native_word(${atomic}_t)) {
+ smp_store_release(&(v)->counter, i);
+ } else {
+ __atomic_release_fence();
+ arch_atomic_set(v, i);
+ }
}
EOF
--
2.30.2
Hi Mark,
I love your patch! Yet something to improve:
[auto build test ERROR on linux/master]
[also build test ERROR on soc/for-next linus/master v5.17-rc2 next-20220203]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/0day-ci/linux/commits/Mark-Rutland/atomics-fix-atomic64_-read_acquire-set_release-fallbacks/20220203-224037
base: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 2c271fe77d52a0555161926c232cd5bc07178b39
config: um-i386_defconfig (https://download.01.org/0day-ci/archive/20220203/202202032312.7YDqjour-lkp@intel.com/config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
# https://github.com/0day-ci/linux/commit/a4f59a24830e45bbd94645639aae50597b148388
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Mark-Rutland/atomics-fix-atomic64_-read_acquire-set_release-fallbacks/20220203-224037
git checkout a4f59a24830e45bbd94645639aae50597b148388
# save the config file to linux build tree
mkdir build_dir
make W=1 O=build_dir ARCH=um SUBARCH=i386 prepare
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
arch/x86/um/user-offsets.c:18:6: warning: no previous prototype for 'foo' [-Wmissing-prototypes]
18 | void foo(void)
| ^~~
In file included from include/linux/atomic.h:80,
from include/linux/rcupdate.h:25,
from include/linux/rculist.h:11,
from include/linux/pid.h:5,
from include/linux/sched.h:14,
from arch/x86/um/shared/sysdep/kernel-offsets.h:3,
from arch/um/kernel/asm-offsets.c:1:
include/linux/atomic/atomic-arch-fallback.h: In function 'arch_atomic64_read_acquire':
>> include/linux/atomic/atomic-arch-fallback.h:1280:26: error: passing argument 1 of 'arch_atomic_read' from incompatible pointer type [-Werror=incompatible-pointer-types]
1280 | ret = arch_atomic_read(v);
| ^
| |
| const atomic64_t * {aka const struct <anonymous> *}
In file included from include/linux/atomic.h:7,
from include/linux/rcupdate.h:25,
from include/linux/rculist.h:11,
from include/linux/pid.h:5,
from include/linux/sched.h:14,
from arch/x86/um/shared/sysdep/kernel-offsets.h:3,
from arch/um/kernel/asm-offsets.c:1:
arch/x86/include/asm/atomic.h:23:61: note: expected 'const atomic_t *' {aka 'const struct <anonymous> *'} but argument is of type 'const atomic64_t *' {aka 'const struct <anonymous> *'}
23 | static __always_inline int arch_atomic_read(const atomic_t *v)
| ~~~~~~~~~~~~~~~~^
In file included from include/linux/atomic.h:80,
from include/linux/rcupdate.h:25,
from include/linux/rculist.h:11,
from include/linux/pid.h:5,
from include/linux/sched.h:14,
from arch/x86/um/shared/sysdep/kernel-offsets.h:3,
from arch/um/kernel/asm-offsets.c:1:
include/linux/atomic/atomic-arch-fallback.h: In function 'arch_atomic64_set_release':
>> include/linux/atomic/atomic-arch-fallback.h:1297:19: error: passing argument 1 of 'arch_atomic_set' from incompatible pointer type [-Werror=incompatible-pointer-types]
1297 | arch_atomic_set(v, i);
| ^
| |
| atomic64_t * {aka struct <anonymous> *}
In file included from include/linux/atomic.h:7,
from include/linux/rcupdate.h:25,
from include/linux/rculist.h:11,
from include/linux/pid.h:5,
from include/linux/sched.h:14,
from arch/x86/um/shared/sysdep/kernel-offsets.h:3,
from arch/um/kernel/asm-offsets.c:1:
arch/x86/include/asm/atomic.h:39:55: note: expected 'atomic_t *' {aka 'struct <anonymous> *'} but argument is of type 'atomic64_t *' {aka 'struct <anonymous> *'}
39 | static __always_inline void arch_atomic_set(atomic_t *v, int i)
| ~~~~~~~~~~^
In file included from arch/um/kernel/asm-offsets.c:1:
arch/x86/um/shared/sysdep/kernel-offsets.h: At top level:
arch/x86/um/shared/sysdep/kernel-offsets.h:9:6: warning: no previous prototype for 'foo' [-Wmissing-prototypes]
9 | void foo(void)
| ^~~
cc1: some warnings being treated as errors
make[2]: *** [scripts/Makefile.build:121: arch/um/kernel/asm-offsets.s] Error 1
make[2]: Target '__build' not remade because of errors.
make[1]: *** [Makefile:1191: prepare0] Error 2
make[1]: Target 'prepare' not remade because of errors.
make: *** [Makefile:219: __sub-make] Error 2
make: Target 'prepare' not remade because of errors.
vim +/arch_atomic_read +1280 include/linux/atomic/atomic-arch-fallback.h
1270
1271 #ifndef arch_atomic64_read_acquire
1272 static __always_inline s64
1273 arch_atomic64_read_acquire(const atomic64_t *v)
1274 {
1275 s64 ret;
1276
1277 if (__native_word(atomic64_t)) {
1278 ret = smp_load_acquire(&(v)->counter);
1279 } else {
> 1280 ret = arch_atomic_read(v);
1281 __atomic_acquire_fence();
1282 }
1283
1284 return ret;
1285 }
1286 #define arch_atomic64_read_acquire arch_atomic64_read_acquire
1287 #endif
1288
1289 #ifndef arch_atomic64_set_release
1290 static __always_inline void
1291 arch_atomic64_set_release(atomic64_t *v, s64 i)
1292 {
1293 if (__native_word(atomic64_t)) {
1294 smp_store_release(&(v)->counter, i);
1295 } else {
1296 __atomic_release_fence();
> 1297 arch_atomic_set(v, i);
1298 }
1299 }
1300 #define arch_atomic64_set_release arch_atomic64_set_release
1301 #endif
1302
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
© 2016 - 2026 Red Hat, Inc.