aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorJan Engelmohr <jan.engelmohr@mailbox.tu-dresden.de>2016-08-01 13:31:29 +0200
committerMoyster <oysterized@gmail.com>2016-08-26 16:15:25 +0200
commit97ef32aefecf27ce57455ac16a2da18ac7e2c1d6 (patch)
tree813972e3812b6a7caf1464068e8c774e7334e962 /kernel
parent1e9ab116c0933c30e51bf68071eb822a90451a6d (diff)
3.10.76 -> 3.10.77
Diffstat (limited to 'kernel')
-rw-r--r--kernel/ptrace.c20
-rw-r--r--kernel/softirq.c6
-rw-r--r--kernel/trace/ring_buffer.c11
3 files changed, 30 insertions, 7 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index afadcf7b4..118323bc8 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -720,6 +720,8 @@ static int ptrace_peek_siginfo(struct task_struct *child,
static int ptrace_resume(struct task_struct *child, long request,
unsigned long data)
{
+ bool need_siglock;
+
if (!valid_signal(data))
return -EIO;
@@ -747,8 +749,26 @@ static int ptrace_resume(struct task_struct *child, long request,
user_disable_single_step(child);
}
+ /*
+ * Change ->exit_code and ->state under siglock to avoid the race
+ * with wait_task_stopped() in between; a non-zero ->exit_code will
+ * wrongly look like another report from tracee.
+ *
+ * Note that we need siglock even if ->exit_code == data and/or this
+ * status was not reported yet, the new status must not be cleared by
+ * wait_task_stopped() after resume.
+ *
+ * If data == 0 we do not care if wait_task_stopped() reports the old
+ * status and clears the code too; this can't race with the tracee, it
+ * takes siglock after resume.
+ */
+ need_siglock = data && !thread_group_empty(current);
+ if (need_siglock)
+ spin_lock_irq(&child->sighand->siglock);
child->exit_code = data;
wake_up_state(child, __TASK_TRACED);
+ if (need_siglock)
+ spin_unlock_irq(&child->sighand->siglock);
return 0;
}
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 2dfd616e4..2f39153d1 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -779,9 +779,13 @@ static void run_ksoftirqd(unsigned int cpu)
local_irq_disable();
if (local_softirq_pending()) {
__do_softirq();
- rcu_note_context_switch(cpu);
local_irq_enable();
cond_resched();
+
+ preempt_disable();
+ rcu_note_context_switch(cpu);
+ preempt_enable();
+
return;
}
local_irq_enable();
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index ac08750ec..5c053e79d 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -2678,7 +2678,7 @@ static DEFINE_PER_CPU(unsigned int, current_context);
static __always_inline int trace_recursive_lock(void)
{
- unsigned int val = this_cpu_read(current_context);
+ unsigned int val = __this_cpu_read(current_context);
int bit;
if (in_interrupt()) {
@@ -2695,18 +2695,17 @@ static __always_inline int trace_recursive_lock(void)
return 1;
val |= (1 << bit);
- this_cpu_write(current_context, val);
+ __this_cpu_write(current_context, val);
return 0;
}
static __always_inline void trace_recursive_unlock(void)
{
- unsigned int val = this_cpu_read(current_context);
+ unsigned int val = __this_cpu_read(current_context);
- val--;
- val &= this_cpu_read(current_context);
- this_cpu_write(current_context, val);
+ val &= val & (val - 1);
+ __this_cpu_write(current_context, val);
}
#else