[ANNOUNCE] 3.14.72-rt76
From: Steven Rostedt <rostedt@goodmis.org>
Date: 2016-07-14 14:58:21
Also in:
lkml
Subsystem:
arm port, function hooks (ftrace), generic include/asm header files, kvm paravirt (kvm/paravirt), memory management, memory management - mglru (multi-gen lru), memory management - swap, networking [general], performance events subsystem, printk, the rest, tracing, x86 architecture (32-bit and 64-bit), zsmalloc compressed slab memory allocator · Maintainers:
Russell King, Steven Rostedt, Masami Hiramatsu, Arnd Bergmann, Paolo Bonzini, Andrew Morton, Chris Li, Kairui Song, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Peter Zijlstra, Ingo Molnar, Arnaldo Carvalho de Melo, Namhyung Kim, Petr Mladek, Linus Torvalds, Thomas Gleixner, Borislav Petkov, Dave Hansen, Minchan Kim, Sergey Senozhatsky
Dear RT Folks, I'm pleased to announce the 3.14.72-rt76 stable release. You can get this release via the git tree at: git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-stable-rt.git branch: v3.14-rt Head SHA1: e9deb8e0208728e04f658d89e60e641f0beefe54 Or to build 3.14.72-rt76 directly, the following patches should be applied: http://www.kernel.org/pub/linux/kernel/v3.x/linux-3.14.tar.xz http://www.kernel.org/pub/linux/kernel/v3.x/patch-3.14.72.xz http://www.kernel.org/pub/linux/kernel/projects/rt/3.14/patch-3.14.72-rt76.patch.xz You can also build from 3.14.72-rt75 by applying the incremental patch: http://www.kernel.org/pub/linux/kernel/projects/rt/3.14/incr/patch-3.14.72-rt75-rt76.patch.xz Enjoy, -- Steve Changes from v3.14.72-rt75: --- Corey Minyard (1): x86: Fix an RT MCE crash Josh Cartwright (1): list_bl: fixup bogus lockdep warning Luiz Capitulino (1): mm: perform lru_add_drain_all() remotely Mike Galbraith (1): mm/zsmalloc: Use get/put_cpu_light in zs_map_object()/zs_unmap_object() Peter Zijlstra (1): sched,preempt: Fix preempt_count manipulations Rik van Riel (1): kvm, rt: change async pagefault code locking for PREEMPT_RT Sebastian Andrzej Siewior (5): net: dev: always take qdisc's busylock in __dev_xmit_skb() kernel/printk: Don't try to print from IRQ/NMI region arm: lazy preempt: correct resched condition locallock: add local_lock_on() trace: correct off by one while recording the trace-event Steven Rostedt (Red Hat) (1): Linux 3.14.72-rt76 Thomas Gleixner (1): perf/x86/intel/rapl: Make PMU lock raw ---- arch/arm/kernel/entry-armv.S | 6 ++++- arch/x86/kernel/cpu/mcheck/mce.c | 3 ++- arch/x86/kernel/cpu/perf_event_intel_rapl.c | 20 ++++++++-------- arch/x86/kernel/kvm.c | 37 +++++++++++++++-------------- include/asm-generic/preempt.h | 4 ++-- include/linux/list_bl.h | 12 ++++++---- include/linux/locallock.h | 6 +++++ include/trace/ftrace.h | 3 +++ kernel/printk/printk.c | 10 ++++++++ localversion-rt | 2 +- mm/swap.c | 37 +++++++++++++++++++++++------ mm/zsmalloc.c | 4 ++-- net/core/dev.c | 4 ++++ 13 files changed, 101 insertions(+), 47 deletions(-) ---------------------------
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 62bc04cc9b7d..ceda9997a29d 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S@@ -234,7 +234,11 @@ svc_preempt: bne 1b tst r0, #_TIF_NEED_RESCHED_LAZY moveq pc, r8 @ go again - b 1b + ldr r0, [tsk, #TI_PREEMPT_LAZY] @ get preempt lazy count + teq r0, #0 @ if preempt lazy count != 0 + beq 1b + mov pc, r8 @ go again + #endif __und_fault:
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index d4867bd532f3..31ec14000e4a 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c@@ -1403,7 +1403,8 @@ static int mce_notify_work_init(void) static void mce_notify_work(void) { - wake_up_process(mce_notify_helper); + if (mce_notify_helper) + wake_up_process(mce_notify_helper); } #else static void mce_notify_work(void)
diff --git a/arch/x86/kernel/cpu/perf_event_intel_rapl.c b/arch/x86/kernel/cpu/perf_event_intel_rapl.c
index 95700e52061d..4d270d910c33 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_rapl.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_rapl.c@@ -98,7 +98,7 @@ static struct kobj_attribute format_attr_##_var = \ #define RAPL_CNTR_WIDTH 32 /* 32-bit rapl counters */ struct rapl_pmu { - spinlock_t lock; + raw_spinlock_t lock; int hw_unit; /* 1/2^hw_unit Joule */ int n_active; /* number of active events */ struct list_head active_list;
@@ -188,13 +188,13 @@ static enum hrtimer_restart rapl_hrtimer_handle(struct hrtimer *hrtimer) if (!pmu->n_active) return HRTIMER_NORESTART; - spin_lock_irqsave(&pmu->lock, flags); + raw_spin_lock_irqsave(&pmu->lock, flags); list_for_each_entry(event, &pmu->active_list, active_entry) { rapl_event_update(event); } - spin_unlock_irqrestore(&pmu->lock, flags); + raw_spin_unlock_irqrestore(&pmu->lock, flags); hrtimer_forward_now(hrtimer, pmu->timer_interval);
@@ -231,9 +231,9 @@ static void rapl_pmu_event_start(struct perf_event *event, int mode) struct rapl_pmu *pmu = __get_cpu_var(rapl_pmu); unsigned long flags; - spin_lock_irqsave(&pmu->lock, flags); + raw_spin_lock_irqsave(&pmu->lock, flags); __rapl_pmu_event_start(pmu, event); - spin_unlock_irqrestore(&pmu->lock, flags); + raw_spin_unlock_irqrestore(&pmu->lock, flags); } static void rapl_pmu_event_stop(struct perf_event *event, int mode)
@@ -242,7 +242,7 @@ static void rapl_pmu_event_stop(struct perf_event *event, int mode) struct hw_perf_event *hwc = &event->hw; unsigned long flags; - spin_lock_irqsave(&pmu->lock, flags); + raw_spin_lock_irqsave(&pmu->lock, flags); /* mark event as deactivated and stopped */ if (!(hwc->state & PERF_HES_STOPPED)) {
@@ -267,7 +267,7 @@ static void rapl_pmu_event_stop(struct perf_event *event, int mode) hwc->state |= PERF_HES_UPTODATE; } - spin_unlock_irqrestore(&pmu->lock, flags); + raw_spin_unlock_irqrestore(&pmu->lock, flags); } static int rapl_pmu_event_add(struct perf_event *event, int mode)
@@ -276,14 +276,14 @@ static int rapl_pmu_event_add(struct perf_event *event, int mode) struct hw_perf_event *hwc = &event->hw; unsigned long flags; - spin_lock_irqsave(&pmu->lock, flags); + raw_spin_lock_irqsave(&pmu->lock, flags); hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; if (mode & PERF_EF_START) __rapl_pmu_event_start(pmu, event); - spin_unlock_irqrestore(&pmu->lock, flags); + raw_spin_unlock_irqrestore(&pmu->lock, flags); return 0; }
@@ -526,7 +526,7 @@ static int rapl_cpu_prepare(int cpu) if (!pmu) return -1; - spin_lock_init(&pmu->lock); + raw_spin_lock_init(&pmu->lock); INIT_LIST_HEAD(&pmu->active_list);
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 0b1e1d5dbc5b..7606d7c35bd2 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c@@ -35,6 +35,7 @@ #include <linux/slab.h> #include <linux/kprobes.h> #include <linux/debugfs.h> +#include <linux/wait-simple.h> #include <asm/timer.h> #include <asm/cpu.h> #include <asm/traps.h>
@@ -90,14 +91,14 @@ static void kvm_io_delay(void) struct kvm_task_sleep_node { struct hlist_node link; - wait_queue_head_t wq; + struct swait_head wq; u32 token; int cpu; bool halted; }; static struct kvm_task_sleep_head { - spinlock_t lock; + raw_spinlock_t lock; struct hlist_head list; } async_pf_sleepers[KVM_TASK_SLEEP_HASHSIZE];
@@ -121,17 +122,17 @@ void kvm_async_pf_task_wait(u32 token) u32 key = hash_32(token, KVM_TASK_SLEEP_HASHBITS); struct kvm_task_sleep_head *b = &async_pf_sleepers[key]; struct kvm_task_sleep_node n, *e; - DEFINE_WAIT(wait); + DEFINE_SWAITER(wait); rcu_irq_enter(); - spin_lock(&b->lock); + raw_spin_lock(&b->lock); e = _find_apf_task(b, token); if (e) { /* dummy entry exist -> wake up was delivered ahead of PF */ hlist_del(&e->link); kfree(e); - spin_unlock(&b->lock); + raw_spin_unlock(&b->lock); rcu_irq_exit(); return;
@@ -140,13 +141,13 @@ void kvm_async_pf_task_wait(u32 token) n.token = token; n.cpu = smp_processor_id(); n.halted = is_idle_task(current) || preempt_count() > 1; - init_waitqueue_head(&n.wq); + init_swait_head(&n.wq); hlist_add_head(&n.link, &b->list); - spin_unlock(&b->lock); + raw_spin_unlock(&b->lock); for (;;) { if (!n.halted) - prepare_to_wait(&n.wq, &wait, TASK_UNINTERRUPTIBLE); + swait_prepare(&n.wq, &wait, TASK_UNINTERRUPTIBLE); if (hlist_unhashed(&n.link)) break;
@@ -165,7 +166,7 @@ void kvm_async_pf_task_wait(u32 token) } } if (!n.halted) - finish_wait(&n.wq, &wait); + swait_finish(&n.wq, &wait); rcu_irq_exit(); return;
@@ -177,8 +178,8 @@ static void apf_task_wake_one(struct kvm_task_sleep_node *n) hlist_del_init(&n->link); if (n->halted) smp_send_reschedule(n->cpu); - else if (waitqueue_active(&n->wq)) - wake_up(&n->wq); + else if (swaitqueue_active(&n->wq)) + swait_wake(&n->wq); } static void apf_task_wake_all(void)
@@ -188,14 +189,14 @@ static void apf_task_wake_all(void) for (i = 0; i < KVM_TASK_SLEEP_HASHSIZE; i++) { struct hlist_node *p, *next; struct kvm_task_sleep_head *b = &async_pf_sleepers[i]; - spin_lock(&b->lock); + raw_spin_lock(&b->lock); hlist_for_each_safe(p, next, &b->list) { struct kvm_task_sleep_node *n = hlist_entry(p, typeof(*n), link); if (n->cpu == smp_processor_id()) apf_task_wake_one(n); } - spin_unlock(&b->lock); + raw_spin_unlock(&b->lock); } }
@@ -211,7 +212,7 @@ void kvm_async_pf_task_wake(u32 token) } again: - spin_lock(&b->lock); + raw_spin_lock(&b->lock); n = _find_apf_task(b, token); if (!n) { /*
@@ -224,17 +225,17 @@ again: * Allocation failed! Busy wait while other cpu * handles async PF. */ - spin_unlock(&b->lock); + raw_spin_unlock(&b->lock); cpu_relax(); goto again; } n->token = token; n->cpu = smp_processor_id(); - init_waitqueue_head(&n->wq); + init_swait_head(&n->wq); hlist_add_head(&n->link, &b->list); } else apf_task_wake_one(n); - spin_unlock(&b->lock); + raw_spin_unlock(&b->lock); return; } EXPORT_SYMBOL_GPL(kvm_async_pf_task_wake);
@@ -484,7 +485,7 @@ void __init kvm_guest_init(void) paravirt_ops_setup(); register_reboot_notifier(&kvm_pv_reboot_nb); for (i = 0; i < KVM_TASK_SLEEP_HASHSIZE; i++) - spin_lock_init(&async_pf_sleepers[i].lock); + raw_spin_lock_init(&async_pf_sleepers[i].lock); if (kvm_para_has_feature(KVM_FEATURE_ASYNC_PF)) x86_init.irqs.trap_init = kvm_apf_trap_init;
diff --git a/include/asm-generic/preempt.h b/include/asm-generic/preempt.h
index 54352f4dde1a..65759d8b0b46 100644
--- a/include/asm-generic/preempt.h
+++ b/include/asm-generic/preempt.h@@ -7,10 +7,10 @@ static __always_inline int preempt_count(void) { - return current_thread_info()->preempt_count; + return READ_ONCE(current_thread_info()->preempt_count); } -static __always_inline int *preempt_count_ptr(void) +static __always_inline volatile int *preempt_count_ptr(void) { return ¤t_thread_info()->preempt_count; }
diff --git a/include/linux/list_bl.h b/include/linux/list_bl.h
index d8876a0cf036..017d0f1c1eb4 100644
--- a/include/linux/list_bl.h
+++ b/include/linux/list_bl.h@@ -42,13 +42,15 @@ struct hlist_bl_node { struct hlist_bl_node *next, **pprev; }; -static inline void INIT_HLIST_BL_HEAD(struct hlist_bl_head *h) -{ - h->first = NULL; #ifdef CONFIG_PREEMPT_RT_BASE - raw_spin_lock_init(&h->lock); +#define INIT_HLIST_BL_HEAD(h) \ +do { \ + (h)->first = NULL; \ + raw_spin_lock_init(&(h)->lock); \ +} while (0) +#else +#define INIT_HLIST_BL_HEAD(h) (h)->first = NULL #endif -} static inline void INIT_HLIST_BL_NODE(struct hlist_bl_node *h) {
diff --git a/include/linux/locallock.h b/include/linux/locallock.h
index 21653e9bfa20..015271ff8ec8 100644
--- a/include/linux/locallock.h
+++ b/include/linux/locallock.h@@ -66,6 +66,9 @@ static inline void __local_lock(struct local_irq_lock *lv) #define local_lock(lvar) \ do { __local_lock(&get_local_var(lvar)); } while (0) +#define local_lock_on(lvar, cpu) \ + do { __local_lock(&per_cpu(lvar, cpu)); } while (0) + static inline int __local_trylock(struct local_irq_lock *lv) { if (lv->owner != current && spin_trylock_local(&lv->lock)) {
@@ -104,6 +107,9 @@ static inline void __local_unlock(struct local_irq_lock *lv) put_local_var(lvar); \ } while (0) +#define local_unlock_on(lvar, cpu) \ + do { __local_unlock(&per_cpu(lvar, cpu)); } while (0) + static inline void __local_lock_irq(struct local_irq_lock *lv) { spin_lock_irqsave(&lv->lock, lv->flags);
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 1ee19a24cc5f..73a9f766e904 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h@@ -555,6 +555,9 @@ ftrace_raw_event_##call(void *__data, proto) \ \ local_save_flags(irq_flags); \ pc = preempt_count(); \ + /* Account for tracepoint preempt disable */ \ + if (IS_ENABLED(CONFIG_PREEMPT)) \ + pc--; \ \ __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \ \
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 0b47939efd62..4472339e2156 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c@@ -1289,6 +1289,11 @@ static void call_console_drivers(int level, const char *text, size_t len) if (!console_drivers) return; + if (IS_ENABLED(CONFIG_PREEMPT_RT_BASE)) { + if (in_irq() || in_nmi()) + return; + } + migrate_disable(); for_each_console(con) { if (exclusive_console && con != exclusive_console)
@@ -2214,6 +2219,11 @@ void console_unblank(void) { struct console *c; + if (IS_ENABLED(CONFIG_PREEMPT_RT_BASE)) { + if (in_irq() || in_nmi()) + return; + } + /* * console_unblank can no longer be called in interrupt context unless * oops_in_progress is set to 1..
diff --git a/localversion-rt b/localversion-rt
index 54e7da6f49fb..c1f2720eaf25 100644
--- a/localversion-rt
+++ b/localversion-rt@@ -1 +1 @@ --rt75 +-rt76
diff --git a/mm/swap.c b/mm/swap.c
index 9a9d4c7da2cc..a9064ed57fc2 100644
--- a/mm/swap.c
+++ b/mm/swap.c@@ -750,9 +750,15 @@ void lru_add_drain_cpu(int cpu) unsigned long flags; /* No harm done if a racing interrupt already did this */ +#ifdef CONFIG_PREEMPT_RT_BASE + local_lock_irqsave_on(rotate_lock, flags, cpu); + pagevec_move_tail(pvec); + local_unlock_irqrestore_on(rotate_lock, flags, cpu); +#else local_lock_irqsave(rotate_lock, flags); pagevec_move_tail(pvec); local_unlock_irqrestore(rotate_lock, flags); +#endif } pvec = &per_cpu(lru_deactivate_pvecs, cpu);
@@ -795,12 +801,32 @@ void lru_add_drain(void) local_unlock_cpu(swapvec_lock); } + +#ifdef CONFIG_PREEMPT_RT_BASE +static inline void remote_lru_add_drain(int cpu, struct cpumask *has_work) +{ + local_lock_on(swapvec_lock, cpu); + lru_add_drain_cpu(cpu); + local_unlock_on(swapvec_lock, cpu); +} + +#else + static void lru_add_drain_per_cpu(struct work_struct *dummy) { lru_add_drain(); } static DEFINE_PER_CPU(struct work_struct, lru_add_drain_work); +static inline void remote_lru_add_drain(int cpu, struct cpumask *has_work) +{ + struct work_struct *work = &per_cpu(lru_add_drain_work, cpu); + + INIT_WORK(work, lru_add_drain_per_cpu); + schedule_work_on(cpu, work); + cpumask_set_cpu(cpu, has_work); +} +#endif void lru_add_drain_all(void) {
@@ -813,20 +839,17 @@ void lru_add_drain_all(void) cpumask_clear(&has_work); for_each_online_cpu(cpu) { - struct work_struct *work = &per_cpu(lru_add_drain_work, cpu); - if (pagevec_count(&per_cpu(lru_add_pvec, cpu)) || pagevec_count(&per_cpu(lru_rotate_pvecs, cpu)) || pagevec_count(&per_cpu(lru_deactivate_pvecs, cpu)) || - need_activate_page_drain(cpu)) { - INIT_WORK(work, lru_add_drain_per_cpu); - schedule_work_on(cpu, work); - cpumask_set_cpu(cpu, &has_work); - } + need_activate_page_drain(cpu)) + remote_lru_add_drain(cpu, &has_work); } +#ifndef CONFIG_PREEMPT_RT_BASE for_each_cpu(cpu, &has_work) flush_work(&per_cpu(lru_add_drain_work, cpu)); +#endif put_online_cpus(); mutex_unlock(&lock);
diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c
index c03ca5e9fe15..df9c7a189118 100644
--- a/mm/zsmalloc.c
+++ b/mm/zsmalloc.c@@ -1037,7 +1037,7 @@ void *zs_map_object(struct zs_pool *pool, unsigned long handle, class = &pool->size_class[class_idx]; off = obj_idx_to_offset(page, obj_idx, class->size); - area = &get_cpu_var(zs_map_area); + area = per_cpu_ptr(&zs_map_area, get_cpu_light()); area->vm_mm = mm; if (off + class->size <= PAGE_SIZE) { /* this object is contained entirely within a page */
@@ -1083,7 +1083,7 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle) __zs_unmap_object(area, pages, off, class->size); } - put_cpu_var(zs_map_area); + put_cpu_light(); } EXPORT_SYMBOL_GPL(zs_unmap_object);
diff --git a/net/core/dev.c b/net/core/dev.c
index 4259edb6d29b..0a680b4adf35 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c@@ -2720,7 +2720,11 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, * This permits __QDISC_STATE_RUNNING owner to get the lock more often * and dequeue packets faster. */ +#ifdef CONFIG_PREEMPT_RT_FULL + contended = true; +#else contended = qdisc_is_running(q); +#endif if (unlikely(contended)) spin_lock(&q->busylock);