summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kernel/trace/bpf_trace.c7
1 files changed, 5 insertions, 2 deletions
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c
index 195f78db9bda..5465e7eba238 100644
--- a/kernel/trace/bpf_trace.c
+++ b/kernel/trace/bpf_trace.c
@@ -823,6 +823,7 @@ const struct bpf_func_proto bpf_task_pt_regs_proto = {
struct send_signal_irq_work {
struct irq_work irq_work;
+ /* The claim: NULL marks the slot free for the next caller. */
struct task_struct *task;
u32 sig;
enum pid_type type;
@@ -842,6 +843,8 @@ static void do_bpf_send_signal(struct irq_work *entry)
group_send_sig_info(work->sig, siginfo, work->task, work->type);
put_task_struct(work->task);
+ /* Release once the fields are consumed. */
+ smp_store_release(&work->task, NULL);
}
static int bpf_send_signal_common(u32 sig, enum pid_type type, struct task_struct *task, u64 value)
@@ -885,14 +888,14 @@ static int bpf_send_signal_common(u32 sig, enum pid_type type, struct task_struc
return -EINVAL;
work = this_cpu_ptr(&send_signal_work);
- if (irq_work_is_busy(&work->irq_work))
+ if (cmpxchg(&work->task, NULL, task))
return -EBUSY;
/* Add the current task, which is the target of sending signal,
* to the irq_work. The current task may change when queued
* irq works get executed.
*/
- work->task = get_task_struct(task);
+ get_task_struct(task);
work->has_siginfo = siginfo == &info;
if (work->has_siginfo)
copy_siginfo(&work->info, &info);