summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorOtavio Salvador <otavio@ossystems.com.br>2016-10-26 10:28:23 -0200
committerOtavio Salvador <otavio@ossystems.com.br>2016-10-26 10:28:23 -0200
commitd7568534f54f5eb1efa4143ba09a77116f964c80 (patch)
treef0baf6887b0634658ca57ce2cdfda7b5355a7df7 /kernel
parent34002442b17af7220fa52b2d153db90685113947 (diff)
parent9ca365c0c8bdd8552ec064f0e696600cf7ea66dd (diff)
Merge tag 'v4.1.35' into 4.1-2.0.x-imx
Linux 4.1.35 * tag 'v4.1.35': (98 commits) Linux 4.1.35 xhci: fix usb2 resume timing and races. mm: remove gup_flags FOLL_WRITE games from __get_user_pages() timekeeping: Fix __ktime_get_fast_ns() regression time: Add cycles to nanoseconds translation Linux 4.1.34 openrisc: fix the fix of copy_from_user() avr32: fix 'undefined reference to `___copy_from_user' fix memory leaks in tracing_buffers_splice_read() tracing: Move mutex to protect against resetting of seq data MIPS: SMP: Fix possibility of deadlock when bringing CPUs online MIPS: Fix pre-r6 emulation FPU initialisation btrfs: ensure that file descriptor used with subvol ioctls is a dir fix fault_in_multipages_...() on architectures with no-op access_ok() ocfs2: fix start offset to ocfs2_zero_range_for_truncate() fanotify: fix list corruption in fanotify_get_response() fsnotify: add a way to stop queueing events on group shutdown autofs: use dentry flags to block walks during expire autofs races ocfs2/dlm: fix race between convert and migration ... Signed-off-by: Otavio Salvador <otavio@ossystems.com.br>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/sched/core.c22
-rw-r--r--kernel/time/timekeeping.c32
-rw-r--r--kernel/trace/trace.c29
3 files changed, 64 insertions, 19 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 98e607121d09..6cb5f00696f5 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1672,6 +1672,28 @@ try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
success = 1; /* we're going to change ->state */
cpu = task_cpu(p);
+ /*
+ * Ensure we load p->on_rq _after_ p->state, otherwise it would
+ * be possible to, falsely, observe p->on_rq == 0 and get stuck
+ * in smp_cond_load_acquire() below.
+ *
+ * sched_ttwu_pending() try_to_wake_up()
+ * [S] p->on_rq = 1; [L] P->state
+ * UNLOCK rq->lock -----.
+ * \
+ * +--- RMB
+ * schedule() /
+ * LOCK rq->lock -----'
+ * UNLOCK rq->lock
+ *
+ * [task p]
+ * [S] p->state = UNINTERRUPTIBLE [L] p->on_rq
+ *
+ * Pairs with the UNLOCK+LOCK on rq->lock from the
+ * last wakeup of our task and the schedule that got our task
+ * current.
+ */
+ smp_rmb();
if (p->on_rq && ttwu_remote(p, wake_flags))
goto stat;
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index 8fcc801fde15..d9f112bd42a7 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -309,17 +309,34 @@ u32 (*arch_gettimeoffset)(void) = default_arch_gettimeoffset;
static inline u32 arch_gettimeoffset(void) { return 0; }
#endif
+static inline s64 timekeeping_delta_to_ns(struct tk_read_base *tkr,
+ cycle_t delta)
+{
+ s64 nsec;
+
+ nsec = delta * tkr->mult + tkr->xtime_nsec;
+ nsec >>= tkr->shift;
+
+ /* If arch requires, add in get_arch_timeoffset() */
+ return nsec + arch_gettimeoffset();
+}
+
static inline s64 timekeeping_get_ns(struct tk_read_base *tkr)
{
cycle_t delta;
- s64 nsec;
delta = timekeeping_get_delta(tkr);
+ return timekeeping_delta_to_ns(tkr, delta);
+}
- nsec = (delta * tkr->mult + tkr->xtime_nsec) >> tkr->shift;
+static inline s64 timekeeping_cycles_to_ns(struct tk_read_base *tkr,
+ cycle_t cycles)
+{
+ cycle_t delta;
- /* If arch requires, add in get_arch_timeoffset() */
- return nsec + arch_gettimeoffset();
+ /* calculate the delta since the last update_wall_time */
+ delta = clocksource_delta(cycles, tkr->cycle_last, tkr->mask);
+ return timekeeping_delta_to_ns(tkr, delta);
}
/**
@@ -421,8 +438,11 @@ static __always_inline u64 __ktime_get_fast_ns(struct tk_fast *tkf)
tkr = tkf->base + (seq & 0x01);
now = ktime_to_ns(tkr->base);
- now += clocksource_delta(tkr->read(tkr->clock),
- tkr->cycle_last, tkr->mask);
+ now += timekeeping_delta_to_ns(tkr,
+ clocksource_delta(
+ tkr->read(tkr->clock),
+ tkr->cycle_last,
+ tkr->mask));
} while (read_seqcount_retry(&tkf->seq, seq));
return now;
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index de6ea94c41bb..61ea7e8cdde5 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -4694,19 +4694,20 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
struct trace_iterator *iter = filp->private_data;
ssize_t sret;
- /* return any leftover data */
- sret = trace_seq_to_user(&iter->seq, ubuf, cnt);
- if (sret != -EBUSY)
- return sret;
-
- trace_seq_init(&iter->seq);
-
/*
* Avoid more than one consumer on a single file descriptor
* This is just a matter of traces coherency, the ring buffer itself
* is protected.
*/
mutex_lock(&iter->mutex);
+
+ /* return any leftover data */
+ sret = trace_seq_to_user(&iter->seq, ubuf, cnt);
+ if (sret != -EBUSY)
+ goto out;
+
+ trace_seq_init(&iter->seq);
+
if (iter->trace->read) {
sret = iter->trace->read(iter, filp, ubuf, cnt, ppos);
if (sret)
@@ -5731,9 +5732,6 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
return -EBUSY;
#endif
- if (splice_grow_spd(pipe, &spd))
- return -ENOMEM;
-
if (*ppos & (PAGE_SIZE - 1))
return -EINVAL;
@@ -5743,6 +5741,9 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
len &= PAGE_MASK;
}
+ if (splice_grow_spd(pipe, &spd))
+ return -ENOMEM;
+
again:
trace_access_lock(iter->cpu_file);
entries = ring_buffer_entries_cpu(iter->trace_buffer->buffer, iter->cpu_file);
@@ -5800,19 +5801,21 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
/* did we read anything? */
if (!spd.nr_pages) {
if (ret)
- return ret;
+ goto out;
+ ret = -EAGAIN;
if ((file->f_flags & O_NONBLOCK) || (flags & SPLICE_F_NONBLOCK))
- return -EAGAIN;
+ goto out;
ret = wait_on_pipe(iter, true);
if (ret)
- return ret;
+ goto out;
goto again;
}
ret = splice_to_pipe(pipe, &spd);
+out:
splice_shrink_spd(&spd);
return ret;