diff options
| -rw-r--r-- | include/linux/unwind_deferred.h | 4 | ||||
| -rw-r--r-- | include/linux/unwind_deferred_types.h | 1 | ||||
| -rw-r--r-- | kernel/unwind/deferred.c | 19 |
3 files changed, 19 insertions, 5 deletions
diff --git a/include/linux/unwind_deferred.h b/include/linux/unwind_deferred.h index 337ead927d4d..b9ec4c8515c7 100644 --- a/include/linux/unwind_deferred.h +++ b/include/linux/unwind_deferred.h @@ -55,8 +55,10 @@ static __always_inline void unwind_reset_info(void) * depends on nr_entries being cleared on exit to user, * this needs to be a separate conditional. */ - if (unlikely(info->cache)) + if (unlikely(info->cache)) { info->cache->nr_entries = 0; + info->cache->unwind_completed = 0; + } } #else /* !CONFIG_UNWIND_USER */ diff --git a/include/linux/unwind_deferred_types.h b/include/linux/unwind_deferred_types.h index 5dc9cda141ff..33b62ac25c86 100644 --- a/include/linux/unwind_deferred_types.h +++ b/include/linux/unwind_deferred_types.h @@ -3,6 +3,7 @@ #define _LINUX_UNWIND_USER_DEFERRED_TYPES_H struct unwind_cache { + unsigned long unwind_completed; unsigned int nr_entries; unsigned long entries[]; }; diff --git a/kernel/unwind/deferred.c b/kernel/unwind/deferred.c index e19f02ef416d..a3d26014a2e6 100644 --- a/kernel/unwind/deferred.c +++ b/kernel/unwind/deferred.c @@ -166,12 +166,18 @@ static void unwind_deferred_task_work(struct callback_head *head) unwind_user_faultable(&trace); + if (info->cache) + bits &= ~(info->cache->unwind_completed); + cookie = info->id.id; guard(mutex)(&callback_mutex); list_for_each_entry(work, &callbacks, list) { - if (test_bit(work->bit, &bits)) + if (test_bit(work->bit, &bits)) { work->func(work, &trace, cookie); + if (info->cache) + info->cache->unwind_completed |= BIT(work->bit); + } } } @@ -260,23 +266,28 @@ int unwind_deferred_request(struct unwind_work *work, u64 *cookie) void unwind_deferred_cancel(struct unwind_work *work) { struct task_struct *g, *t; + int bit; if (!work) return; + bit = work->bit; + /* No work should be using a reserved bit */ - if (WARN_ON_ONCE(BIT(work->bit) & RESERVED_BITS)) + if (WARN_ON_ONCE(BIT(bit) & RESERVED_BITS)) return; guard(mutex)(&callback_mutex); list_del(&work->list); - __clear_bit(work->bit, &unwind_mask); + __clear_bit(bit, &unwind_mask); guard(rcu)(); /* Clear this bit from all threads */ for_each_process_thread(g, t) { - clear_bit(work->bit, &t->unwind_info.unwind_mask); + clear_bit(bit, &t->unwind_info.unwind_mask); + if (t->unwind_info.cache) + clear_bit(bit, &t->unwind_info.cache->unwind_completed); } } |
