diff options
Diffstat (limited to 'kernel/sched')
| -rw-r--r-- | kernel/sched/core.c | 80 | ||||
| -rw-r--r-- | kernel/sched/cpudeadline.c | 37 | ||||
| -rw-r--r-- | kernel/sched/cpudeadline.h | 6 | ||||
| -rw-r--r-- | kernel/sched/cpupri.c | 10 | ||||
| -rw-r--r-- | kernel/sched/cpupri.h | 2 | ||||
| -rw-r--r-- | kernel/sched/cputime.c | 32 | ||||
| -rw-r--r-- | kernel/sched/deadline.c | 16 | ||||
| -rw-r--r-- | kernel/sched/fair.c | 32 | ||||
| -rw-r--r-- | kernel/sched/rt.c | 7 | ||||
| -rw-r--r-- | kernel/sched/sched.h | 9 | 
10 files changed, 153 insertions, 78 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 268a45ea238c..0a7251678982 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -2192,7 +2192,7 @@ static inline void post_schedule(struct rq *rq)   * schedule_tail - first thing a freshly forked thread must call.   * @prev: the thread we just switched away from.   */ -asmlinkage void schedule_tail(struct task_struct *prev) +asmlinkage __visible void schedule_tail(struct task_struct *prev)  	__releases(rq->lock)  {  	struct rq *rq = this_rq(); @@ -2592,8 +2592,14 @@ pick_next_task(struct rq *rq, struct task_struct *prev)  	if (likely(prev->sched_class == class &&  		   rq->nr_running == rq->cfs.h_nr_running)) {  		p = fair_sched_class.pick_next_task(rq, prev); -		if (likely(p && p != RETRY_TASK)) -			return p; +		if (unlikely(p == RETRY_TASK)) +			goto again; + +		/* assumes fair_sched_class->next == idle_sched_class */ +		if (unlikely(!p)) +			p = idle_sched_class.pick_next_task(rq, prev); + +		return p;  	}  again: @@ -2741,7 +2747,7 @@ static inline void sched_submit_work(struct task_struct *tsk)  		blk_schedule_flush_plug(tsk);  } -asmlinkage void __sched schedule(void) +asmlinkage __visible void __sched schedule(void)  {  	struct task_struct *tsk = current; @@ -2751,7 +2757,7 @@ asmlinkage void __sched schedule(void)  EXPORT_SYMBOL(schedule);  #ifdef CONFIG_CONTEXT_TRACKING -asmlinkage void __sched schedule_user(void) +asmlinkage __visible void __sched schedule_user(void)  {  	/*  	 * If we come here after a random call to set_need_resched(), @@ -2783,7 +2789,7 @@ void __sched schedule_preempt_disabled(void)   * off of preempt_enable. Kernel preemptions off return from interrupt   * occur there and call schedule directly.   */ -asmlinkage void __sched notrace preempt_schedule(void) +asmlinkage __visible void __sched notrace preempt_schedule(void)  {  	/*  	 * If there is a non-zero preempt_count or interrupts are disabled, @@ -2813,7 +2819,7 @@ EXPORT_SYMBOL(preempt_schedule);   * Note, that this is called and return with irqs disabled. This will   * protect us against recursive calling from irq.   */ -asmlinkage void __sched preempt_schedule_irq(void) +asmlinkage __visible void __sched preempt_schedule_irq(void)  {  	enum ctx_state prev_state; @@ -3124,6 +3130,7 @@ __setparam_dl(struct task_struct *p, const struct sched_attr *attr)  	dl_se->dl_bw = to_ratio(dl_se->dl_period, dl_se->dl_runtime);  	dl_se->dl_throttled = 0;  	dl_se->dl_new = 1; +	dl_se->dl_yielded = 0;  }  static void __setscheduler_params(struct task_struct *p, @@ -3188,17 +3195,40 @@ __getparam_dl(struct task_struct *p, struct sched_attr *attr)   * We ask for the deadline not being zero, and greater or equal   * than the runtime, as well as the period of being zero or   * greater than deadline. Furthermore, we have to be sure that - * user parameters are above the internal resolution (1us); we - * check sched_runtime only since it is always the smaller one. + * user parameters are above the internal resolution of 1us (we + * check sched_runtime only since it is always the smaller one) and + * below 2^63 ns (we have to check both sched_deadline and + * sched_period, as the latter can be zero).   */  static bool  __checkparam_dl(const struct sched_attr *attr)  { -	return attr && attr->sched_deadline != 0 && -		(attr->sched_period == 0 || -		(s64)(attr->sched_period   - attr->sched_deadline) >= 0) && -		(s64)(attr->sched_deadline - attr->sched_runtime ) >= 0  && -		attr->sched_runtime >= (2 << (DL_SCALE - 1)); +	/* deadline != 0 */ +	if (attr->sched_deadline == 0) +		return false; + +	/* +	 * Since we truncate DL_SCALE bits, make sure we're at least +	 * that big. +	 */ +	if (attr->sched_runtime < (1ULL << DL_SCALE)) +		return false; + +	/* +	 * Since we use the MSB for wrap-around and sign issues, make +	 * sure it's not set (mind that period can be equal to zero). +	 */ +	if (attr->sched_deadline & (1ULL << 63) || +	    attr->sched_period & (1ULL << 63)) +		return false; + +	/* runtime <= deadline <= period (if period != 0) */ +	if ((attr->sched_period != 0 && +	     attr->sched_period < attr->sched_deadline) || +	    attr->sched_deadline < attr->sched_runtime) +		return false; + +	return true;  }  /* @@ -3639,6 +3669,7 @@ SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param)   * sys_sched_setattr - same as above, but with extended sched_attr   * @pid: the pid in question.   * @uattr: structure containing the extended parameters. + * @flags: for future extension.   */  SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr,  			       unsigned int, flags) @@ -3650,8 +3681,12 @@ SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr,  	if (!uattr || pid < 0 || flags)  		return -EINVAL; -	if (sched_copy_attr(uattr, &attr)) -		return -EFAULT; +	retval = sched_copy_attr(uattr, &attr); +	if (retval) +		return retval; + +	if (attr.sched_policy < 0) +		return -EINVAL;  	rcu_read_lock();  	retval = -ESRCH; @@ -3701,7 +3736,7 @@ SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid)   */  SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param)  { -	struct sched_param lp; +	struct sched_param lp = { .sched_priority = 0 };  	struct task_struct *p;  	int retval; @@ -3718,11 +3753,8 @@ SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param)  	if (retval)  		goto out_unlock; -	if (task_has_dl_policy(p)) { -		retval = -EINVAL; -		goto out_unlock; -	} -	lp.sched_priority = p->rt_priority; +	if (task_has_rt_policy(p)) +		lp.sched_priority = p->rt_priority;  	rcu_read_unlock();  	/* @@ -3783,6 +3815,7 @@ err_size:   * @pid: the pid in question.   * @uattr: structure containing the extended parameters.   * @size: sizeof(attr) for fwd/bwd comp. + * @flags: for future extension.   */  SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,  		unsigned int, size, unsigned int, flags) @@ -5043,7 +5076,6 @@ static int sched_cpu_active(struct notifier_block *nfb,  				      unsigned long action, void *hcpu)  {  	switch (action & ~CPU_TASKS_FROZEN) { -	case CPU_STARTING:  	case CPU_DOWN_FAILED:  		set_cpu_active((long)hcpu, true);  		return NOTIFY_OK; @@ -6017,6 +6049,8 @@ sd_numa_init(struct sched_domain_topology_level *tl, int cpu)  					,  		.last_balance		= jiffies,  		.balance_interval	= sd_weight, +		.max_newidle_lb_cost	= 0, +		.next_decay_max_lb_cost	= jiffies,  	};  	SD_INIT_NAME(sd, NUMA);  	sd->private = &tl->data; diff --git a/kernel/sched/cpudeadline.c b/kernel/sched/cpudeadline.c index 5b9bb42b2d47..bd95963dae80 100644 --- a/kernel/sched/cpudeadline.c +++ b/kernel/sched/cpudeadline.c @@ -13,6 +13,7 @@  #include <linux/gfp.h>  #include <linux/kernel.h> +#include <linux/slab.h>  #include "cpudeadline.h"  static inline int parent(int i) @@ -39,8 +40,10 @@ static void cpudl_exchange(struct cpudl *cp, int a, int b)  {  	int cpu_a = cp->elements[a].cpu, cpu_b = cp->elements[b].cpu; -	swap(cp->elements[a], cp->elements[b]); -	swap(cp->cpu_to_idx[cpu_a], cp->cpu_to_idx[cpu_b]); +	swap(cp->elements[a].cpu, cp->elements[b].cpu); +	swap(cp->elements[a].dl , cp->elements[b].dl ); + +	swap(cp->elements[cpu_a].idx, cp->elements[cpu_b].idx);  }  static void cpudl_heapify(struct cpudl *cp, int idx) @@ -140,7 +143,7 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl, int is_valid)  	WARN_ON(!cpu_present(cpu));  	raw_spin_lock_irqsave(&cp->lock, flags); -	old_idx = cp->cpu_to_idx[cpu]; +	old_idx = cp->elements[cpu].idx;  	if (!is_valid) {  		/* remove item */  		if (old_idx == IDX_INVALID) { @@ -155,8 +158,8 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl, int is_valid)  		cp->elements[old_idx].dl = cp->elements[cp->size - 1].dl;  		cp->elements[old_idx].cpu = new_cpu;  		cp->size--; -		cp->cpu_to_idx[new_cpu] = old_idx; -		cp->cpu_to_idx[cpu] = IDX_INVALID; +		cp->elements[new_cpu].idx = old_idx; +		cp->elements[cpu].idx = IDX_INVALID;  		while (old_idx > 0 && dl_time_before(  				cp->elements[parent(old_idx)].dl,  				cp->elements[old_idx].dl)) { @@ -173,7 +176,7 @@ void cpudl_set(struct cpudl *cp, int cpu, u64 dl, int is_valid)  		cp->size++;  		cp->elements[cp->size - 1].dl = 0;  		cp->elements[cp->size - 1].cpu = cpu; -		cp->cpu_to_idx[cpu] = cp->size - 1; +		cp->elements[cpu].idx = cp->size - 1;  		cpudl_change_key(cp, cp->size - 1, dl);  		cpumask_clear_cpu(cpu, cp->free_cpus);  	} else { @@ -195,10 +198,21 @@ int cpudl_init(struct cpudl *cp)  	memset(cp, 0, sizeof(*cp));  	raw_spin_lock_init(&cp->lock);  	cp->size = 0; -	for (i = 0; i < NR_CPUS; i++) -		cp->cpu_to_idx[i] = IDX_INVALID; -	if (!alloc_cpumask_var(&cp->free_cpus, GFP_KERNEL)) + +	cp->elements = kcalloc(nr_cpu_ids, +			       sizeof(struct cpudl_item), +			       GFP_KERNEL); +	if (!cp->elements) +		return -ENOMEM; + +	if (!alloc_cpumask_var(&cp->free_cpus, GFP_KERNEL)) { +		kfree(cp->elements);  		return -ENOMEM; +	} + +	for_each_possible_cpu(i) +		cp->elements[i].idx = IDX_INVALID; +  	cpumask_setall(cp->free_cpus);  	return 0; @@ -210,7 +224,6 @@ int cpudl_init(struct cpudl *cp)   */  void cpudl_cleanup(struct cpudl *cp)  { -	/* -	 * nothing to do for the moment -	 */ +	free_cpumask_var(cp->free_cpus); +	kfree(cp->elements);  } diff --git a/kernel/sched/cpudeadline.h b/kernel/sched/cpudeadline.h index a202789a412c..538c9796ad4a 100644 --- a/kernel/sched/cpudeadline.h +++ b/kernel/sched/cpudeadline.h @@ -5,17 +5,17 @@  #define IDX_INVALID     -1 -struct array_item { +struct cpudl_item {  	u64 dl;  	int cpu; +	int idx;  };  struct cpudl {  	raw_spinlock_t lock;  	int size; -	int cpu_to_idx[NR_CPUS]; -	struct array_item elements[NR_CPUS];  	cpumask_var_t free_cpus; +	struct cpudl_item *elements;  }; diff --git a/kernel/sched/cpupri.c b/kernel/sched/cpupri.c index 8b836b376d91..8834243abee2 100644 --- a/kernel/sched/cpupri.c +++ b/kernel/sched/cpupri.c @@ -30,6 +30,7 @@  #include <linux/gfp.h>  #include <linux/sched.h>  #include <linux/sched/rt.h> +#include <linux/slab.h>  #include "cpupri.h"  /* Convert between a 140 based task->prio, and our 102 based cpupri */ @@ -70,8 +71,7 @@ int cpupri_find(struct cpupri *cp, struct task_struct *p,  	int idx = 0;  	int task_pri = convert_prio(p->prio); -	if (task_pri >= MAX_RT_PRIO) -		return 0; +	BUG_ON(task_pri >= CPUPRI_NR_PRIORITIES);  	for (idx = 0; idx < task_pri; idx++) {  		struct cpupri_vec *vec  = &cp->pri_to_cpu[idx]; @@ -219,8 +219,13 @@ int cpupri_init(struct cpupri *cp)  			goto cleanup;  	} +	cp->cpu_to_pri = kcalloc(nr_cpu_ids, sizeof(int), GFP_KERNEL); +	if (!cp->cpu_to_pri) +		goto cleanup; +  	for_each_possible_cpu(i)  		cp->cpu_to_pri[i] = CPUPRI_INVALID; +  	return 0;  cleanup: @@ -237,6 +242,7 @@ void cpupri_cleanup(struct cpupri *cp)  {  	int i; +	kfree(cp->cpu_to_pri);  	for (i = 0; i < CPUPRI_NR_PRIORITIES; i++)  		free_cpumask_var(cp->pri_to_cpu[i].mask);  } diff --git a/kernel/sched/cpupri.h b/kernel/sched/cpupri.h index f6d756173491..6b033347fdfd 100644 --- a/kernel/sched/cpupri.h +++ b/kernel/sched/cpupri.h @@ -17,7 +17,7 @@ struct cpupri_vec {  struct cpupri {  	struct cpupri_vec pri_to_cpu[CPUPRI_NR_PRIORITIES]; -	int               cpu_to_pri[NR_CPUS]; +	int *cpu_to_pri;  };  #ifdef CONFIG_SMP diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index a95097cb4591..72fdf06ef865 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -332,50 +332,50 @@ out:   * softirq as those do not count in task exec_runtime any more.   */  static void irqtime_account_process_tick(struct task_struct *p, int user_tick, -						struct rq *rq) +					 struct rq *rq, int ticks)  { -	cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy); +	cputime_t scaled = cputime_to_scaled(cputime_one_jiffy); +	u64 cputime = (__force u64) cputime_one_jiffy;  	u64 *cpustat = kcpustat_this_cpu->cpustat;  	if (steal_account_process_tick())  		return; +	cputime *= ticks; +	scaled *= ticks; +  	if (irqtime_account_hi_update()) { -		cpustat[CPUTIME_IRQ] += (__force u64) cputime_one_jiffy; +		cpustat[CPUTIME_IRQ] += cputime;  	} else if (irqtime_account_si_update()) { -		cpustat[CPUTIME_SOFTIRQ] += (__force u64) cputime_one_jiffy; +		cpustat[CPUTIME_SOFTIRQ] += cputime;  	} else if (this_cpu_ksoftirqd() == p) {  		/*  		 * ksoftirqd time do not get accounted in cpu_softirq_time.  		 * So, we have to handle it separately here.  		 * Also, p->stime needs to be updated for ksoftirqd.  		 */ -		__account_system_time(p, cputime_one_jiffy, one_jiffy_scaled, -					CPUTIME_SOFTIRQ); +		__account_system_time(p, cputime, scaled, CPUTIME_SOFTIRQ);  	} else if (user_tick) { -		account_user_time(p, cputime_one_jiffy, one_jiffy_scaled); +		account_user_time(p, cputime, scaled);  	} else if (p == rq->idle) { -		account_idle_time(cputime_one_jiffy); +		account_idle_time(cputime);  	} else if (p->flags & PF_VCPU) { /* System time or guest time */ -		account_guest_time(p, cputime_one_jiffy, one_jiffy_scaled); +		account_guest_time(p, cputime, scaled);  	} else { -		__account_system_time(p, cputime_one_jiffy, one_jiffy_scaled, -					CPUTIME_SYSTEM); +		__account_system_time(p, cputime, scaled,	CPUTIME_SYSTEM);  	}  }  static void irqtime_account_idle_ticks(int ticks)  { -	int i;  	struct rq *rq = this_rq(); -	for (i = 0; i < ticks; i++) -		irqtime_account_process_tick(current, 0, rq); +	irqtime_account_process_tick(current, 0, rq, ticks);  }  #else /* CONFIG_IRQ_TIME_ACCOUNTING */  static inline void irqtime_account_idle_ticks(int ticks) {}  static inline void irqtime_account_process_tick(struct task_struct *p, int user_tick, -						struct rq *rq) {} +						struct rq *rq, int nr_ticks) {}  #endif /* CONFIG_IRQ_TIME_ACCOUNTING */  /* @@ -464,7 +464,7 @@ void account_process_tick(struct task_struct *p, int user_tick)  		return;  	if (sched_clock_irqtime) { -		irqtime_account_process_tick(p, user_tick, rq); +		irqtime_account_process_tick(p, user_tick, rq, 1);  		return;  	} diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c index 27ef40925525..800e99b99075 100644 --- a/kernel/sched/deadline.c +++ b/kernel/sched/deadline.c @@ -528,6 +528,7 @@ static enum hrtimer_restart dl_task_timer(struct hrtimer *timer)  	sched_clock_tick();  	update_rq_clock(rq);  	dl_se->dl_throttled = 0; +	dl_se->dl_yielded = 0;  	if (p->on_rq) {  		enqueue_task_dl(rq, p, ENQUEUE_REPLENISH);  		if (task_has_dl_policy(rq->curr)) @@ -893,10 +894,10 @@ static void yield_task_dl(struct rq *rq)  	 * We make the task go to sleep until its current deadline by  	 * forcing its runtime to zero. This way, update_curr_dl() stops  	 * it and the bandwidth timer will wake it up and will give it -	 * new scheduling parameters (thanks to dl_new=1). +	 * new scheduling parameters (thanks to dl_yielded=1).  	 */  	if (p->dl.runtime > 0) { -		rq->curr->dl.dl_new = 1; +		rq->curr->dl.dl_yielded = 1;  		p->dl.runtime = 0;  	}  	update_curr_dl(rq); @@ -1021,8 +1022,17 @@ struct task_struct *pick_next_task_dl(struct rq *rq, struct task_struct *prev)  	dl_rq = &rq->dl; -	if (need_pull_dl_task(rq, prev)) +	if (need_pull_dl_task(rq, prev)) {  		pull_dl_task(rq); +		/* +		 * pull_rt_task() can drop (and re-acquire) rq->lock; this +		 * means a stop task can slip in, in which case we need to +		 * re-start task selection. +		 */ +		if (rq->stop && rq->stop->on_rq) +			return RETRY_TASK; +	} +  	/*  	 * When prev is DL, we may throttle it in put_prev_task().  	 * So, we update time before we check for dl_nr_running. diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c index 7e9bd0b1fa9e..0fdb96de81a5 100644 --- a/kernel/sched/fair.c +++ b/kernel/sched/fair.c @@ -1497,7 +1497,7 @@ static void task_numa_placement(struct task_struct *p)  	/* If the task is part of a group prevent parallel updates to group stats */  	if (p->numa_group) {  		group_lock = &p->numa_group->lock; -		spin_lock(group_lock); +		spin_lock_irq(group_lock);  	}  	/* Find the node with the highest number of faults */ @@ -1572,7 +1572,7 @@ static void task_numa_placement(struct task_struct *p)  			}  		} -		spin_unlock(group_lock); +		spin_unlock_irq(group_lock);  	}  	/* Preferred node as the node with the most faults */ @@ -1677,7 +1677,8 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,  	if (!join)  		return; -	double_lock(&my_grp->lock, &grp->lock); +	BUG_ON(irqs_disabled()); +	double_lock_irq(&my_grp->lock, &grp->lock);  	for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++) {  		my_grp->faults[i] -= p->numa_faults_memory[i]; @@ -1691,7 +1692,7 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,  	grp->nr_tasks++;  	spin_unlock(&my_grp->lock); -	spin_unlock(&grp->lock); +	spin_unlock_irq(&grp->lock);  	rcu_assign_pointer(p->numa_group, grp); @@ -1710,14 +1711,14 @@ void task_numa_free(struct task_struct *p)  	void *numa_faults = p->numa_faults_memory;  	if (grp) { -		spin_lock(&grp->lock); +		spin_lock_irq(&grp->lock);  		for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++)  			grp->faults[i] -= p->numa_faults_memory[i];  		grp->total_faults -= p->total_numa_faults;  		list_del(&p->numa_entry);  		grp->nr_tasks--; -		spin_unlock(&grp->lock); +		spin_unlock_irq(&grp->lock);  		rcu_assign_pointer(p->numa_group, NULL);  		put_numa_group(grp);  	} @@ -6652,6 +6653,7 @@ static int idle_balance(struct rq *this_rq)  	int this_cpu = this_rq->cpu;  	idle_enter_fair(this_rq); +  	/*  	 * We must set idle_stamp _before_ calling idle_balance(), such that we  	 * measure the duration of idle_balance() as idle time. @@ -6704,14 +6706,16 @@ static int idle_balance(struct rq *this_rq)  	raw_spin_lock(&this_rq->lock); +	if (curr_cost > this_rq->max_idle_balance_cost) +		this_rq->max_idle_balance_cost = curr_cost; +  	/* -	 * While browsing the domains, we released the rq lock. -	 * A task could have be enqueued in the meantime +	 * While browsing the domains, we released the rq lock, a task could +	 * have been enqueued in the meantime. Since we're not going idle, +	 * pretend we pulled a task.  	 */ -	if (this_rq->cfs.h_nr_running && !pulled_task) { +	if (this_rq->cfs.h_nr_running && !pulled_task)  		pulled_task = 1; -		goto out; -	}  	if (pulled_task || time_after(jiffies, this_rq->next_balance)) {  		/* @@ -6721,13 +6725,11 @@ static int idle_balance(struct rq *this_rq)  		this_rq->next_balance = next_balance;  	} -	if (curr_cost > this_rq->max_idle_balance_cost) -		this_rq->max_idle_balance_cost = curr_cost; -  out:  	/* Is there a task of a high priority class? */  	if (this_rq->nr_running != this_rq->cfs.h_nr_running && -	    (this_rq->dl.dl_nr_running || +	    ((this_rq->stop && this_rq->stop->on_rq) || +	     this_rq->dl.dl_nr_running ||  	     (this_rq->rt.rt_nr_running && !rt_rq_throttled(&this_rq->rt))))  		pulled_task = -1; diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c index d8cdf1618551..bd2267ad404f 100644 --- a/kernel/sched/rt.c +++ b/kernel/sched/rt.c @@ -1362,10 +1362,11 @@ pick_next_task_rt(struct rq *rq, struct task_struct *prev)  		pull_rt_task(rq);  		/*  		 * pull_rt_task() can drop (and re-acquire) rq->lock; this -		 * means a dl task can slip in, in which case we need to -		 * re-start task selection. +		 * means a dl or stop task can slip in, in which case we need +		 * to re-start task selection.  		 */ -		if (unlikely(rq->dl.dl_nr_running)) +		if (unlikely((rq->stop && rq->stop->on_rq) || +			     rq->dl.dl_nr_running))  			return RETRY_TASK;  	} diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index c9007f28d3a2..456e492a3dca 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1385,6 +1385,15 @@ static inline void double_lock(spinlock_t *l1, spinlock_t *l2)  	spin_lock_nested(l2, SINGLE_DEPTH_NESTING);  } +static inline void double_lock_irq(spinlock_t *l1, spinlock_t *l2) +{ +	if (l1 > l2) +		swap(l1, l2); + +	spin_lock_irq(l1); +	spin_lock_nested(l2, SINGLE_DEPTH_NESTING); +} +  static inline void double_raw_lock(raw_spinlock_t *l1, raw_spinlock_t *l2)  {  	if (l1 > l2)  | 

