Skip to content

Commit 656e900

Browse files
committed
asm-generic: avoid __generic_cmpxchg_local warnings
Code that passes a 32-bit constant into cmpxchg() produces a harmless sparse warning because of the truncation in the branch that is not taken: fs/erofs/zdata.c: note: in included file (through /home/arnd/arm-soc/arch/arm/include/asm/cmpxchg.h, /home/arnd/arm-soc/arch/arm/include/asm/atomic.h, /home/arnd/arm-soc/include/linux/atomic.h, ...): include/asm-generic/cmpxchg-local.h:29:33: warning: cast truncates bits from constant value (5f0ecafe becomes fe) include/asm-generic/cmpxchg-local.h:33:34: warning: cast truncates bits from constant value (5f0ecafe becomes cafe) include/asm-generic/cmpxchg-local.h:29:33: warning: cast truncates bits from constant value (5f0ecafe becomes fe) include/asm-generic/cmpxchg-local.h:30:42: warning: cast truncates bits from constant value (5f0edead becomes ad) include/asm-generic/cmpxchg-local.h:33:34: warning: cast truncates bits from constant value (5f0ecafe becomes cafe) include/asm-generic/cmpxchg-local.h:34:44: warning: cast truncates bits from constant value (5f0edead becomes dead) This was reported as a regression to Matt's recent __generic_cmpxchg_local patch, though this patch only added more warnings on top of the ones that were already there. Rewording the truncation to use an explicit bitmask instead of a cast to a smaller type avoids the warning but otherwise leaves the code unchanged. I had another look at why the cast is even needed for atomic_cmpxchg(), and as Matt describes the problem here is that atomic_t contains a signed 'int', but cmpxchg() takes an 'unsigned long' argument, and converting between the two leads to a 64-bit sign-extension of negative 32-bit atomics. I checked the other implementations of arch_cmpxchg() and did not find any others that run into the same problem as __generic_cmpxchg_local(), but it's easy to be on the safe side here and always convert the signed int into an unsigned int when calling arch_cmpxchg(), as this will work even when any of the arch_cmpxchg() implementations run into the same problem. Fixes: 6246541 ("locking/atomic: cmpxchg: Make __generic_cmpxchg_local compare against zero-extended 'old' value") Reviewed-by: Matt Evans <mev@rivosinc.com> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
1 parent 05d3855 commit 656e900

File tree

3 files changed

+11
-11
lines changed

3 files changed

+11
-11
lines changed

include/asm-generic/atomic.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ ATOMIC_OP(xor, ^)
130130
#define arch_atomic_read(v) READ_ONCE((v)->counter)
131131
#define arch_atomic_set(v, i) WRITE_ONCE(((v)->counter), (i))
132132

133-
#define arch_atomic_xchg(ptr, v) (arch_xchg(&(ptr)->counter, (v)))
134-
#define arch_atomic_cmpxchg(v, old, new) (arch_cmpxchg(&((v)->counter), (old), (new)))
133+
#define arch_atomic_xchg(ptr, v) (arch_xchg(&(ptr)->counter, (u32)(v)))
134+
#define arch_atomic_cmpxchg(v, old, new) (arch_cmpxchg(&((v)->counter), (u32)(old), (u32)(new)))
135135

136136
#endif /* __ASM_GENERIC_ATOMIC_H */

include/asm-generic/cmpxchg-local.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@ static inline unsigned long __generic_cmpxchg_local(volatile void *ptr,
2626
raw_local_irq_save(flags);
2727
switch (size) {
2828
case 1: prev = *(u8 *)ptr;
29-
if (prev == (u8)old)
30-
*(u8 *)ptr = (u8)new;
29+
if (prev == (old & 0xffu))
30+
*(u8 *)ptr = (new & 0xffu);
3131
break;
3232
case 2: prev = *(u16 *)ptr;
33-
if (prev == (u16)old)
34-
*(u16 *)ptr = (u16)new;
33+
if (prev == (old & 0xffffu))
34+
*(u16 *)ptr = (new & 0xffffu);
3535
break;
3636
case 4: prev = *(u32 *)ptr;
37-
if (prev == (u32)old)
38-
*(u32 *)ptr = (u32)new;
37+
if (prev == (old & 0xffffffffffu))
38+
*(u32 *)ptr = (new & 0xffffffffu);
3939
break;
4040
case 8: prev = *(u64 *)ptr;
4141
if (prev == old)

include/asm-generic/cmpxchg.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ unsigned long __generic_xchg(unsigned long x, volatile void *ptr, int size)
3232
#else
3333
local_irq_save(flags);
3434
ret = *(volatile u8 *)ptr;
35-
*(volatile u8 *)ptr = x;
35+
*(volatile u8 *)ptr = (x & 0xffu);
3636
local_irq_restore(flags);
3737
return ret;
3838
#endif /* __xchg_u8 */
@@ -43,7 +43,7 @@ unsigned long __generic_xchg(unsigned long x, volatile void *ptr, int size)
4343
#else
4444
local_irq_save(flags);
4545
ret = *(volatile u16 *)ptr;
46-
*(volatile u16 *)ptr = x;
46+
*(volatile u16 *)ptr = (x & 0xffffu);
4747
local_irq_restore(flags);
4848
return ret;
4949
#endif /* __xchg_u16 */
@@ -54,7 +54,7 @@ unsigned long __generic_xchg(unsigned long x, volatile void *ptr, int size)
5454
#else
5555
local_irq_save(flags);
5656
ret = *(volatile u32 *)ptr;
57-
*(volatile u32 *)ptr = x;
57+
*(volatile u32 *)ptr = (x & 0xffffffffu);
5858
local_irq_restore(flags);
5959
return ret;
6060
#endif /* __xchg_u32 */

0 commit comments

Comments
 (0)