Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

unwind: Make unwind_task_info::unwind_mask consistent

The unwind_task_info::unwind_mask was manipulated using a mixture of:

regular store
WRITE_ONCE()
try_cmpxchg()
set_bit()
atomic_long_*()

Clean up and make it consistently atomic_long_t.

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20250924080119.384384486@infradead.org

+13 -11
+2 -2
include/linux/unwind_deferred.h
··· 46 46 static __always_inline void unwind_reset_info(void) 47 47 { 48 48 struct unwind_task_info *info = &current->unwind_info; 49 - unsigned long bits = info->unwind_mask; 49 + unsigned long bits = atomic_long_read(&info->unwind_mask); 50 50 51 51 /* Was there any unwinding? */ 52 52 if (likely(!bits)) ··· 56 56 /* Is a task_work going to run again before going back */ 57 57 if (bits & UNWIND_PENDING) 58 58 return; 59 - } while (!try_cmpxchg(&info->unwind_mask, &bits, 0UL)); 59 + } while (!atomic_long_try_cmpxchg(&info->unwind_mask, &bits, 0UL)); 60 60 current->unwind_info.id.id = 0; 61 61 62 62 if (unlikely(info->cache)) {
+2 -1
include/linux/unwind_deferred_types.h
··· 3 3 #define _LINUX_UNWIND_USER_DEFERRED_TYPES_H 4 4 5 5 #include <linux/types.h> 6 + #include <linux/atomic.h> 6 7 7 8 struct unwind_cache { 8 9 unsigned long unwind_completed; ··· 33 32 }; 34 33 35 34 struct unwind_task_info { 36 - unsigned long unwind_mask; 35 + atomic_long_t unwind_mask; 37 36 struct unwind_cache *cache; 38 37 struct callback_head work; 39 38 union unwind_task_id id;
+9 -8
kernel/unwind/deferred.c
··· 53 53 54 54 static inline bool unwind_pending(struct unwind_task_info *info) 55 55 { 56 - return test_bit(UNWIND_PENDING_BIT, &info->unwind_mask); 56 + return atomic_long_read(&info->unwind_mask) & UNWIND_PENDING; 57 57 } 58 58 59 59 /* ··· 141 141 cache->nr_entries = trace->nr; 142 142 143 143 /* Clear nr_entries on way back to user space */ 144 - set_bit(UNWIND_USED_BIT, &info->unwind_mask); 144 + atomic_long_or(UNWIND_USED, &info->unwind_mask); 145 145 146 146 return 0; 147 147 } ··· 159 159 160 160 /* Clear pending bit but make sure to have the current bits */ 161 161 bits = atomic_long_fetch_andnot(UNWIND_PENDING, 162 - (atomic_long_t *)&info->unwind_mask); 162 + &info->unwind_mask); 163 163 /* 164 164 * From here on out, the callback must always be called, even if it's 165 165 * just an empty trace. ··· 264 264 265 265 *cookie = get_cookie(info); 266 266 267 - old = READ_ONCE(info->unwind_mask); 267 + old = atomic_long_read(&info->unwind_mask); 268 268 269 269 /* Is this already queued or executed */ 270 270 if (old & bit) ··· 277 277 * to have a callback. 278 278 */ 279 279 bits = UNWIND_PENDING | bit; 280 - old = atomic_long_fetch_or(bits, (atomic_long_t *)&info->unwind_mask); 280 + old = atomic_long_fetch_or(bits, &info->unwind_mask); 281 281 if (old & bits) { 282 282 /* 283 283 * If the work's bit was set, whatever set it had better ··· 291 291 ret = task_work_add(current, &info->work, twa_mode); 292 292 293 293 if (WARN_ON_ONCE(ret)) 294 - WRITE_ONCE(info->unwind_mask, 0); 294 + atomic_long_set(&info->unwind_mask, 0); 295 295 296 296 return ret; 297 297 } ··· 323 323 guard(rcu)(); 324 324 /* Clear this bit from all threads */ 325 325 for_each_process_thread(g, t) { 326 - clear_bit(bit, &t->unwind_info.unwind_mask); 326 + atomic_long_andnot(BIT(bit), 327 + &t->unwind_info.unwind_mask); 327 328 if (t->unwind_info.cache) 328 329 clear_bit(bit, &t->unwind_info.cache->unwind_completed); 329 330 } ··· 354 353 355 354 memset(info, 0, sizeof(*info)); 356 355 init_task_work(&info->work, unwind_deferred_task_work); 357 - info->unwind_mask = 0; 356 + atomic_long_set(&info->unwind_mask, 0); 358 357 } 359 358 360 359 void unwind_task_free(struct task_struct *task)