4.6.1-rt3
Subsystems (13)
Dear RT folks!
I'm pleased to announce the v4.6.1-rt3 patch set.
Changes since v4.6.1-rt2:
- On return from interrupt on ARM we could schedule with lazy preempt count > 0 under some circumstances. It isn't toxic but it shouldn't happen. Noticed by Thomas Gleixner.
- The way the preempt counter is accessed on non-x86 architectures allowed the compiler to reorder the code slightly. This led to decrementing the preempt counter, checking for the need resched bit followed by writing the counter back. An interrupt between the last two steps will lead to a missing preemption point and thus high latencies. Patch by Peter Zijlstra.
- The recorded preemption counter in event trace points (such as raw_syscall_entry) are off by one because each trace point increments the counter. This has been corrected.
- It is now ensured that there are no attempts to print from IRQ or NMI context. On certain events such as hard-lockup-detector we would attempt to grab sleeping locks.
- Allow lru_add_drain_all() to perform its work remotely. Patch by Luiz Capitulino and Rik van Riel.
Known issues
- CPU hotplug got a little better but can deadlock.
The delta patch against 4.6.1-rt2 is appended below and can be found here:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.6/incr/patch-4.6.1-rt2-rt3.patch.xz
You can get this release via the git tree at:
git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git v4.6.1-rt3
The RT patch against 4.6.1 can be found here:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.6/patch-4.6.1-rt3.patch.xz
The split quilt queue is available at:
https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.6/patches-4.6.1-rt3.tar.xz
Sebastian
arch/arm/kernel/entry-armv.S +5 -1
@@ -244,7 +244,11 @@ ENDPROC(__irq_svc) bne 1b tst r0, #_TIF_NEED_RESCHED_LAZY reteq 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 + ret r8 @ go again + #endif __und_fault:
include/asm-generic/preempt.h +2 -2
@@ -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; }
include/linux/locallock.h +6 -0
@@ -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);
include/linux/tracepoint.h +13 -0
@@ -33,6 +33,19 @@ struct trace_enum_map {#define TRACEPOINT_DEFAULT_PRIO 10 +/* +* The preempt count recorded in trace_event_raw_event_# are off by one due to +* rcu_read_lock_sched_notrace() in __DO_TRACE. This is corrected here. +*/ +static inline int event_preempt_count (void ) +{ +#ifdef CONFIG_PREEMPT +return preempt_count () -1 ; +#else +return 0 ; +#endif +} +extern int tracepoint_probe_register (struct tracepoint *tp,void *probe,void *data); extern int
kernel/locking/rtmutex.c +1 -1
@@ -2059,7 +2059,7 @@ EXPORT_SYMBOL_GPL(rt_mutex_timed_lock); int __sched rt_mutex_trylock(struct rt_mutex *lock) {#ifdef CONFIG_PREEMPT_RT_FULL -if (WARN_ON (in_irq () ||in_nmi ())) +if (WARN_ON_ONCE (in_irq () ||in_nmi ())) #else if (WARN_ON(in_irq() || in_nmi() || in_serving_softirq()))#endif
kernel/printk/printk.c +10 -0
@@ -1528,6 +1528,11 @@ static void call_console_drivers(int level,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)
@@ -2460,6 +2465,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..
kernel/trace/trace_events.c +1 -1
@@ -245,7 +245,7 @@ void *trace_event_buffer_reserve(struct trace_event_buffer *fbuffer,return NULL ;local_save_flags (fbuffer->flags); - fbuffer->pc =preempt_count (); + fbuffer->pc =event_preempt_count (); fbuffer->trace_file = trace_file; fbuffer->event =
localversion-rt +1 -1
@@ -1 +1 @@ --rt2 +-rt3
mm/swap.c +30 -7
@@ -596,9 +596,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_file_pvecs, cpu);
@@ -666,12 +672,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 ) {
@@ -684,21 +710,18 @@ 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_file_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);
PATCH 1/1 mm/memcontrol.c::mem_cgroup_migrate() - replace another local_irq_disable() w. local_lock_irq()
v4.6 grew a local_irq_disable() in mm/memcontrol.c::mem_cgroup_migrate(). Convert it to use the existing local lock (event_lock) like the others.
--- mm/memcontrol.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
mm/memcontrol.c +2 -2
@@ -5557,10 +5557,10 @@ void mem_cgroup_migrate(struct page *oldcommit_charge (newpage, memcg, false); -local_irq_disable (); +local_lock_irq (event_lock);mem_cgroup_charge_statistics (memcg, newpage, compound, nr_pages);memcg_check_events (memcg, newpage); -local_irq_enable (); +local_unlock_irq (event_lock); }DEFINE_STATIC_KEY_FALSE (memcg_sockets_enabled_key);
Sebastian Andrzej Siewior
AppliedRe: [patch] mm/memcontrol.c::mem_cgroup_migrate() - replace another local_irq_disable() w. local_lock_irq()
Quoted 4 lines · Mike Galbraith
v4.6 grew a
local_irq_disable()in mm/memcontrol.c::mem_cgroup_migrate(). Convert it to use the existing local lock (event_lock) like the others.Signed-off-by Mike Galbraith <[email protected]>
Applied.
Sebastian
RFC PATCH 1/1 work-simple: Rename work-simple.[ch] to swork.[ch] for consistency
In reply to Sebastian Andrzej SiewiorThe internal bits are already swork_blah, rename source to match.
--- arch/x86/kernel/cpu/mcheck/mce.c | 2 drivers/thermal/x86_pkg_temp_thermal.c | 2 fs/aio.c | 2 include/linux/cgroup-defs.h | 2 include/linux/swork.h | 24 ++++ include/linux/work-simple.h | 24 ---- kernel/sched/Makefile | 2 kernel/sched/swork.c | 173 +++++++++++++++++++++++++++++++++ kernel/sched/work-simple.c | 173 --------------------------------- 9 files changed, 202 insertions(+), 202 deletions(-)
arch/x86/kernel/cpu/mcheck/mce.c +1 -1
@@ -42,7 +42,7 @@#include <linux/irq_work.h> #include <linux/export.h> #include <linux/jiffies.h> -#include <linux/work-simple.h> +#include <linux/swork.h> #include <asm/processor.h> #include <asm/traps.h>
drivers/thermal/x86_pkg_temp_thermal.c +1 -1
@@ -29,7 +29,7 @@#include <linux/pm.h> #include <linux/thermal.h> #include <linux/debugfs.h> -#include <linux/work-simple.h> +#include <linux/swork.h> #include <asm/cpu_device_id.h> #include <asm/mce.h>
fs/aio.c +1 -1
@@ -40,7 +40,7 @@#include <linux/ramfs.h> #include <linux/percpu-refcount.h> #include <linux/mount.h> -#include <linux/work-simple.h> +#include <linux/swork.h> #include <asm/kmap_types.h> #include <asm/uaccess.h>
include/linux/cgroup-defs.h +1 -1
@@ -16,7 +16,7 @@#include <linux/percpu-refcount.h> #include <linux/percpu-rwsem.h> #include <linux/workqueue.h> -#include <linux/work-simple.h> +#include <linux/swork.h> #ifdef CONFIG_CGROUPS
include/linux/swork.h new file +24 -0
@@ -0,0 +1,24 @@ +#ifndef _LINUX_SWORK_H +#define _LINUX_SWORK_H + +#include <linux/list.h> + +struct swork_event { +struct list_head item; +unsigned long flags; +void (*func)(struct swork_event *); +}; + +static inline void INIT_SWORK (struct swork_event *event, +void (*func)(struct swork_event *)) +{ + event->flags =0 ; + event->func = func; +} + +bool swork_queue (struct swork_event *sev); + +int swork_get (void ); +void swork_put (void ); + +#endif /* _LINUX_SWORK_H */
include/linux/work-simple.h deleted +0 -24
@@ -1,24 +0,0 @@ -#ifndef _LINUX_SWORK_H -#define _LINUX_SWORK_H - -#include <linux/list.h> - -struct swork_event { -struct list_head item; -unsigned long flags; -void (*func)(struct swork_event *); -}; - -static inline void INIT_SWORK (struct swork_event *event, -void (*func)(struct swork_event *)) -{ - event->flags =0 ; - event->func = func; -} - -bool swork_queue (struct swork_event *sev); - -int swork_get (void ); -void swork_put (void ); - -#endif /* _LINUX_SWORK_H */
kernel/sched/Makefile +1 -1
@@ -17,7 +17,7 @@ endif obj-y += core.o loadavg.o clock.o cputime.o obj-y += idle_task.o fair.o rt.o deadline.o stop_task.o -obj-y += wait.o swait.o work-simple.o completion.o idle.o +obj-y += wait.o swait.o swork.o completion.o idle.o obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o obj-$(CONFIG_SCHEDSTATS) += stats.o
kernel/sched/swork.c new file +173 -0
173 lines not on this page · raw message
kernel/sched/work-simple.c deleted +0 -173
173 lines not on this page · raw message
Re: [patch rfc] work-simple: Rename work-simple.[ch] to swork.[ch] for consistency
Quoted 4 lines · Mike Galbraith
The internal bits are already
swork_blah, rename source to match.Signed-off-by Mike Galbraith <[email protected]>
I don't mind the rename to keep things consistent. I merged the rename into the original patch.
Sebastian
RFC PATCH 1/1 locking/rwsem: Add down_write_killable/killable_nested()
In reply to Sebastian Andrzej Siewiorv4.7 added down_write_killable/killable_nested(), add them to -rt.
--- include/linux/rwsem_rt.h | 12 ++++++++++++ kernel/locking/rt.c | 24 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+)
include/linux/rwsem_rt.h +12 -0
@@ -52,8 +52,10 @@ do { \ }while (0 ) extern void rt_down_write(struct rw_semaphore *rwsem); +extern int __must_check rt_down_write_killable (struct rw_semaphore *rwsem);extern void rt_down_read_nested (struct rw_semaphore *rwsem,int subclass);extern void rt_down_write_nested (struct rw_semaphore *rwsem,int subclass); +extern int __must_check rt_down_write_killable_nested (struct rw_semaphore *rwsem,int subclass);extern void rt_down_write_nested_lock (struct rw_semaphore *rwsem,struct lockdep_map *nest);extern void rt__down_read (struct rw_semaphore *rwsem);
@@ -100,6 +102,11 @@ static inline void down_write(struct rw_rt_down_write (sem); } +static inline int down_write_killable (struct rw_semaphore *sem) +{ +return rt_down_write_killable (sem); +} +static inline int down_write_trylock (struct rw_semaphore *sem) {return rt_down_write_trylock (sem);
@@ -134,6 +141,11 @@ static inline void down_write_nested(str {rt_down_write_nested (sem, subclass); } + +static inline int down_write_killable_nested (struct rw_semaphore *sem,int subclass) +{ +return rt_down_write_killable_nested (sem, subclass); +}#ifdef CONFIG_DEBUG_LOCK_ALLOC static inline void down_write_nest_lock (struct rw_semaphore *sem,struct rw_semaphore *nest_lock)
kernel/locking/rt.c +24 -0
@@ -358,6 +358,18 @@ void rt_down_write(struct rw_semaphore }EXPORT_SYMBOL (rt_down_write); +int rt_down_write_killable (struct rw_semaphore *rwsem) +{ +int ret; + +rwsem_acquire (&rwsem->dep_map,0 ,0 , _RET_IP_); + ret =rt_mutex_lock_killable (&rwsem->lock); +if (ret) +rwsem_release (&rwsem->dep_map,1 , _RET_IP_); +return ret; +} +EXPORT_SYMBOL (rt_down_write_killable); +void rt_down_write_nested (struct rw_semaphore *rwsem,int subclass) {rwsem_acquire (&rwsem->dep_map, subclass,0 , _RET_IP_);
@@ -365,6 +377,18 @@ void rt_down_write_nested(struct rw_sem }EXPORT_SYMBOL (rt_down_write_nested); +int rt_down_write_killable_nested (struct rw_semaphore *rwsem,int subclass) +{ +int ret; + +rwsem_acquire (&rwsem->dep_map, subclass,0 , _RET_IP_); + ret =rt_mutex_lock_killable (&rwsem->lock); +if (ret) +rwsem_release (&rwsem->dep_map,1 , _RET_IP_); +return ret; +} +EXPORT_SYMBOL (rt_down_write_killable_nested); +void rt_down_write_nested_lock (struct rw_semaphore *rwsem,struct lockdep_map *nest) {
Re: [patch rfc] locking/rwsem: Add down_write_killable/killable_nested()
Quoted 1 line · * Mike Galbraith | 2016-06-07 06:19:19 [+0200]:
v4.7 added down_write_killable/killable_nested(), add them to -rt.
looks good, I will postpone this until v4.8-RT
Quoted 1 line
Signed-off-by Mike Galbraith <[email protected]>
Sebastian