Forum | Documentation | Website | Blog

Skip to content
Snippets Groups Projects
  1. Feb 19, 2017
    • Sebastian Andrzej Siewior's avatar
      [ANNOUNCE] v4.9.11-rt9 · 71ddc37d
      Sebastian Andrzej Siewior authored
      Dear RT folks!
      
      I'm pleased to announce the v4.9.11-rt9 patch set.
      
      Changes since v4.9.11-rt8:
      
        - rt_mutex_destroy() is EXPORT_SYMBOL_GPL again. As pointed by Peter
          Zijlstra, the removal of _GPL is not required.
      
        - Added a rescheduling point so we don't forget to run a runnable task
          at elevated priority under certain circumstances.
      
        - The static initializes for PER_CPU locks were wrong. This affects
          the local_locks and resulted in lockdep disabling itself a few
          minutes after boot on _big_ iron (100 CPUs+). Reported by Mike
          Galbraith and patched by Thomas Gleixner.
      
      Known issues
      	- CPU hotplug got a little better but can deadlock.
      
      The delta patch against v4.9.11-rt9 is appended below and can be found here:
      
           https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.9/incr/patch-4.9.11-rt8-rt9.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.9.11-rt9
      
      The RT patch against v4.9.11 can be found here:
      
          https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.9/older/patch-4.9.11-rt9.patch.xz
      
      The split quilt queue is available at:
      
          https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.9/older/patches-4.9.11-rt9.tar.xz
      
      
      
      Sebastian
      diff --git a/include/linux/module.h b/include/linux/module.h
      --- a/include/linux/module.h
      +++ b/include/linux/module.h
      @@ -496,6 +496,7 @@ static inline int module_is_live(struct module *mod)
       struct module *__module_text_address(unsigned long addr);
       struct module *__module_address(unsigned long addr);
       bool is_module_address(unsigned long addr);
      +bool __is_module_percpu_address(unsigned long addr, unsigned long *can_addr);
       bool is_module_percpu_address(unsigned long addr);
       bool is_module_text_address(unsigned long addr);
      
      diff --git a/include/linux/percpu.h b/include/linux/percpu.h
      --- a/include/linux/percpu.h
      +++ b/include/linux/percpu.h
      @@ -139,6 +139,7 @@ extern int __init pcpu_page_first_chunk(size_t reserved_size,
       #endif
      
       extern void __percpu *__alloc_reserved_percpu(size_t size, size_t align);
      +extern bool __is_kernel_percpu_address(unsigned long addr, unsigned long *can_addr);
       extern bool is_kernel_percpu_address(unsigned long addr);
      
       #if !defined(CONFIG_SMP) || !defined(CONFIG_HAVE_SETUP_PER_CPU_AREA)
      diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
      --- a/kernel/locking/lockdep.c
      +++ b/kernel/locking/lockdep.c
      @@ -658,6 +658,7 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
       	struct lockdep_subclass_key *key;
       	struct hlist_head *hash_head;
       	struct lock_class *class;
      +	bool is_static = false;
      
       	if (unlikely(subclass >= MAX_LOCKDEP_SUBCLASSES)) {
       		debug_locks_off();
      @@ -671,10 +672,23 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
      
       	/*
       	 * Static locks do not have their class-keys yet - for them the key
      -	 * is the lock object itself:
      +	 * is the lock object itself. If the lock is in the per cpu area,
      +	 * the canonical address of the lock (per cpu offset removed) is
      +	 * used.
       	 */
      -	if (unlikely(!lock->key))
      -		lock->key = (void *)lock;
      +	if (unlikely(!lock->key)) {
      +		unsigned long can_addr, addr = (unsigned long)lock;
      +
      +		if (__is_kernel_percpu_address(addr, &can_addr))
      +			lock->key = (void *)can_addr;
      +		else if (__is_module_percpu_address(addr, &can_addr))
      +			lock->key = (void *)can_addr;
      +		else if (static_obj(lock))
      +			lock->key = (void *)lock;
      +		else
      +			return ERR_PTR(-EINVAL);
      +		is_static = true;
      +	}
      
       	/*
       	 * NOTE: the class-key must be unique. For dynamic locks, a static
      @@ -706,7 +720,7 @@ look_up_lock_class(struct lockdep_map *lock, unsigned int subclass)
       		}
       	}
      
      -	return NULL;
      +	return is_static || static_obj(lock->key) ? NULL : ERR_PTR(-EINVAL);
       }
      
       /*
      @@ -724,19 +738,18 @@ register_lock_class(struct lockdep_map *lock, unsigned int subclass, int force)
       	DEBUG_LOCKS_WARN_ON(!irqs_disabled());
      
       	class = look_up_lock_class(lock, subclass);
      -	if (likely(class))
      +	if (likely(!IS_ERR_OR_NULL(class)))
       		goto out_set_class_cache;
      
       	/*
       	 * Debug-check: all keys must be persistent!
      - 	 */
      -	if (!static_obj(lock->key)) {
      +	 */
      +	if (IS_ERR(class)) {
       		debug_locks_off();
       		printk("INFO: trying to register non-static key.\n");
       		printk("the code is fine but needs lockdep annotation.\n");
       		printk("turning off the locking correctness validator.\n");
       		dump_stack();
      -
       		return NULL;
       	}
      
      @@ -3410,7 +3423,7 @@ static int match_held_lock(struct held_lock *hlock, struct lockdep_map *lock)
       		 * Clearly if the lock hasn't been acquired _ever_, we're not
       		 * holding it either, so report failure.
       		 */
      -		if (!class)
      +		if (IS_ERR_OR_NULL(class))
       			return 0;
      
       		/*
      @@ -4161,7 +4174,7 @@ void lockdep_reset_lock(struct lockdep_map *lock)
       		 * If the class exists we look it up and zap it:
       		 */
       		class = look_up_lock_class(lock, j);
      -		if (class)
      +		if (!IS_ERR_OR_NULL(class))
       			zap_class(class);
       	}
       	/*
      diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
      --- a/kernel/locking/rtmutex.c
      +++ b/kernel/locking/rtmutex.c
      @@ -2211,7 +2211,8 @@ void rt_mutex_destroy(struct rt_mutex *lock)
       	lock->magic = NULL;
       #endif
       }
      -EXPORT_SYMBOL(rt_mutex_destroy);
      +
      +EXPORT_SYMBOL_GPL(rt_mutex_destroy);
      
       /**
        * __rt_mutex_init - initialize the rt lock
      diff --git a/kernel/module.c b/kernel/module.c
      --- a/kernel/module.c
      +++ b/kernel/module.c
      @@ -660,16 +660,7 @@ static void percpu_modcopy(struct module *mod,
       		memcpy(per_cpu_ptr(mod->percpu, cpu), from, size);
       }
      
      -/**
      - * is_module_percpu_address - test whether address is from module static percpu
      - * @addr: address to test
      - *
      - * Test whether @addr belongs to module static percpu area.
      - *
      - * RETURNS:
      - * %true if @addr is from module static percpu area
      - */
      -bool is_module_percpu_address(unsigned long addr)
      +bool __is_module_percpu_address(unsigned long addr, unsigned long *can_addr)
       {
       	struct module *mod;
       	unsigned int cpu;
      @@ -683,9 +674,11 @@ bool is_module_percpu_address(unsigned long addr)
       			continue;
       		for_each_possible_cpu(cpu) {
       			void *start = per_cpu_ptr(mod->percpu, cpu);
      +			void *va = (void *)addr;
      
      -			if ((void *)addr >= start &&
      -			    (void *)addr < start + mod->percpu_size) {
      +			if (va >= start && va < start + mod->percpu_size) {
      +				if (can_addr)
      +					*can_addr = (unsigned long) (va - start);
       				preempt_enable();
       				return true;
       			}
      @@ -696,6 +689,20 @@ bool is_module_percpu_address(unsigned long addr)
       	return false;
       }
      
      +/**
      + * is_module_percpu_address - test whether address is from module static percpu
      + * @addr: address to test
      + *
      + * Test whether @addr belongs to module static percpu area.
      + *
      + * RETURNS:
      + * %true if @addr is from module static percpu area
      + */
      +bool is_module_percpu_address(unsigned long addr)
      +{
      +	return __is_module_percpu_address(addr, NULL);
      +}
      +
       #else /* ... !CONFIG_SMP */
      
       static inline void __percpu *mod_percpu(struct module *mod)
      diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
      --- a/kernel/sched/deadline.c
      +++ b/kernel/sched/deadline.c
      @@ -1730,12 +1730,11 @@ static void switched_to_dl(struct rq *rq, struct task_struct *p)
       #ifdef CONFIG_SMP
       		if (tsk_nr_cpus_allowed(p) > 1 && rq->dl.overloaded)
       			queue_push_tasks(rq);
      -#else
      +#endif
       		if (dl_task(rq->curr))
       			check_preempt_curr_dl(rq, p, 0);
       		else
       			resched_curr(rq);
      -#endif
       	}
       }
      
      diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
      --- a/kernel/sched/rt.c
      +++ b/kernel/sched/rt.c
      @@ -2200,10 +2200,9 @@ static void switched_to_rt(struct rq *rq, struct task_struct *p)
       #ifdef CONFIG_SMP
       		if (tsk_nr_cpus_allowed(p) > 1 && rq->rt.overloaded)
       			queue_push_tasks(rq);
      -#else
      +#endif /* CONFIG_SMP */
       		if (p->prio < rq->curr->prio)
       			resched_curr(rq);
      -#endif /* CONFIG_SMP */
       	}
       }
      
      diff --git a/localversion-rt b/localversion-rt
      --- a/localversion-rt
      +++ b/localversion-rt
      @@ -1 +1 @@
      --rt8
      +-rt9
      diff --git a/mm/percpu.c b/mm/percpu.c
      --- a/mm/percpu.c
      +++ b/mm/percpu.c
      @@ -1280,6 +1280,28 @@ void free_percpu(void __percpu *ptr)
       }
       EXPORT_SYMBOL_GPL(free_percpu);
      
      +bool __is_kernel_percpu_address(unsigned long addr, unsigned long *can_addr)
      +{
      +#ifdef CONFIG_SMP
      +	const size_t static_size = __per_cpu_end - __per_cpu_start;
      +	void __percpu *base = __addr_to_pcpu_ptr(pcpu_base_addr);
      +	unsigned int cpu;
      +
      +	for_each_possible_cpu(cpu) {
      +		void *start = per_cpu_ptr(base, cpu);
      +		void *va = (void *)addr;
      +
      +		if (va >= start && va < start + static_size) {
      +			if (can_addr)
      +				*can_addr = (unsigned long) (va - start);
      +			return true;
      +		}
      +	}
      +#endif
      +	/* on UP, can't distinguish from other static vars, always false */
      +	return false;
      +}
      +
       /**
        * is_kernel_percpu_address - test whether address is from static percpu area
        * @addr: address to test
      @@ -1293,20 +1315,7 @@ EXPORT_SYMBOL_GPL(free_percpu);
        */
       bool is_kernel_percpu_address(unsigned long addr)
       {
      -#ifdef CONFIG_SMP
      -	const size_t static_size = __per_cpu_end - __per_cpu_start;
      -	void __percpu *base = __addr_to_pcpu_ptr(pcpu_base_addr);
      -	unsigned int cpu;
      -
      -	for_each_possible_cpu(cpu) {
      -		void *start = per_cpu_ptr(base, cpu);
      -
      -		if ((void *)addr >= start && (void *)addr < start + static_size)
      -			return true;
      -        }
      -#endif
      -	/* on UP, can't distinguish from other static vars, always false */
      -	return false;
      +	return __is_kernel_percpu_address(addr, NULL);
       }
      
       /**
      
      Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
    • Sebastian Andrzej Siewior's avatar
  2. Feb 17, 2017
  3. Feb 10, 2017
    • Sebastian Andrzej Siewior's avatar
      [ANNOUNCE] v4.9.9-rt6 · 1ffaec01
      Sebastian Andrzej Siewior authored
      Dear RT folks!
      
      I'm pleased to announce the v4.9.9-rt6 patch set.
      
      Changes since v4.9.9-rt5:
      
        - The timer softirq was woken up under certain circumstances where it
          could have been avoided. Patch by Haris Okanovic.
      
        - Alex Goins noticed that a GPL only symbol will be forced on -RT
          which is not the case on !RT configurations. This has been resolved.
      
      Known issues
      	- CPU hotplug got a little better but can deadlock.
      
      The delta patch against v4.9.9-rt6 is appended below and can be found here:
      
           https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.9/incr/patch-4.9.9-rt5-rt6.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.9.9-rt6
      
      The RT patch against v4.9.9 can be found here:
      
          https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.9/older/patch-4.9.9-rt6.patch.xz
      
      The split quilt queue is available at:
      
          https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.9/older/patches-4.9.9-rt6.tar.xz
      
      
      
      Sebastian
      diff --git a/include/linux/mutex_rt.h b/include/linux/mutex_rt.h
      --- a/include/linux/mutex_rt.h
      +++ b/include/linux/mutex_rt.h
      @@ -43,7 +43,12 @@ extern void __lockfunc _mutex_unlock(struct mutex *lock);
       #define mutex_lock_killable(l)		_mutex_lock_killable(l)
       #define mutex_trylock(l)		_mutex_trylock(l)
       #define mutex_unlock(l)			_mutex_unlock(l)
      +
      +#ifdef CONFIG_DEBUG_MUTEXES
       #define mutex_destroy(l)		rt_mutex_destroy(&(l)->lock)
      +#else
      +static inline void mutex_destroy(struct mutex *lock) {}
      +#endif
      
       #ifdef CONFIG_DEBUG_LOCK_ALLOC
       # define mutex_lock_nested(l, s)	_mutex_lock_nested(l, s)
      diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c
      --- a/kernel/locking/rtmutex.c
      +++ b/kernel/locking/rtmutex.c
      @@ -2211,8 +2211,7 @@ void rt_mutex_destroy(struct rt_mutex *lock)
       	lock->magic = NULL;
       #endif
       }
      -
      -EXPORT_SYMBOL_GPL(rt_mutex_destroy);
      +EXPORT_SYMBOL(rt_mutex_destroy);
      
       /**
        * __rt_mutex_init - initialize the rt lock
      diff --git a/kernel/time/timer.c b/kernel/time/timer.c
      --- a/kernel/time/timer.c
      +++ b/kernel/time/timer.c
      @@ -206,6 +206,8 @@ struct timer_base {
       	bool			is_idle;
       	DECLARE_BITMAP(pending_map, WHEEL_SIZE);
       	struct hlist_head	vectors[WHEEL_SIZE];
      +	struct hlist_head	expired_lists[LVL_DEPTH];
      +	int			expired_count;
       } ____cacheline_aligned;
      
       static DEFINE_PER_CPU(struct timer_base, timer_bases[NR_BASES]);
      @@ -1353,7 +1355,8 @@ static void call_timer_fn(struct timer_list *timer, void (*fn)(unsigned long),
       	}
       }
      
      -static void expire_timers(struct timer_base *base, struct hlist_head *head)
      +static inline void __expire_timers(struct timer_base *base,
      +				   struct hlist_head *head)
       {
       	while (!hlist_empty(head)) {
       		struct timer_list *timer;
      @@ -1384,21 +1387,38 @@ static void expire_timers(struct timer_base *base, struct hlist_head *head)
       	}
       }
      
      -static int __collect_expired_timers(struct timer_base *base,
      -				    struct hlist_head *heads)
      +static void expire_timers(struct timer_base *base)
      +{
      +	struct hlist_head *head;
      +
      +	while (base->expired_count--) {
      +		head = base->expired_lists + base->expired_count;
      +		__expire_timers(base, head);
      +	}
      +	base->expired_count = 0;
      +}
      +
      +static void __collect_expired_timers(struct timer_base *base)
       {
       	unsigned long clk = base->clk;
       	struct hlist_head *vec;
      -	int i, levels = 0;
      +	int i;
       	unsigned int idx;
      
      +	/*
      +	 * expire_timers() must be called at least once before we can
      +	 * collect more timers
      +	 */
      +	if (WARN_ON(base->expired_count))
      +		return;
      +
       	for (i = 0; i < LVL_DEPTH; i++) {
       		idx = (clk & LVL_MASK) + i * LVL_SIZE;
      
       		if (__test_and_clear_bit(idx, base->pending_map)) {
       			vec = base->vectors + idx;
      -			hlist_move_list(vec, heads++);
      -			levels++;
      +			hlist_move_list(vec,
      +				&base->expired_lists[base->expired_count++]);
       		}
       		/* Is it time to look at the next level? */
       		if (clk & LVL_CLK_MASK)
      @@ -1406,7 +1426,6 @@ static int __collect_expired_timers(struct timer_base *base,
       		/* Shift clock for the next level granularity */
       		clk >>= LVL_CLK_SHIFT;
       	}
      -	return levels;
       }
      
       #ifdef CONFIG_NO_HZ_COMMON
      @@ -1599,8 +1618,7 @@ void timer_clear_idle(void)
       	base->is_idle = false;
       }
      
      -static int collect_expired_timers(struct timer_base *base,
      -				  struct hlist_head *heads)
      +static void collect_expired_timers(struct timer_base *base)
       {
       	/*
       	 * NOHZ optimization. After a long idle sleep we need to forward the
      @@ -1617,20 +1635,49 @@ static int collect_expired_timers(struct timer_base *base,
       		if (time_after(next, jiffies)) {
       			/* The call site will increment clock! */
       			base->clk = jiffies - 1;
      -			return 0;
      +			return;
       		}
       		base->clk = next;
       	}
      -	return __collect_expired_timers(base, heads);
      +	__collect_expired_timers(base);
       }
       #else
      -static inline int collect_expired_timers(struct timer_base *base,
      -					 struct hlist_head *heads)
      +static inline void collect_expired_timers(struct timer_base *base)
       {
      -	return __collect_expired_timers(base, heads);
      +	__collect_expired_timers(base);
       }
       #endif
      
      +static int find_expired_timers(struct timer_base *base)
      +{
      +	const unsigned long int end_clk = jiffies;
      +
      +	while (!base->expired_count && time_after_eq(end_clk, base->clk)) {
      +		collect_expired_timers(base);
      +		base->clk++;
      +	}
      +
      +	return base->expired_count;
      +}
      +
      +/* Called from CPU tick routine to quickly collect expired timers */
      +static int tick_find_expired(struct timer_base *base)
      +{
      +	int count;
      +
      +	raw_spin_lock(&base->lock);
      +
      +	if (unlikely(time_after(jiffies, base->clk + HZ))) {
      +		/* defer to ktimersoftd; don't spend too long in irq context */
      +		count = -1;
      +	} else
      +		count = find_expired_timers(base);
      +
      +	raw_spin_unlock(&base->lock);
      +
      +	return count;
      +}
      +
       /*
        * Called from the timer interrupt handler to charge one tick to the current
        * process.  user_tick is 1 if the tick is user time, 0 for system.
      @@ -1657,22 +1704,11 @@ void update_process_times(int user_tick)
        */
       static inline void __run_timers(struct timer_base *base)
       {
      -	struct hlist_head heads[LVL_DEPTH];
      -	int levels;
      -
      -	if (!time_after_eq(jiffies, base->clk))
      -		return;
      -
       	raw_spin_lock_irq(&base->lock);
      
      -	while (time_after_eq(jiffies, base->clk)) {
      +	while (find_expired_timers(base))
      +		expire_timers(base);
      
      -		levels = collect_expired_timers(base, heads);
      -		base->clk++;
      -
      -		while (levels--)
      -			expire_timers(base, heads + levels);
      -	}
       	raw_spin_unlock_irq(&base->lock);
       	wakeup_timer_waiters(base);
       }
      @@ -1700,12 +1736,12 @@ void run_local_timers(void)
      
       	hrtimer_run_queues();
       	/* Raise the softirq only if required. */
      -	if (time_before(jiffies, base->clk)) {
      +	if (time_before(jiffies, base->clk) || !tick_find_expired(base)) {
       		if (!IS_ENABLED(CONFIG_NO_HZ_COMMON) || !base->nohz_active)
       			return;
       		/* CPU is awake, so check the deferrable base. */
       		base++;
      -		if (time_before(jiffies, base->clk))
      +		if (time_before(jiffies, base->clk) || !tick_find_expired(base))
       			return;
       	}
       	raise_softirq(TIMER_SOFTIRQ);
      @@ -1875,6 +1911,7 @@ int timers_dead_cpu(unsigned int cpu)
       		raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING);
      
       		BUG_ON(old_base->running_timer);
      +		BUG_ON(old_base->expired_count);
      
       		for (i = 0; i < WHEEL_SIZE; i++)
       			migrate_timer_list(new_base, old_base->vectors + i);
      @@ -1901,6 +1938,7 @@ static void __init init_timer_cpu(int cpu)
       #ifdef CONFIG_PREEMPT_RT_FULL
       		init_swait_queue_head(&base->wait_for_running_timer);
       #endif
      +		base->expired_count = 0;
       	}
       }
      
      diff --git a/localversion-rt b/localversion-rt
      --- a/localversion-rt
      +++ b/localversion-rt
      @@ -1 +1 @@
      --rt5
      +-rt6
      
      Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
    • Sebastian Andrzej Siewior's avatar
  4. Jan 30, 2017
    • Sebastian Andrzej Siewior's avatar
      [ANNOUNCE] v4.9.6-rt4 · de67a67a
      Sebastian Andrzej Siewior authored
      Dear RT folks!
      
      I'm pleased to announce the v4.9.6-rt4 patch set.
      
      Changes since v4.9.6-rt3:
      
        - Since the timer(s)-softirq split we could delay the wakeup the timer
          sofitrq. Patch by Mike Galbraith
      
        - The CPUSET code maybe be called with disabled interrupts and
          requires raw locks for it to succeed. Patch by Mike Galbraith.
      
        - The workaround for the radix preload code was not perfect and could
          cause failure if the code relied on it. Reported by Mike Galbraith.
      
        - Qualcomm's pinctrl driver got rawlocks. Reported by Brian Wrenn,
          patched by Julia Cartwright.
      
        - On X86, setting / changing page attributes could lead to an
          expensive (in terms of latency) but efficient (in terms of runtime)
          cache flush. In order no to hurt the latency the expensive cache has
          been disabled. Patch by John Ogness.
      
      Known issues
      	- CPU hotplug got a little better but can deadlock.
      
      The delta patch against v4.9.6-rt4 is appended below and can be found here:
      
           https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.9/incr/patch-4.9.6-rt3-rt4.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.9.6-rt4
      
      The RT patch against v4.9.6 can be found here:
      
          https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.9/older/patch-4.9.6-rt4.patch.xz
      
      The split quilt queue is available at:
      
          https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.9/older/patches-4.9.6-rt4.tar.xz
      
      
      
      Sebastian
      diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
      --- a/arch/x86/mm/pageattr.c
      +++ b/arch/x86/mm/pageattr.c
      @@ -214,7 +214,15 @@ static void cpa_flush_array(unsigned long *start, int numpages, int cache,
       			    int in_flags, struct page **pages)
       {
       	unsigned int i, level;
      +#ifdef CONFIG_PREEMPT
      +	/*
      +	 * Avoid wbinvd() because it causes latencies on all CPUs,
      +	 * regardless of any CPU isolation that may be in effect.
      +	 */
      +	unsigned long do_wbinvd = 0;
      +#else
       	unsigned long do_wbinvd = cache && numpages >= 1024; /* 4M threshold */
      +#endif
      
       	BUG_ON(irqs_disabled());
      
      diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
      --- a/drivers/pinctrl/qcom/pinctrl-msm.c
      +++ b/drivers/pinctrl/qcom/pinctrl-msm.c
      @@ -61,7 +61,7 @@ struct msm_pinctrl {
       	struct notifier_block restart_nb;
       	int irq;
      
      -	spinlock_t lock;
      +	raw_spinlock_t lock;
      
       	DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
       	DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);
      @@ -153,14 +153,14 @@ static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev,
       	if (WARN_ON(i == g->nfuncs))
       		return -EINVAL;
      
      -	spin_lock_irqsave(&pctrl->lock, flags);
      +	raw_spin_lock_irqsave(&pctrl->lock, flags);
      
       	val = readl(pctrl->regs + g->ctl_reg);
       	val &= ~mask;
       	val |= i << g->mux_bit;
       	writel(val, pctrl->regs + g->ctl_reg);
      
      -	spin_unlock_irqrestore(&pctrl->lock, flags);
      +	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
      
       	return 0;
       }
      @@ -323,14 +323,14 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
       			break;
       		case PIN_CONFIG_OUTPUT:
       			/* set output value */
      -			spin_lock_irqsave(&pctrl->lock, flags);
      +			raw_spin_lock_irqsave(&pctrl->lock, flags);
       			val = readl(pctrl->regs + g->io_reg);
       			if (arg)
       				val |= BIT(g->out_bit);
       			else
       				val &= ~BIT(g->out_bit);
       			writel(val, pctrl->regs + g->io_reg);
      -			spin_unlock_irqrestore(&pctrl->lock, flags);
      +			raw_spin_unlock_irqrestore(&pctrl->lock, flags);
      
       			/* enable output */
       			arg = 1;
      @@ -351,12 +351,12 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
       			return -EINVAL;
       		}
      
      -		spin_lock_irqsave(&pctrl->lock, flags);
      +		raw_spin_lock_irqsave(&pctrl->lock, flags);
       		val = readl(pctrl->regs + g->ctl_reg);
       		val &= ~(mask << bit);
       		val |= arg << bit;
       		writel(val, pctrl->regs + g->ctl_reg);
      -		spin_unlock_irqrestore(&pctrl->lock, flags);
      +		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
       	}
      
       	return 0;
      @@ -384,13 +384,13 @@ static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
      
       	g = &pctrl->soc->groups[offset];
      
      -	spin_lock_irqsave(&pctrl->lock, flags);
      +	raw_spin_lock_irqsave(&pctrl->lock, flags);
      
       	val = readl(pctrl->regs + g->ctl_reg);
       	val &= ~BIT(g->oe_bit);
       	writel(val, pctrl->regs + g->ctl_reg);
      
      -	spin_unlock_irqrestore(&pctrl->lock, flags);
      +	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
      
       	return 0;
       }
      @@ -404,7 +404,7 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in
      
       	g = &pctrl->soc->groups[offset];
      
      -	spin_lock_irqsave(&pctrl->lock, flags);
      +	raw_spin_lock_irqsave(&pctrl->lock, flags);
      
       	val = readl(pctrl->regs + g->io_reg);
       	if (value)
      @@ -417,7 +417,7 @@ static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, in
       	val |= BIT(g->oe_bit);
       	writel(val, pctrl->regs + g->ctl_reg);
      
      -	spin_unlock_irqrestore(&pctrl->lock, flags);
      +	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
      
       	return 0;
       }
      @@ -443,7 +443,7 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
      
       	g = &pctrl->soc->groups[offset];
      
      -	spin_lock_irqsave(&pctrl->lock, flags);
      +	raw_spin_lock_irqsave(&pctrl->lock, flags);
      
       	val = readl(pctrl->regs + g->io_reg);
       	if (value)
      @@ -452,7 +452,7 @@ static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
       		val &= ~BIT(g->out_bit);
       	writel(val, pctrl->regs + g->io_reg);
      
      -	spin_unlock_irqrestore(&pctrl->lock, flags);
      +	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
       }
      
       #ifdef CONFIG_DEBUG_FS
      @@ -571,7 +571,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
      
       	g = &pctrl->soc->groups[d->hwirq];
      
      -	spin_lock_irqsave(&pctrl->lock, flags);
      +	raw_spin_lock_irqsave(&pctrl->lock, flags);
      
       	val = readl(pctrl->regs + g->intr_cfg_reg);
       	val &= ~BIT(g->intr_enable_bit);
      @@ -579,7 +579,7 @@ static void msm_gpio_irq_mask(struct irq_data *d)
      
       	clear_bit(d->hwirq, pctrl->enabled_irqs);
      
      -	spin_unlock_irqrestore(&pctrl->lock, flags);
      +	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
       }
      
       static void msm_gpio_irq_unmask(struct irq_data *d)
      @@ -592,7 +592,7 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
      
       	g = &pctrl->soc->groups[d->hwirq];
      
      -	spin_lock_irqsave(&pctrl->lock, flags);
      +	raw_spin_lock_irqsave(&pctrl->lock, flags);
      
       	val = readl(pctrl->regs + g->intr_status_reg);
       	val &= ~BIT(g->intr_status_bit);
      @@ -604,7 +604,7 @@ static void msm_gpio_irq_unmask(struct irq_data *d)
      
       	set_bit(d->hwirq, pctrl->enabled_irqs);
      
      -	spin_unlock_irqrestore(&pctrl->lock, flags);
      +	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
       }
      
       static void msm_gpio_irq_ack(struct irq_data *d)
      @@ -617,7 +617,7 @@ static void msm_gpio_irq_ack(struct irq_data *d)
      
       	g = &pctrl->soc->groups[d->hwirq];
      
      -	spin_lock_irqsave(&pctrl->lock, flags);
      +	raw_spin_lock_irqsave(&pctrl->lock, flags);
      
       	val = readl(pctrl->regs + g->intr_status_reg);
       	if (g->intr_ack_high)
      @@ -629,7 +629,7 @@ static void msm_gpio_irq_ack(struct irq_data *d)
       	if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
       		msm_gpio_update_dual_edge_pos(pctrl, g, d);
      
      -	spin_unlock_irqrestore(&pctrl->lock, flags);
      +	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
       }
      
       static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
      @@ -642,7 +642,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
      
       	g = &pctrl->soc->groups[d->hwirq];
      
      -	spin_lock_irqsave(&pctrl->lock, flags);
      +	raw_spin_lock_irqsave(&pctrl->lock, flags);
      
       	/*
       	 * For hw without possibility of detecting both edges
      @@ -716,7 +716,7 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type)
       	if (test_bit(d->hwirq, pctrl->dual_edge_irqs))
       		msm_gpio_update_dual_edge_pos(pctrl, g, d);
      
      -	spin_unlock_irqrestore(&pctrl->lock, flags);
      +	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
      
       	if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
       		irq_set_handler_locked(d, handle_level_irq);
      @@ -732,11 +732,11 @@ static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
       	struct msm_pinctrl *pctrl = gpiochip_get_data(gc);
       	unsigned long flags;
      
      -	spin_lock_irqsave(&pctrl->lock, flags);
      +	raw_spin_lock_irqsave(&pctrl->lock, flags);
      
       	irq_set_irq_wake(pctrl->irq, on);
      
      -	spin_unlock_irqrestore(&pctrl->lock, flags);
      +	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
      
       	return 0;
       }
      @@ -882,7 +882,7 @@ int msm_pinctrl_probe(struct platform_device *pdev,
       	pctrl->soc = soc_data;
       	pctrl->chip = msm_gpio_template;
      
      -	spin_lock_init(&pctrl->lock);
      +	raw_spin_lock_init(&pctrl->lock);
      
       	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
       	pctrl->regs = devm_ioremap_resource(&pdev->dev, res);
      diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
      --- a/include/linux/radix-tree.h
      +++ b/include/linux/radix-tree.h
      @@ -289,19 +289,11 @@ unsigned int radix_tree_gang_lookup(struct radix_tree_root *root,
       unsigned int radix_tree_gang_lookup_slot(struct radix_tree_root *root,
       			void ***results, unsigned long *indices,
       			unsigned long first_index, unsigned int max_items);
      -#ifdef CONFIG_PREEMPT_RT_FULL
      -static inline int radix_tree_preload(gfp_t gm) { return 0; }
      -static inline int radix_tree_maybe_preload(gfp_t gfp_mask) { return 0; }
      -static inline int radix_tree_maybe_preload_order(gfp_t gfp_mask, int order)
      -{
      -	return 0;
      -};
      -
      -#else
       int radix_tree_preload(gfp_t gfp_mask);
       int radix_tree_maybe_preload(gfp_t gfp_mask);
       int radix_tree_maybe_preload_order(gfp_t gfp_mask, int order);
      -#endif
      +void radix_tree_preload_end(void);
      +
       void radix_tree_init(void);
       void *radix_tree_tag_set(struct radix_tree_root *root,
       			unsigned long index, unsigned int tag);
      @@ -324,11 +316,6 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
       int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag);
       unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item);
      
      -static inline void radix_tree_preload_end(void)
      -{
      -	preempt_enable_nort();
      -}
      -
       /**
        * struct radix_tree_iter - radix tree iterator state
        *
      diff --git a/kernel/cpuset.c b/kernel/cpuset.c
      --- a/kernel/cpuset.c
      +++ b/kernel/cpuset.c
      @@ -284,7 +284,7 @@ static struct cpuset top_cpuset = {
        */
      
       static DEFINE_MUTEX(cpuset_mutex);
      -static DEFINE_SPINLOCK(callback_lock);
      +static DEFINE_RAW_SPINLOCK(callback_lock);
      
       static struct workqueue_struct *cpuset_migrate_mm_wq;
      
      @@ -907,9 +907,9 @@ static void update_cpumasks_hier(struct cpuset *cs, struct cpumask *new_cpus)
       			continue;
       		rcu_read_unlock();
      
      -		spin_lock_irq(&callback_lock);
      +		raw_spin_lock_irq(&callback_lock);
       		cpumask_copy(cp->effective_cpus, new_cpus);
      -		spin_unlock_irq(&callback_lock);
      +		raw_spin_unlock_irq(&callback_lock);
      
       		WARN_ON(!cgroup_subsys_on_dfl(cpuset_cgrp_subsys) &&
       			!cpumask_equal(cp->cpus_allowed, cp->effective_cpus));
      @@ -974,9 +974,9 @@ static int update_cpumask(struct cpuset *cs, struct cpuset *trialcs,
       	if (retval < 0)
       		return retval;
      
      -	spin_lock_irq(&callback_lock);
      +	raw_spin_lock_irq(&callback_lock);
       	cpumask_copy(cs->cpus_allowed, trialcs->cpus_allowed);
      -	spin_unlock_irq(&callback_lock);
      +	raw_spin_unlock_irq(&callback_lock);
      
       	/* use trialcs->cpus_allowed as a temp variable */
       	update_cpumasks_hier(cs, trialcs->cpus_allowed);
      @@ -1176,9 +1176,9 @@ static void update_nodemasks_hier(struct cpuset *cs, nodemask_t *new_mems)
       			continue;
       		rcu_read_unlock();
      
      -		spin_lock_irq(&callback_lock);
      +		raw_spin_lock_irq(&callback_lock);
       		cp->effective_mems = *new_mems;
      -		spin_unlock_irq(&callback_lock);
      +		raw_spin_unlock_irq(&callback_lock);
      
       		WARN_ON(!cgroup_subsys_on_dfl(cpuset_cgrp_subsys) &&
       			!nodes_equal(cp->mems_allowed, cp->effective_mems));
      @@ -1246,9 +1246,9 @@ static int update_nodemask(struct cpuset *cs, struct cpuset *trialcs,
       	if (retval < 0)
       		goto done;
      
      -	spin_lock_irq(&callback_lock);
      +	raw_spin_lock_irq(&callback_lock);
       	cs->mems_allowed = trialcs->mems_allowed;
      -	spin_unlock_irq(&callback_lock);
      +	raw_spin_unlock_irq(&callback_lock);
      
       	/* use trialcs->mems_allowed as a temp variable */
       	update_nodemasks_hier(cs, &trialcs->mems_allowed);
      @@ -1339,9 +1339,9 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs,
       	spread_flag_changed = ((is_spread_slab(cs) != is_spread_slab(trialcs))
       			|| (is_spread_page(cs) != is_spread_page(trialcs)));
      
      -	spin_lock_irq(&callback_lock);
      +	raw_spin_lock_irq(&callback_lock);
       	cs->flags = trialcs->flags;
      -	spin_unlock_irq(&callback_lock);
      +	raw_spin_unlock_irq(&callback_lock);
      
       	if (!cpumask_empty(trialcs->cpus_allowed) && balance_flag_changed)
       		rebuild_sched_domains_locked();
      @@ -1756,7 +1756,7 @@ static int cpuset_common_seq_show(struct seq_file *sf, void *v)
       	cpuset_filetype_t type = seq_cft(sf)->private;
       	int ret = 0;
      
      -	spin_lock_irq(&callback_lock);
      +	raw_spin_lock_irq(&callback_lock);
      
       	switch (type) {
       	case FILE_CPULIST:
      @@ -1775,7 +1775,7 @@ static int cpuset_common_seq_show(struct seq_file *sf, void *v)
       		ret = -EINVAL;
       	}
      
      -	spin_unlock_irq(&callback_lock);
      +	raw_spin_unlock_irq(&callback_lock);
       	return ret;
       }
      
      @@ -1989,12 +1989,12 @@ static int cpuset_css_online(struct cgroup_subsys_state *css)
      
       	cpuset_inc();
      
      -	spin_lock_irq(&callback_lock);
      +	raw_spin_lock_irq(&callback_lock);
       	if (cgroup_subsys_on_dfl(cpuset_cgrp_subsys)) {
       		cpumask_copy(cs->effective_cpus, parent->effective_cpus);
       		cs->effective_mems = parent->effective_mems;
       	}
      -	spin_unlock_irq(&callback_lock);
      +	raw_spin_unlock_irq(&callback_lock);
      
       	if (!test_bit(CGRP_CPUSET_CLONE_CHILDREN, &css->cgroup->flags))
       		goto out_unlock;
      @@ -2021,12 +2021,12 @@ static int cpuset_css_online(struct cgroup_subsys_state *css)
       	}
       	rcu_read_unlock();
      
      -	spin_lock_irq(&callback_lock);
      +	raw_spin_lock_irq(&callback_lock);
       	cs->mems_allowed = parent->mems_allowed;
       	cs->effective_mems = parent->mems_allowed;
       	cpumask_copy(cs->cpus_allowed, parent->cpus_allowed);
       	cpumask_copy(cs->effective_cpus, parent->cpus_allowed);
      -	spin_unlock_irq(&callback_lock);
      +	raw_spin_unlock_irq(&callback_lock);
       out_unlock:
       	mutex_unlock(&cpuset_mutex);
       	return 0;
      @@ -2065,7 +2065,7 @@ static void cpuset_css_free(struct cgroup_subsys_state *css)
       static void cpuset_bind(struct cgroup_subsys_state *root_css)
       {
       	mutex_lock(&cpuset_mutex);
      -	spin_lock_irq(&callback_lock);
      +	raw_spin_lock_irq(&callback_lock);
      
       	if (cgroup_subsys_on_dfl(cpuset_cgrp_subsys)) {
       		cpumask_copy(top_cpuset.cpus_allowed, cpu_possible_mask);
      @@ -2076,7 +2076,7 @@ static void cpuset_bind(struct cgroup_subsys_state *root_css)
       		top_cpuset.mems_allowed = top_cpuset.effective_mems;
       	}
      
      -	spin_unlock_irq(&callback_lock);
      +	raw_spin_unlock_irq(&callback_lock);
       	mutex_unlock(&cpuset_mutex);
       }
      
      @@ -2177,12 +2177,12 @@ hotplug_update_tasks_legacy(struct cpuset *cs,
       {
       	bool is_empty;
      
      -	spin_lock_irq(&callback_lock);
      +	raw_spin_lock_irq(&callback_lock);
       	cpumask_copy(cs->cpus_allowed, new_cpus);
       	cpumask_copy(cs->effective_cpus, new_cpus);
       	cs->mems_allowed = *new_mems;
       	cs->effective_mems = *new_mems;
      -	spin_unlock_irq(&callback_lock);
      +	raw_spin_unlock_irq(&callback_lock);
      
       	/*
       	 * Don't call update_tasks_cpumask() if the cpuset becomes empty,
      @@ -2219,10 +2219,10 @@ hotplug_update_tasks(struct cpuset *cs,
       	if (nodes_empty(*new_mems))
       		*new_mems = parent_cs(cs)->effective_mems;
      
      -	spin_lock_irq(&callback_lock);
      +	raw_spin_lock_irq(&callback_lock);
       	cpumask_copy(cs->effective_cpus, new_cpus);
       	cs->effective_mems = *new_mems;
      -	spin_unlock_irq(&callback_lock);
      +	raw_spin_unlock_irq(&callback_lock);
      
       	if (cpus_updated)
       		update_tasks_cpumask(cs);
      @@ -2308,21 +2308,21 @@ static void cpuset_hotplug_workfn(struct work_struct *work)
      
       	/* synchronize cpus_allowed to cpu_active_mask */
       	if (cpus_updated) {
      -		spin_lock_irq(&callback_lock);
      +		raw_spin_lock_irq(&callback_lock);
       		if (!on_dfl)
       			cpumask_copy(top_cpuset.cpus_allowed, &new_cpus);
       		cpumask_copy(top_cpuset.effective_cpus, &new_cpus);
      -		spin_unlock_irq(&callback_lock);
      +		raw_spin_unlock_irq(&callback_lock);
       		/* we don't mess with cpumasks of tasks in top_cpuset */
       	}
      
       	/* synchronize mems_allowed to N_MEMORY */
       	if (mems_updated) {
      -		spin_lock_irq(&callback_lock);
      +		raw_spin_lock_irq(&callback_lock);
       		if (!on_dfl)
       			top_cpuset.mems_allowed = new_mems;
       		top_cpuset.effective_mems = new_mems;
      -		spin_unlock_irq(&callback_lock);
      +		raw_spin_unlock_irq(&callback_lock);
       		update_tasks_nodemask(&top_cpuset);
       	}
      
      @@ -2420,11 +2420,11 @@ void cpuset_cpus_allowed(struct task_struct *tsk, struct cpumask *pmask)
       {
       	unsigned long flags;
      
      -	spin_lock_irqsave(&callback_lock, flags);
      +	raw_spin_lock_irqsave(&callback_lock, flags);
       	rcu_read_lock();
       	guarantee_online_cpus(task_cs(tsk), pmask);
       	rcu_read_unlock();
      -	spin_unlock_irqrestore(&callback_lock, flags);
      +	raw_spin_unlock_irqrestore(&callback_lock, flags);
       }
      
       void cpuset_cpus_allowed_fallback(struct task_struct *tsk)
      @@ -2472,11 +2472,11 @@ nodemask_t cpuset_mems_allowed(struct task_struct *tsk)
       	nodemask_t mask;
       	unsigned long flags;
      
      -	spin_lock_irqsave(&callback_lock, flags);
      +	raw_spin_lock_irqsave(&callback_lock, flags);
       	rcu_read_lock();
       	guarantee_online_mems(task_cs(tsk), &mask);
       	rcu_read_unlock();
      -	spin_unlock_irqrestore(&callback_lock, flags);
      +	raw_spin_unlock_irqrestore(&callback_lock, flags);
      
       	return mask;
       }
      @@ -2568,14 +2568,14 @@ bool __cpuset_node_allowed(int node, gfp_t gfp_mask)
       		return true;
      
       	/* Not hardwall and node outside mems_allowed: scan up cpusets */
      -	spin_lock_irqsave(&callback_lock, flags);
      +	raw_spin_lock_irqsave(&callback_lock, flags);
      
       	rcu_read_lock();
       	cs = nearest_hardwall_ancestor(task_cs(current));
       	allowed = node_isset(node, cs->mems_allowed);
       	rcu_read_unlock();
      
      -	spin_unlock_irqrestore(&callback_lock, flags);
      +	raw_spin_unlock_irqrestore(&callback_lock, flags);
       	return allowed;
       }
      
      diff --git a/kernel/softirq.c b/kernel/softirq.c
      --- a/kernel/softirq.c
      +++ b/kernel/softirq.c
      @@ -206,6 +206,7 @@ static void handle_softirq(unsigned int vec_nr)
       	}
       }
      
      +#ifndef CONFIG_PREEMPT_RT_FULL
       /*
        * If ksoftirqd is scheduled, we do not want to process pending softirqs
        * right now. Let ksoftirqd handle this at its own rate, to get fairness.
      @@ -217,7 +218,6 @@ static bool ksoftirqd_running(void)
       	return tsk && (tsk->state == TASK_RUNNING);
       }
      
      -#ifndef CONFIG_PREEMPT_RT_FULL
       static inline int ksoftirqd_softirq_pending(void)
       {
       	return local_softirq_pending();
      @@ -794,13 +794,10 @@ void irq_enter(void)
      
       static inline void invoke_softirq(void)
       {
      -#ifdef CONFIG_PREEMPT_RT_FULL
      -	unsigned long flags;
      -#endif
      -
      +#ifndef CONFIG_PREEMPT_RT_FULL
       	if (ksoftirqd_running())
       		return;
      -#ifndef CONFIG_PREEMPT_RT_FULL
      +
       	if (!force_irqthreads) {
       #ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
       		/*
      @@ -821,6 +818,7 @@ static inline void invoke_softirq(void)
       		wakeup_softirqd();
       	}
       #else /* PREEMPT_RT_FULL */
      +	unsigned long flags;
      
       	local_irq_save(flags);
       	if (__this_cpu_read(ksoftirqd) &&
      diff --git a/lib/radix-tree.c b/lib/radix-tree.c
      --- a/lib/radix-tree.c
      +++ b/lib/radix-tree.c
      @@ -36,7 +36,7 @@
       #include <linux/bitops.h>
       #include <linux/rcupdate.h>
       #include <linux/preempt.h>		/* in_interrupt() */
      -
      +#include <linux/locallock.h>
      
       /* Number of nodes in fully populated tree of given height */
       static unsigned long height_to_maxnodes[RADIX_TREE_MAX_PATH + 1] __read_mostly;
      @@ -68,6 +68,7 @@ struct radix_tree_preload {
       	struct radix_tree_node *nodes;
       };
       static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, };
      +static DEFINE_LOCAL_IRQ_LOCK(radix_tree_preloads_lock);
      
       static inline void *node_to_entry(void *ptr)
       {
      @@ -290,14 +291,14 @@ radix_tree_node_alloc(struct radix_tree_root *root)
       		 * succeed in getting a node here (and never reach
       		 * kmem_cache_alloc)
       		 */
      -		rtp = &get_cpu_var(radix_tree_preloads);
      +		rtp = &get_locked_var(radix_tree_preloads_lock, radix_tree_preloads);
       		if (rtp->nr) {
       			ret = rtp->nodes;
       			rtp->nodes = ret->private_data;
       			ret->private_data = NULL;
       			rtp->nr--;
       		}
      -		put_cpu_var(radix_tree_preloads);
      +		put_locked_var(radix_tree_preloads_lock, radix_tree_preloads);
       		/*
       		 * Update the allocation stack trace as this is more useful
       		 * for debugging.
      @@ -337,7 +338,6 @@ radix_tree_node_free(struct radix_tree_node *node)
       	call_rcu(&node->rcu_head, radix_tree_node_rcu_free);
       }
      
      -#ifndef CONFIG_PREEMPT_RT_FULL
       /*
        * Load up this CPU's radix_tree_node buffer with sufficient objects to
        * ensure that the addition of a single element in the tree cannot fail.  On
      @@ -359,14 +359,14 @@ static int __radix_tree_preload(gfp_t gfp_mask, int nr)
       	 */
       	gfp_mask &= ~__GFP_ACCOUNT;
      
      -	preempt_disable();
      +	local_lock(radix_tree_preloads_lock);
       	rtp = this_cpu_ptr(&radix_tree_preloads);
       	while (rtp->nr < nr) {
      -		preempt_enable();
      +		local_unlock(radix_tree_preloads_lock);
       		node = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask);
       		if (node == NULL)
       			goto out;
      -		preempt_disable();
      +		local_lock(radix_tree_preloads_lock);
       		rtp = this_cpu_ptr(&radix_tree_preloads);
       		if (rtp->nr < nr) {
       			node->private_data = rtp->nodes;
      @@ -408,7 +408,7 @@ int radix_tree_maybe_preload(gfp_t gfp_mask)
       	if (gfpflags_allow_blocking(gfp_mask))
       		return __radix_tree_preload(gfp_mask, RADIX_TREE_PRELOAD_SIZE);
       	/* Preloading doesn't help anything with this gfp mask, skip it */
      -	preempt_disable();
      +	local_lock(radix_tree_preloads_lock);
       	return 0;
       }
       EXPORT_SYMBOL(radix_tree_maybe_preload);
      @@ -424,7 +424,7 @@ int radix_tree_maybe_preload_order(gfp_t gfp_mask, int order)
      
       	/* Preloading doesn't help anything with this gfp mask, skip it */
       	if (!gfpflags_allow_blocking(gfp_mask)) {
      -		preempt_disable();
      +		local_lock(radix_tree_preloads_lock);
       		return 0;
       	}
      
      @@ -457,7 +457,12 @@ int radix_tree_maybe_preload_order(gfp_t gfp_mask, int order)
      
       	return __radix_tree_preload(gfp_mask, nr_nodes);
       }
      -#endif
      +
      +void radix_tree_preload_end(void)
      +{
      +	local_unlock(radix_tree_preloads_lock);
      +}
      +EXPORT_SYMBOL(radix_tree_preload_end);
      
       /*
        * The maximum index which can be stored in a radix tree
      diff --git a/localversion-rt b/localversion-rt
      --- a/localversion-rt
      +++ b/localversion-rt
      @@ -1 +1 @@
      --rt3
      +-rt4
      
      Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
    • Sebastian Andrzej Siewior's avatar
  5. Jan 20, 2017
  6. Dec 23, 2016
  7. Dec 12, 2016
    • Sebastian Andrzej Siewior's avatar
      [ANNOUNCE] v4.8.14-rt9 · af8baa07
      Sebastian Andrzej Siewior authored
      Dear RT folks!
      
      I'm pleased to announce the v4.8.14-rt9 patch set.
      
      Changes since v4.8.14-rt8:
      
        - If network interface is removed we move all skbs which are active to
          a list and free it later. The hunk where the list was cleaned up was
          lost and is back.
      
        - bnx2x and a few others could corrupt their ->poll_list. Patch by
          Steven Rostedt.
      
        - A missing RCU section in the workqueue code could lead to a "use after
          free" condition if the worqueue was removed. Reported by John Keeping
      
      Known issues
      	- CPU hotplug got a little better but can deadlock.
      
      The delta patch against v4.8.14-rt9 is appended below and can be found here:
      
           https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.8/incr/patch-4.8.14-rt8-rt9.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.8.14-rt9
      
      The RT patch against v4.8.14 can be found here:
      
          https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.8/patch-4.8.14-rt9.patch.xz
      
      The split quilt queue is available at:
      
          https://cdn.kernel.org/pub/linux/kernel/projects/rt/4.8/patches-4.8.14-rt9.tar.xz
      
      
      
      Sebastian
      diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
      --- a/include/linux/netdevice.h
      +++ b/include/linux/netdevice.h
      @@ -395,7 +395,19 @@ typedef enum rx_handler_result rx_handler_result_t;
       typedef rx_handler_result_t rx_handler_func_t(struct sk_buff **pskb);
      
       void __napi_schedule(struct napi_struct *n);
      +
      +/*
      + * When PREEMPT_RT_FULL is defined, all device interrupt handlers
      + * run as threads, and they can also be preempted (without PREEMPT_RT
      + * interrupt threads can not be preempted). Which means that calling
      + * __napi_schedule_irqoff() from an interrupt handler can be preempted
      + * and can corrupt the napi->poll_list.
      + */
      +#ifdef CONFIG_PREEMPT_RT_FULL
      +#define __napi_schedule_irqoff(n) __napi_schedule(n)
      +#else
       void __napi_schedule_irqoff(struct napi_struct *n);
      +#endif
      
       static inline bool napi_disable_pending(struct napi_struct *n)
       {
      diff --git a/kernel/workqueue.c b/kernel/workqueue.c
      --- a/kernel/workqueue.c
      +++ b/kernel/workqueue.c
      @@ -1127,9 +1127,11 @@ static void put_pwq_unlocked(struct pool_workqueue *pwq)
       		 * As both pwqs and pools are RCU protected, the
       		 * following lock operations are safe.
       		 */
      +		rcu_read_lock();
       		local_spin_lock_irq(pendingb_lock, &pwq->pool->lock);
       		put_pwq(pwq);
       		local_spin_unlock_irq(pendingb_lock, &pwq->pool->lock);
      +		rcu_read_unlock();
       	}
       }
      
      diff --git a/localversion-rt b/localversion-rt
      --- a/localversion-rt
      +++ b/localversion-rt
      @@ -1 +1 @@
      --rt8
      +-rt9
      diff --git a/net/core/dev.c b/net/core/dev.c
      --- a/net/core/dev.c
      +++ b/net/core/dev.c
      @@ -4912,6 +4912,7 @@ void __napi_schedule(struct napi_struct *n)
       }
       EXPORT_SYMBOL(__napi_schedule);
      
      +#ifndef CONFIG_PREEMPT_RT_FULL
       /**
        * __napi_schedule_irqoff - schedule for receive
        * @n: entry to schedule
      @@ -4923,6 +4924,7 @@ void __napi_schedule_irqoff(struct napi_struct *n)
       	____napi_schedule(this_cpu_ptr(&softnet_data), n);
       }
       EXPORT_SYMBOL(__napi_schedule_irqoff);
      +#endif
      
       void __napi_complete(struct napi_struct *n)
       {
      @@ -5212,13 +5214,21 @@ static void net_rx_action(struct softirq_action *h)
       	struct softnet_data *sd = this_cpu_ptr(&softnet_data);
       	unsigned long time_limit = jiffies + 2;
       	int budget = netdev_budget;
      +	struct sk_buff_head tofree_q;
      +	struct sk_buff *skb;
       	LIST_HEAD(list);
       	LIST_HEAD(repoll);
      
      +	__skb_queue_head_init(&tofree_q);
      +
       	local_irq_disable();
      +	skb_queue_splice_init(&sd->tofree_queue, &tofree_q);
       	list_splice_init(&sd->poll_list, &list);
       	local_irq_enable();
      
      +	while ((skb = __skb_dequeue(&tofree_q)))
      +		kfree_skb(skb);
      +
       	for (;;) {
       		struct napi_struct *n;
      
      Signed-off-by: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
    • Sebastian Andrzej Siewior's avatar
  8. Dec 01, 2016
  9. Oct 31, 2016
  10. Oct 24, 2016
  11. Oct 17, 2016
  12. Oct 06, 2016
  13. Sep 30, 2016
  14. Sep 15, 2016
  15. Sep 08, 2016
  16. Aug 22, 2016
  17. Aug 05, 2016
  18. Jul 29, 2016
  19. Jul 15, 2016
  20. Jul 14, 2016
  21. Jul 12, 2016
  22. Jun 10, 2016
  23. Jun 03, 2016
  24. Jun 02, 2016
  25. May 13, 2016
  26. May 06, 2016
  27. Apr 15, 2016
  28. Apr 08, 2016
  29. Apr 01, 2016
  30. Mar 29, 2016
  31. Mar 09, 2016
Loading