mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-10-29 13:23:23 +01:00
locking/atomic: cmpxchg: Make __generic_cmpxchg_local compare against zero-extended 'old' value
__generic_cmpxchg_local takes unsigned long old/new arguments which might end up being up-cast from smaller signed types (which will sign-extend). The loaded compare value must be compared against a truncated smaller type, so down-cast appropriately for each size. The issue is apparent on 64-bit machines with code, such as atomic_dec_unless_positive(), that sign-extends from int. 64-bit machines generally don't use the generic cmpxchg but development/early ports might make use of it, so make it correct. Signed-off-by: Matt Evans <[email protected]> Signed-off-by: Arnd Bergmann <[email protected]>
This commit is contained in:
1 parent
88603b6dc4
commit
6246541522
1 file changed
+3
-3
@@ -26,15 +26,15 @@ static inline unsigned long __generic_cmpxchg_local(volatile void *ptr,
|
||||
raw_local_irq_save(flags);
|
||||
switch (size) {
|
||||
case 1: prev = *(u8 *)ptr;
|
||||
if (prev == old)
|
||||
if (prev == (u8)old)
|
||||
*(u8 *)ptr = (u8)new;
|
||||
break;
|
||||
case 2: prev = *(u16 *)ptr;
|
||||
if (prev == old)
|
||||
if (prev == (u16)old)
|
||||
*(u16 *)ptr = (u16)new;
|
||||
break;
|
||||
case 4: prev = *(u32 *)ptr;
|
||||
if (prev == old)
|
||||
if (prev == (u32)old)
|
||||
*(u32 *)ptr = (u32)new;
|
||||
break;
|
||||
case 8: prev = *(u64 *)ptr;
|
||||
|
||||
Reference in new issue
Block a user