mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	In the v6.12 scheduler development cycle we had 63 commits from 18 contributors:
- Implement the SCHED_DEADLINE server infrastructure - Daniel Bristot de Oliveira's
    last major contribution to the kernel:
 
      "SCHED_DEADLINE servers can help fixing starvation issues of low priority
      tasks (e.g., SCHED_OTHER) when higher priority tasks monopolize CPU
      cycles. Today we have RT Throttling; DEADLINE servers should be able to
      replace and improve that."
 
      (Daniel Bristot de Oliveira, Peter Zijlstra, Joel Fernandes,
       Youssef Esmat, Huang Shijie)
 
  - Preparatory changes for sched_ext integration:
 
      - Use set_next_task(.first) where required
      - Fix up set_next_task() implementations
      - Clean up DL server vs. core sched
      - Split up put_prev_task_balance()
      - Rework pick_next_task()
      - Combine the last put_prev_task() and the first set_next_task()
      - Rework dl_server
      - Add put_prev_task(.next)
 
       (Peter Zijlstra, with a fix by Tejun Heo)
 
  - Complete the EEVDF transition and refine EEVDF scheduling:
 
      - Implement delayed dequeue
      - Allow shorter slices to wakeup-preempt
      - Use sched_attr::sched_runtime to set request/slice suggestion
      - Document the new feature flags
      - Remove unused and duplicate-functionality fields
      - Simplify & unify pick_next_task_fair()
      - Misc debuggability enhancements
 
       (Peter Zijlstra, with fixes/cleanups by Dietmar Eggemann,
        Valentin Schneider and Chuyi Zhou)
 
  - Initialize the vruntime of a new task when it is first enqueued,
    resulting in significant decrease in latency of newly woken tasks.
    (Zhang Qiao)
 
  - Introduce SM_IDLE and an idle re-entry fast-path in __schedule()
    (K Prateek Nayak, Peter Zijlstra)
 
  - Clean up and clarify the usage of Clean up usage of rt_task()
    (Qais Yousef)
 
  - Preempt SCHED_IDLE entities in strict cgroup hierarchies
    (Tianchen Ding)
 
  - Clarify the documentation of time units for deadline scheduler
    parameters. (Christian Loehle)
 
  - Remove the HZ_BW chicken-bit feature flag introduced a year ago,
    the original change seems to be working fine.
    (Phil Auld)
 
  - Misc fixes and cleanups (Chen Yu, Dan Carpenter, Huang Shijie,
    Peilin He, Qais Yousefm and Vincent Guittot)
 
 Signed-off-by: Ingo Molnar <mingo@kernel.org>
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCgAvFiEEBpT5eoXrXCwVQwEKEnMQ0APhK1gFAmbr8qcRHG1pbmdvQGtl
 cm5lbC5vcmcACgkQEnMQ0APhK1gdbw/+Mj3zWfYP+dtUkfgrR2FClPAJoo1/9Dz0
 LYD8XgYHu8rEJ0Aq+VbdkgYGUt9utvzUFPIxvWFDcldQl57KwhF4hp9Ir+PqJyYC
 NolQ1q8ddo1hnslxnEg6SgHVzQq/4FqMM0nDNUkQETCx6zTyFFeRf+q7o/2c2m5B
 uI9dSU1Wrx7XrXm2D3kB8+xP+ZRy+qhbFN5Pfuz96mhelfklylgKMfPzgAiCT/7T
 JTbQhQ2HdcCNgiLoSrWsHBDy2UYpouP4zb4jyd+lDQzhSUJrj3u4Xy4vVmuTKq+y
 sTgWlgKB+MTuh9UuJ4UYzSnMqg161UlMvtXeH84ABmAqDNGHRPtOKrrlcLtJ3D4x
 m1SPhNnsvpjOu2pH0XLIS8al3VUesWND5S+rucHRYSq6Nvhivf4MTvRJlicXXurL
 Mt2APnIlhGJuKBNWnmyZovVdtO0ZUUPlaZWfr3rCS4txAVo+HwWhsm3uhtTycQqN
 gazsCiuGh6Jds90ZqA/BvdLWG+DY8J0xLlV3ex4pCXuQ/HFrabVWTyThJsULhrZ2
 5mTdWIsocPctNMO9/RHMy7vJI7G7ljgHEquWVn5kiGGzXhK6VwVwKAMpfgXGw+YA
 yVP6/M7a7g2yEzj69gXkcDa8k/kedMVquJ/G/8YhZM7u7sPqsMjpmaGsqsJRfnpT
 ChngAzap+kA=
 =TEC6
 -----END PGP SIGNATURE-----
Merge tag 'sched-core-2024-09-19' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull scheduler updates from Ingo Molnar:
 - Implement the SCHED_DEADLINE server infrastructure - Daniel Bristot
   de Oliveira's last major contribution to the kernel:
     "SCHED_DEADLINE servers can help fixing starvation issues of low
      priority tasks (e.g., SCHED_OTHER) when higher priority tasks
      monopolize CPU cycles. Today we have RT Throttling; DEADLINE
      servers should be able to replace and improve that."
   (Daniel Bristot de Oliveira, Peter Zijlstra, Joel Fernandes, Youssef
   Esmat, Huang Shijie)
 - Preparatory changes for sched_ext integration:
     - Use set_next_task(.first) where required
     - Fix up set_next_task() implementations
     - Clean up DL server vs. core sched
     - Split up put_prev_task_balance()
     - Rework pick_next_task()
     - Combine the last put_prev_task() and the first set_next_task()
     - Rework dl_server
     - Add put_prev_task(.next)
   (Peter Zijlstra, with a fix by Tejun Heo)
 - Complete the EEVDF transition and refine EEVDF scheduling:
     - Implement delayed dequeue
     - Allow shorter slices to wakeup-preempt
     - Use sched_attr::sched_runtime to set request/slice suggestion
     - Document the new feature flags
     - Remove unused and duplicate-functionality fields
     - Simplify & unify pick_next_task_fair()
     - Misc debuggability enhancements
   (Peter Zijlstra, with fixes/cleanups by Dietmar Eggemann, Valentin
   Schneider and Chuyi Zhou)
 - Initialize the vruntime of a new task when it is first enqueued,
   resulting in significant decrease in latency of newly woken tasks
   (Zhang Qiao)
 - Introduce SM_IDLE and an idle re-entry fast-path in __schedule()
   (K Prateek Nayak, Peter Zijlstra)
 - Clean up and clarify the usage of Clean up usage of rt_task()
   (Qais Yousef)
 - Preempt SCHED_IDLE entities in strict cgroup hierarchies
   (Tianchen Ding)
 - Clarify the documentation of time units for deadline scheduler
   parameters (Christian Loehle)
 - Remove the HZ_BW chicken-bit feature flag introduced a year ago,
   the original change seems to be working fine (Phil Auld)
 - Misc fixes and cleanups (Chen Yu, Dan Carpenter, Huang Shijie,
   Peilin He, Qais Yousefm and Vincent Guittot)
* tag 'sched-core-2024-09-19' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (64 commits)
  sched/cpufreq: Use NSEC_PER_MSEC for deadline task
  cpufreq/cppc: Use NSEC_PER_MSEC for deadline task
  sched/deadline: Clarify nanoseconds in uapi
  sched/deadline: Convert schedtool example to chrt
  sched/debug: Fix the runnable tasks output
  sched: Fix sched_delayed vs sched_core
  kernel/sched: Fix util_est accounting for DELAY_DEQUEUE
  kthread: Fix task state in kthread worker if being frozen
  sched/pelt: Use rq_clock_task() for hw_pressure
  sched/fair: Move effective_cpu_util() and effective_cpu_util() in fair.c
  sched/core: Introduce SM_IDLE and an idle re-entry fast-path in __schedule()
  sched: Add put_prev_task(.next)
  sched: Rework dl_server
  sched: Combine the last put_prev_task() and the first set_next_task()
  sched: Rework pick_next_task()
  sched: Split up put_prev_task_balance()
  sched: Clean up DL server vs core sched
  sched: Fixup set_next_task() implementations
  sched: Use set_next_task(.first) where required
  sched/fair: Properly deactivate sched_delayed task upon class change
  ...
			
			
This commit is contained in:
		
						commit
						2004cef11e
					
				
					 32 changed files with 1695 additions and 747 deletions
				
			
		| 
						 | 
					@ -749,21 +749,19 @@ Appendix A. Test suite
 | 
				
			||||||
 of the command line options. Please refer to rt-app documentation for more
 | 
					 of the command line options. Please refer to rt-app documentation for more
 | 
				
			||||||
 details (`<rt-app-sources>/doc/*.json`).
 | 
					 details (`<rt-app-sources>/doc/*.json`).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 The second testing application is a modification of schedtool, called
 | 
					 The second testing application is done using chrt which has support
 | 
				
			||||||
 schedtool-dl, which can be used to setup SCHED_DEADLINE parameters for a
 | 
					 for SCHED_DEADLINE.
 | 
				
			||||||
 certain pid/application. schedtool-dl is available at:
 | 
					 | 
				
			||||||
 https://github.com/scheduler-tools/schedtool-dl.git.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 The usage is straightforward::
 | 
					 The usage is straightforward::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # schedtool -E -t 10000000:100000000 -e ./my_cpuhog_app
 | 
					  # chrt -d -T 10000000 -D 100000000 0 ./my_cpuhog_app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 With this, my_cpuhog_app is put to run inside a SCHED_DEADLINE reservation
 | 
					 With this, my_cpuhog_app is put to run inside a SCHED_DEADLINE reservation
 | 
				
			||||||
 of 10ms every 100ms (note that parameters are expressed in microseconds).
 | 
					 of 10ms every 100ms (note that parameters are expressed in nanoseconds).
 | 
				
			||||||
 You can also use schedtool to create a reservation for an already running
 | 
					 You can also use chrt to create a reservation for an already running
 | 
				
			||||||
 application, given that you know its pid::
 | 
					 application, given that you know its pid::
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # schedtool -E -t 10000000:100000000 my_app_pid
 | 
					  # chrt -d -T 10000000 -D 100000000 -p 0 my_app_pid
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Appendix B. Minimal main()
 | 
					Appendix B. Minimal main()
 | 
				
			||||||
==========================
 | 
					==========================
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -224,9 +224,9 @@ static void __init cppc_freq_invariance_init(void)
 | 
				
			||||||
		 * Fake (unused) bandwidth; workaround to "fix"
 | 
							 * Fake (unused) bandwidth; workaround to "fix"
 | 
				
			||||||
		 * priority inheritance.
 | 
							 * priority inheritance.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		.sched_runtime	= 1000000,
 | 
							.sched_runtime	= NSEC_PER_MSEC,
 | 
				
			||||||
		.sched_deadline = 10000000,
 | 
							.sched_deadline = 10 * NSEC_PER_MSEC,
 | 
				
			||||||
		.sched_period	= 10000000,
 | 
							.sched_period	= 10 * NSEC_PER_MSEC,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -335,7 +335,7 @@ static inline bool six_owner_running(struct six_lock *lock)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
	struct task_struct *owner = READ_ONCE(lock->owner);
 | 
						struct task_struct *owner = READ_ONCE(lock->owner);
 | 
				
			||||||
	bool ret = owner ? owner_on_cpu(owner) : !rt_task(current);
 | 
						bool ret = owner ? owner_on_cpu(owner) : !rt_or_dl_task(current);
 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2626,7 +2626,7 @@ static ssize_t timerslack_ns_write(struct file *file, const char __user *buf,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	task_lock(p);
 | 
						task_lock(p);
 | 
				
			||||||
	if (task_is_realtime(p))
 | 
						if (rt_or_dl_task_policy(p))
 | 
				
			||||||
		slack_ns = 0;
 | 
							slack_ns = 0;
 | 
				
			||||||
	else if (slack_ns == 0)
 | 
						else if (slack_ns == 0)
 | 
				
			||||||
		slack_ns = p->default_timer_slack_ns;
 | 
							slack_ns = p->default_timer_slack_ns;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,7 +40,7 @@ static inline int task_nice_ioclass(struct task_struct *task)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (task->policy == SCHED_IDLE)
 | 
						if (task->policy == SCHED_IDLE)
 | 
				
			||||||
		return IOPRIO_CLASS_IDLE;
 | 
							return IOPRIO_CLASS_IDLE;
 | 
				
			||||||
	else if (task_is_realtime(task))
 | 
						else if (rt_or_dl_task_policy(task))
 | 
				
			||||||
		return IOPRIO_CLASS_RT;
 | 
							return IOPRIO_CLASS_RT;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		return IOPRIO_CLASS_BE;
 | 
							return IOPRIO_CLASS_BE;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,7 +150,8 @@ struct user_event_mm;
 | 
				
			||||||
 * the comment with set_special_state().
 | 
					 * the comment with set_special_state().
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define is_special_task_state(state)					\
 | 
					#define is_special_task_state(state)					\
 | 
				
			||||||
	((state) & (__TASK_STOPPED | __TASK_TRACED | TASK_PARKED | TASK_DEAD))
 | 
						((state) & (__TASK_STOPPED | __TASK_TRACED | TASK_PARKED |	\
 | 
				
			||||||
 | 
							    TASK_DEAD | TASK_FROZEN))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
 | 
					#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
 | 
				
			||||||
# define debug_normal_state_change(state_value)				\
 | 
					# define debug_normal_state_change(state_value)				\
 | 
				
			||||||
| 
						 | 
					@ -541,9 +542,14 @@ struct sched_entity {
 | 
				
			||||||
	struct rb_node			run_node;
 | 
						struct rb_node			run_node;
 | 
				
			||||||
	u64				deadline;
 | 
						u64				deadline;
 | 
				
			||||||
	u64				min_vruntime;
 | 
						u64				min_vruntime;
 | 
				
			||||||
 | 
						u64				min_slice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct list_head		group_node;
 | 
						struct list_head		group_node;
 | 
				
			||||||
	unsigned int			on_rq;
 | 
						unsigned char			on_rq;
 | 
				
			||||||
 | 
						unsigned char			sched_delayed;
 | 
				
			||||||
 | 
						unsigned char			rel_deadline;
 | 
				
			||||||
 | 
						unsigned char			custom_slice;
 | 
				
			||||||
 | 
										/* hole */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u64				exec_start;
 | 
						u64				exec_start;
 | 
				
			||||||
	u64				sum_exec_runtime;
 | 
						u64				sum_exec_runtime;
 | 
				
			||||||
| 
						 | 
					@ -639,12 +645,26 @@ struct sched_dl_entity {
 | 
				
			||||||
	 *
 | 
						 *
 | 
				
			||||||
	 * @dl_overrun tells if the task asked to be informed about runtime
 | 
						 * @dl_overrun tells if the task asked to be informed about runtime
 | 
				
			||||||
	 * overruns.
 | 
						 * overruns.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @dl_server tells if this is a server entity.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @dl_defer tells if this is a deferred or regular server. For
 | 
				
			||||||
 | 
						 * now only defer server exists.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @dl_defer_armed tells if the deferrable server is waiting
 | 
				
			||||||
 | 
						 * for the replenishment timer to activate it.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * @dl_defer_running tells if the deferrable server is actually
 | 
				
			||||||
 | 
						 * running, skipping the defer phase.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	unsigned int			dl_throttled      : 1;
 | 
						unsigned int			dl_throttled      : 1;
 | 
				
			||||||
	unsigned int			dl_yielded        : 1;
 | 
						unsigned int			dl_yielded        : 1;
 | 
				
			||||||
	unsigned int			dl_non_contending : 1;
 | 
						unsigned int			dl_non_contending : 1;
 | 
				
			||||||
	unsigned int			dl_overrun	  : 1;
 | 
						unsigned int			dl_overrun	  : 1;
 | 
				
			||||||
	unsigned int			dl_server         : 1;
 | 
						unsigned int			dl_server         : 1;
 | 
				
			||||||
 | 
						unsigned int			dl_defer	  : 1;
 | 
				
			||||||
 | 
						unsigned int			dl_defer_armed	  : 1;
 | 
				
			||||||
 | 
						unsigned int			dl_defer_running  : 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Bandwidth enforcement timer. Each -deadline task has its
 | 
						 * Bandwidth enforcement timer. Each -deadline task has its
 | 
				
			||||||
| 
						 | 
					@ -672,7 +692,7 @@ struct sched_dl_entity {
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	struct rq			*rq;
 | 
						struct rq			*rq;
 | 
				
			||||||
	dl_server_has_tasks_f		server_has_tasks;
 | 
						dl_server_has_tasks_f		server_has_tasks;
 | 
				
			||||||
	dl_server_pick_f		server_pick;
 | 
						dl_server_pick_f		server_pick_task;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_RT_MUTEXES
 | 
					#ifdef CONFIG_RT_MUTEXES
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,16 +10,16 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/sched.h>
 | 
					#include <linux/sched.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_DL_PRIO		0
 | 
					static inline bool dl_prio(int prio)
 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline int dl_prio(int prio)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (unlikely(prio < MAX_DL_PRIO))
 | 
						return unlikely(prio < MAX_DL_PRIO);
 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int dl_task(struct task_struct *p)
 | 
					/*
 | 
				
			||||||
 | 
					 * Returns true if a task has a priority that belongs to DL class. PI-boosted
 | 
				
			||||||
 | 
					 * tasks will return true. Use dl_policy() to ignore PI-boosted tasks.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline bool dl_task(struct task_struct *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return dl_prio(p->prio);
 | 
						return dl_prio(p->prio);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,6 +14,7 @@
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_RT_PRIO		100
 | 
					#define MAX_RT_PRIO		100
 | 
				
			||||||
 | 
					#define MAX_DL_PRIO		0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MAX_PRIO		(MAX_RT_PRIO + NICE_WIDTH)
 | 
					#define MAX_PRIO		(MAX_RT_PRIO + NICE_WIDTH)
 | 
				
			||||||
#define DEFAULT_PRIO		(MAX_RT_PRIO + NICE_WIDTH / 2)
 | 
					#define DEFAULT_PRIO		(MAX_RT_PRIO + NICE_WIDTH / 2)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,19 +6,40 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct task_struct;
 | 
					struct task_struct;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int rt_prio(int prio)
 | 
					static inline bool rt_prio(int prio)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (unlikely(prio < MAX_RT_PRIO))
 | 
						return unlikely(prio < MAX_RT_PRIO && prio >= MAX_DL_PRIO);
 | 
				
			||||||
		return 1;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int rt_task(struct task_struct *p)
 | 
					static inline bool rt_or_dl_prio(int prio)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return unlikely(prio < MAX_RT_PRIO);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Returns true if a task has a priority that belongs to RT class. PI-boosted
 | 
				
			||||||
 | 
					 * tasks will return true. Use rt_policy() to ignore PI-boosted tasks.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline bool rt_task(struct task_struct *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return rt_prio(p->prio);
 | 
						return rt_prio(p->prio);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline bool task_is_realtime(struct task_struct *tsk)
 | 
					/*
 | 
				
			||||||
 | 
					 * Returns true if a task has a priority that belongs to RT or DL classes.
 | 
				
			||||||
 | 
					 * PI-boosted tasks will return true. Use rt_or_dl_task_policy() to ignore
 | 
				
			||||||
 | 
					 * PI-boosted tasks.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline bool rt_or_dl_task(struct task_struct *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return rt_or_dl_prio(p->prio);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Returns true if a task has a policy that belongs to RT or DL classes.
 | 
				
			||||||
 | 
					 * PI-boosted tasks will return false.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static inline bool rt_or_dl_task_policy(struct task_struct *tsk)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int policy = tsk->policy;
 | 
						int policy = tsk->policy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -58,9 +58,9 @@
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * This is reflected by the following fields of the sched_attr structure:
 | 
					 * This is reflected by the following fields of the sched_attr structure:
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 *  @sched_deadline	representative of the task's deadline
 | 
					 *  @sched_deadline	representative of the task's deadline in nanoseconds
 | 
				
			||||||
 *  @sched_runtime	representative of the task's runtime
 | 
					 *  @sched_runtime	representative of the task's runtime in nanoseconds
 | 
				
			||||||
 *  @sched_period	representative of the task's period
 | 
					 *  @sched_period	representative of the task's period in nanoseconds
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Given this task model, there are a multiplicity of scheduling algorithms
 | 
					 * Given this task model, there are a multiplicity of scheduling algorithms
 | 
				
			||||||
 * and policies, that can be used to ensure all the tasks will make their
 | 
					 * and policies, that can be used to ensure all the tasks will make their
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,7 +72,7 @@ bool __refrigerator(bool check_kthr_stop)
 | 
				
			||||||
		bool freeze;
 | 
							bool freeze;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		raw_spin_lock_irq(¤t->pi_lock);
 | 
							raw_spin_lock_irq(¤t->pi_lock);
 | 
				
			||||||
		set_current_state(TASK_FROZEN);
 | 
							WRITE_ONCE(current->__state, TASK_FROZEN);
 | 
				
			||||||
		/* unstale saved_state so that __thaw_task() will wake us up */
 | 
							/* unstale saved_state so that __thaw_task() will wake us up */
 | 
				
			||||||
		current->saved_state = TASK_RUNNING;
 | 
							current->saved_state = TASK_RUNNING;
 | 
				
			||||||
		raw_spin_unlock_irq(¤t->pi_lock);
 | 
							raw_spin_unlock_irq(¤t->pi_lock);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -845,8 +845,16 @@ int kthread_worker_fn(void *worker_ptr)
 | 
				
			||||||
		 * event only cares about the address.
 | 
							 * event only cares about the address.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		trace_sched_kthread_work_execute_end(work, func);
 | 
							trace_sched_kthread_work_execute_end(work, func);
 | 
				
			||||||
	} else if (!freezing(current))
 | 
						} else if (!freezing(current)) {
 | 
				
			||||||
		schedule();
 | 
							schedule();
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Handle the case where the current remains
 | 
				
			||||||
 | 
							 * TASK_INTERRUPTIBLE. try_to_freeze() expects
 | 
				
			||||||
 | 
							 * the current to be TASK_RUNNING.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							__set_current_state(TASK_RUNNING);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	try_to_freeze();
 | 
						try_to_freeze();
 | 
				
			||||||
	cond_resched();
 | 
						cond_resched();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -347,7 +347,7 @@ static __always_inline int __waiter_prio(struct task_struct *task)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int prio = task->prio;
 | 
						int prio = task->prio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rt_prio(prio))
 | 
						if (!rt_or_dl_prio(prio))
 | 
				
			||||||
		return DEFAULT_PRIO;
 | 
							return DEFAULT_PRIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return prio;
 | 
						return prio;
 | 
				
			||||||
| 
						 | 
					@ -435,7 +435,7 @@ static inline bool rt_mutex_steal(struct rt_mutex_waiter *waiter,
 | 
				
			||||||
	 * Note that RT tasks are excluded from same priority (lateral)
 | 
						 * Note that RT tasks are excluded from same priority (lateral)
 | 
				
			||||||
	 * steals to prevent the introduction of an unbounded latency.
 | 
						 * steals to prevent the introduction of an unbounded latency.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (rt_prio(waiter->tree.prio) || dl_prio(waiter->tree.prio))
 | 
						if (rt_or_dl_prio(waiter->tree.prio))
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return rt_waiter_node_equal(&waiter->tree, &top_waiter->tree);
 | 
						return rt_waiter_node_equal(&waiter->tree, &top_waiter->tree);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -631,7 +631,7 @@ static inline bool rwsem_try_write_lock(struct rw_semaphore *sem,
 | 
				
			||||||
			 * if it is an RT task or wait in the wait queue
 | 
								 * if it is an RT task or wait in the wait queue
 | 
				
			||||||
			 * for too long.
 | 
								 * for too long.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			if (has_handoff || (!rt_task(waiter->task) &&
 | 
								if (has_handoff || (!rt_or_dl_task(waiter->task) &&
 | 
				
			||||||
					    !time_after(jiffies, waiter->timeout)))
 | 
										    !time_after(jiffies, waiter->timeout)))
 | 
				
			||||||
				return false;
 | 
									return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -914,7 +914,7 @@ static bool rwsem_optimistic_spin(struct rw_semaphore *sem)
 | 
				
			||||||
		if (owner_state != OWNER_WRITER) {
 | 
							if (owner_state != OWNER_WRITER) {
 | 
				
			||||||
			if (need_resched())
 | 
								if (need_resched())
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			if (rt_task(current) &&
 | 
								if (rt_or_dl_task(current) &&
 | 
				
			||||||
			   (prev_owner_state != OWNER_WRITER))
 | 
								   (prev_owner_state != OWNER_WRITER))
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -237,7 +237,7 @@ __ww_ctx_less(struct ww_acquire_ctx *a, struct ww_acquire_ctx *b)
 | 
				
			||||||
	int a_prio = a->task->prio;
 | 
						int a_prio = a->task->prio;
 | 
				
			||||||
	int b_prio = b->task->prio;
 | 
						int b_prio = b->task->prio;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rt_prio(a_prio) || rt_prio(b_prio)) {
 | 
						if (rt_or_dl_prio(a_prio) || rt_or_dl_prio(b_prio)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (a_prio > b_prio)
 | 
							if (a_prio > b_prio)
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -163,7 +163,10 @@ static inline int __task_prio(const struct task_struct *p)
 | 
				
			||||||
	if (p->sched_class == &stop_sched_class) /* trumps deadline */
 | 
						if (p->sched_class == &stop_sched_class) /* trumps deadline */
 | 
				
			||||||
		return -2;
 | 
							return -2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rt_prio(p->prio)) /* includes deadline */
 | 
						if (p->dl_server)
 | 
				
			||||||
 | 
							return -1; /* deadline */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rt_or_dl_prio(p->prio))
 | 
				
			||||||
		return p->prio; /* [-1, 99] */
 | 
							return p->prio; /* [-1, 99] */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (p->sched_class == &idle_sched_class)
 | 
						if (p->sched_class == &idle_sched_class)
 | 
				
			||||||
| 
						 | 
					@ -192,8 +195,24 @@ static inline bool prio_less(const struct task_struct *a,
 | 
				
			||||||
	if (-pb < -pa)
 | 
						if (-pb < -pa)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pa == -1) /* dl_prio() doesn't work because of stop_class above */
 | 
						if (pa == -1) { /* dl_prio() doesn't work because of stop_class above */
 | 
				
			||||||
		return !dl_time_before(a->dl.deadline, b->dl.deadline);
 | 
							const struct sched_dl_entity *a_dl, *b_dl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							a_dl = &a->dl;
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Since,'a' and 'b' can be CFS tasks served by DL server,
 | 
				
			||||||
 | 
							 * __task_prio() can return -1 (for DL) even for those. In that
 | 
				
			||||||
 | 
							 * case, get to the dl_server's DL entity.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (a->dl_server)
 | 
				
			||||||
 | 
								a_dl = a->dl_server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							b_dl = &b->dl;
 | 
				
			||||||
 | 
							if (b->dl_server)
 | 
				
			||||||
 | 
								b_dl = b->dl_server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return !dl_time_before(a_dl->deadline, b_dl->deadline);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pa == MAX_RT_PRIO + MAX_NICE)	/* fair */
 | 
						if (pa == MAX_RT_PRIO + MAX_NICE)	/* fair */
 | 
				
			||||||
		return cfs_prio_less(a, b, in_fi);
 | 
							return cfs_prio_less(a, b, in_fi);
 | 
				
			||||||
| 
						 | 
					@ -240,6 +259,9 @@ static inline int rb_sched_core_cmp(const void *key, const struct rb_node *node)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sched_core_enqueue(struct rq *rq, struct task_struct *p)
 | 
					void sched_core_enqueue(struct rq *rq, struct task_struct *p)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if (p->se.sched_delayed)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rq->core->core_task_seq++;
 | 
						rq->core->core_task_seq++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!p->core_cookie)
 | 
						if (!p->core_cookie)
 | 
				
			||||||
| 
						 | 
					@ -250,6 +272,9 @@ void sched_core_enqueue(struct rq *rq, struct task_struct *p)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void sched_core_dequeue(struct rq *rq, struct task_struct *p, int flags)
 | 
					void sched_core_dequeue(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if (p->se.sched_delayed)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rq->core->core_task_seq++;
 | 
						rq->core->core_task_seq++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sched_core_enqueued(p)) {
 | 
						if (sched_core_enqueued(p)) {
 | 
				
			||||||
| 
						 | 
					@ -1269,7 +1294,7 @@ bool sched_can_stop_tick(struct rq *rq)
 | 
				
			||||||
	 * dequeued by migrating while the constrained task continues to run.
 | 
						 * dequeued by migrating while the constrained task continues to run.
 | 
				
			||||||
	 * E.g. going from 2->1 without going through pick_next_task().
 | 
						 * E.g. going from 2->1 without going through pick_next_task().
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (sched_feat(HZ_BW) && __need_bw_check(rq, rq->curr)) {
 | 
						if (__need_bw_check(rq, rq->curr)) {
 | 
				
			||||||
		if (cfs_task_bw_constrained(rq->curr))
 | 
							if (cfs_task_bw_constrained(rq->curr))
 | 
				
			||||||
			return false;
 | 
								return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -1672,6 +1697,9 @@ static inline void uclamp_rq_inc(struct rq *rq, struct task_struct *p)
 | 
				
			||||||
	if (unlikely(!p->sched_class->uclamp_enabled))
 | 
						if (unlikely(!p->sched_class->uclamp_enabled))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p->se.sched_delayed)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_clamp_id(clamp_id)
 | 
						for_each_clamp_id(clamp_id)
 | 
				
			||||||
		uclamp_rq_inc_id(rq, p, clamp_id);
 | 
							uclamp_rq_inc_id(rq, p, clamp_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1696,6 +1724,9 @@ static inline void uclamp_rq_dec(struct rq *rq, struct task_struct *p)
 | 
				
			||||||
	if (unlikely(!p->sched_class->uclamp_enabled))
 | 
						if (unlikely(!p->sched_class->uclamp_enabled))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p->se.sched_delayed)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_clamp_id(clamp_id)
 | 
						for_each_clamp_id(clamp_id)
 | 
				
			||||||
		uclamp_rq_dec_id(rq, p, clamp_id);
 | 
							uclamp_rq_dec_id(rq, p, clamp_id);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1975,14 +2006,21 @@ void enqueue_task(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
		psi_enqueue(p, (flags & ENQUEUE_WAKEUP) && !(flags & ENQUEUE_MIGRATED));
 | 
							psi_enqueue(p, (flags & ENQUEUE_WAKEUP) && !(flags & ENQUEUE_MIGRATED));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uclamp_rq_inc(rq, p);
 | 
					 | 
				
			||||||
	p->sched_class->enqueue_task(rq, p, flags);
 | 
						p->sched_class->enqueue_task(rq, p, flags);
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Must be after ->enqueue_task() because ENQUEUE_DELAYED can clear
 | 
				
			||||||
 | 
						 * ->sched_delayed.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						uclamp_rq_inc(rq, p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sched_core_enabled(rq))
 | 
						if (sched_core_enabled(rq))
 | 
				
			||||||
		sched_core_enqueue(rq, p);
 | 
							sched_core_enqueue(rq, p);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void dequeue_task(struct rq *rq, struct task_struct *p, int flags)
 | 
					/*
 | 
				
			||||||
 | 
					 * Must only return false when DEQUEUE_SLEEP.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					inline bool dequeue_task(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (sched_core_enabled(rq))
 | 
						if (sched_core_enabled(rq))
 | 
				
			||||||
		sched_core_dequeue(rq, p, flags);
 | 
							sched_core_dequeue(rq, p, flags);
 | 
				
			||||||
| 
						 | 
					@ -1995,8 +2033,12 @@ void dequeue_task(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
		psi_dequeue(p, flags & DEQUEUE_SLEEP);
 | 
							psi_dequeue(p, flags & DEQUEUE_SLEEP);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Must be before ->dequeue_task() because ->dequeue_task() can 'fail'
 | 
				
			||||||
 | 
						 * and mark the task ->sched_delayed.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	uclamp_rq_dec(rq, p);
 | 
						uclamp_rq_dec(rq, p);
 | 
				
			||||||
	p->sched_class->dequeue_task(rq, p, flags);
 | 
						return p->sched_class->dequeue_task(rq, p, flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void activate_task(struct rq *rq, struct task_struct *p, int flags)
 | 
					void activate_task(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
| 
						 | 
					@ -2014,12 +2056,25 @@ void activate_task(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void deactivate_task(struct rq *rq, struct task_struct *p, int flags)
 | 
					void deactivate_task(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	WRITE_ONCE(p->on_rq, (flags & DEQUEUE_SLEEP) ? 0 : TASK_ON_RQ_MIGRATING);
 | 
						SCHED_WARN_ON(flags & DEQUEUE_SLEEP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						WRITE_ONCE(p->on_rq, TASK_ON_RQ_MIGRATING);
 | 
				
			||||||
	ASSERT_EXCLUSIVE_WRITER(p->on_rq);
 | 
						ASSERT_EXCLUSIVE_WRITER(p->on_rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Code explicitly relies on TASK_ON_RQ_MIGRATING begin set *before*
 | 
				
			||||||
 | 
						 * dequeue_task() and cleared *after* enqueue_task().
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dequeue_task(rq, p, flags);
 | 
						dequeue_task(rq, p, flags);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void block_task(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (dequeue_task(rq, p, DEQUEUE_SLEEP | flags))
 | 
				
			||||||
 | 
							__block_task(rq, p);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * task_curr - is this task currently executing on a CPU?
 | 
					 * task_curr - is this task currently executing on a CPU?
 | 
				
			||||||
 * @p: the task in question.
 | 
					 * @p: the task in question.
 | 
				
			||||||
| 
						 | 
					@ -2233,6 +2288,12 @@ void migrate_disable(void)
 | 
				
			||||||
	struct task_struct *p = current;
 | 
						struct task_struct *p = current;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (p->migration_disabled) {
 | 
						if (p->migration_disabled) {
 | 
				
			||||||
 | 
					#ifdef CONFIG_DEBUG_PREEMPT
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 *Warn about overflow half-way through the range.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							WARN_ON_ONCE((s16)p->migration_disabled < 0);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		p->migration_disabled++;
 | 
							p->migration_disabled++;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -2251,14 +2312,20 @@ void migrate_enable(void)
 | 
				
			||||||
		.flags     = SCA_MIGRATE_ENABLE,
 | 
							.flags     = SCA_MIGRATE_ENABLE,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_DEBUG_PREEMPT
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Check both overflow from migrate_disable() and superfluous
 | 
				
			||||||
 | 
						 * migrate_enable().
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (WARN_ON_ONCE((s16)p->migration_disabled <= 0))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (p->migration_disabled > 1) {
 | 
						if (p->migration_disabled > 1) {
 | 
				
			||||||
		p->migration_disabled--;
 | 
							p->migration_disabled--;
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (WARN_ON_ONCE(!p->migration_disabled))
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Ensure stop_task runs either before or after this, and that
 | 
						 * Ensure stop_task runs either before or after this, and that
 | 
				
			||||||
	 * __set_cpus_allowed_ptr(SCA_MIGRATE_ENABLE) doesn't schedule().
 | 
						 * __set_cpus_allowed_ptr(SCA_MIGRATE_ENABLE) doesn't schedule().
 | 
				
			||||||
| 
						 | 
					@ -3607,8 +3674,6 @@ ttwu_do_activate(struct rq *rq, struct task_struct *p, int wake_flags,
 | 
				
			||||||
		rq->idle_stamp = 0;
 | 
							rq->idle_stamp = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
	p->dl_server = NULL;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -3644,12 +3709,14 @@ static int ttwu_runnable(struct task_struct *p, int wake_flags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rq = __task_rq_lock(p, &rf);
 | 
						rq = __task_rq_lock(p, &rf);
 | 
				
			||||||
	if (task_on_rq_queued(p)) {
 | 
						if (task_on_rq_queued(p)) {
 | 
				
			||||||
 | 
							update_rq_clock(rq);
 | 
				
			||||||
 | 
							if (p->se.sched_delayed)
 | 
				
			||||||
 | 
								enqueue_task(rq, p, ENQUEUE_NOCLOCK | ENQUEUE_DELAYED);
 | 
				
			||||||
		if (!task_on_cpu(rq, p)) {
 | 
							if (!task_on_cpu(rq, p)) {
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * When on_rq && !on_cpu the task is preempted, see if
 | 
								 * When on_rq && !on_cpu the task is preempted, see if
 | 
				
			||||||
			 * it should preempt the task that is current now.
 | 
								 * it should preempt the task that is current now.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			update_rq_clock(rq);
 | 
					 | 
				
			||||||
			wakeup_preempt(rq, p, wake_flags);
 | 
								wakeup_preempt(rq, p, wake_flags);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		ttwu_do_wakeup(p);
 | 
							ttwu_do_wakeup(p);
 | 
				
			||||||
| 
						 | 
					@ -4029,11 +4096,16 @@ int try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags)
 | 
				
			||||||
		 * case the whole 'p->on_rq && ttwu_runnable()' case below
 | 
							 * case the whole 'p->on_rq && ttwu_runnable()' case below
 | 
				
			||||||
		 * without taking any locks.
 | 
							 * without taking any locks.
 | 
				
			||||||
		 *
 | 
							 *
 | 
				
			||||||
 | 
							 * Specifically, given current runs ttwu() we must be before
 | 
				
			||||||
 | 
							 * schedule()'s block_task(), as such this must not observe
 | 
				
			||||||
 | 
							 * sched_delayed.
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
		 * In particular:
 | 
							 * In particular:
 | 
				
			||||||
		 *  - we rely on Program-Order guarantees for all the ordering,
 | 
							 *  - we rely on Program-Order guarantees for all the ordering,
 | 
				
			||||||
		 *  - we're serialized against set_special_state() by virtue of
 | 
							 *  - we're serialized against set_special_state() by virtue of
 | 
				
			||||||
		 *    it disabling IRQs (this allows not taking ->pi_lock).
 | 
							 *    it disabling IRQs (this allows not taking ->pi_lock).
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
 | 
							SCHED_WARN_ON(p->se.sched_delayed);
 | 
				
			||||||
		if (!ttwu_state_match(p, state, &success))
 | 
							if (!ttwu_state_match(p, state, &success))
 | 
				
			||||||
			goto out;
 | 
								goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4322,9 +4394,11 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p)
 | 
				
			||||||
	p->se.nr_migrations		= 0;
 | 
						p->se.nr_migrations		= 0;
 | 
				
			||||||
	p->se.vruntime			= 0;
 | 
						p->se.vruntime			= 0;
 | 
				
			||||||
	p->se.vlag			= 0;
 | 
						p->se.vlag			= 0;
 | 
				
			||||||
	p->se.slice			= sysctl_sched_base_slice;
 | 
					 | 
				
			||||||
	INIT_LIST_HEAD(&p->se.group_node);
 | 
						INIT_LIST_HEAD(&p->se.group_node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* A delayed task cannot be in clone(). */
 | 
				
			||||||
 | 
						SCHED_WARN_ON(p->se.sched_delayed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_FAIR_GROUP_SCHED
 | 
					#ifdef CONFIG_FAIR_GROUP_SCHED
 | 
				
			||||||
	p->se.cfs_rq			= NULL;
 | 
						p->se.cfs_rq			= NULL;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -4572,6 +4646,8 @@ int sched_fork(unsigned long clone_flags, struct task_struct *p)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		p->prio = p->normal_prio = p->static_prio;
 | 
							p->prio = p->normal_prio = p->static_prio;
 | 
				
			||||||
		set_load_weight(p, false);
 | 
							set_load_weight(p, false);
 | 
				
			||||||
 | 
							p->se.custom_slice = 0;
 | 
				
			||||||
 | 
							p->se.slice = sysctl_sched_base_slice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * We don't need the reset flag anymore after the fork. It has
 | 
							 * We don't need the reset flag anymore after the fork. It has
 | 
				
			||||||
| 
						 | 
					@ -4686,7 +4762,7 @@ void wake_up_new_task(struct task_struct *p)
 | 
				
			||||||
	update_rq_clock(rq);
 | 
						update_rq_clock(rq);
 | 
				
			||||||
	post_init_entity_util_avg(p);
 | 
						post_init_entity_util_avg(p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	activate_task(rq, p, ENQUEUE_NOCLOCK);
 | 
						activate_task(rq, p, ENQUEUE_NOCLOCK | ENQUEUE_INITIAL);
 | 
				
			||||||
	trace_sched_wakeup_new(p);
 | 
						trace_sched_wakeup_new(p);
 | 
				
			||||||
	wakeup_preempt(rq, p, WF_FORK);
 | 
						wakeup_preempt(rq, p, WF_FORK);
 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
| 
						 | 
					@ -5769,7 +5845,7 @@ static inline void schedule_debug(struct task_struct *prev, bool preempt)
 | 
				
			||||||
	schedstat_inc(this_rq()->sched_count);
 | 
						schedstat_inc(this_rq()->sched_count);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void put_prev_task_balance(struct rq *rq, struct task_struct *prev,
 | 
					static void prev_balance(struct rq *rq, struct task_struct *prev,
 | 
				
			||||||
			 struct rq_flags *rf)
 | 
								 struct rq_flags *rf)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
| 
						 | 
					@ -5787,8 +5863,6 @@ static void put_prev_task_balance(struct rq *rq, struct task_struct *prev,
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					 | 
				
			||||||
	put_prev_task(rq, prev);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -5800,6 +5874,8 @@ __pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 | 
				
			||||||
	const struct sched_class *class;
 | 
						const struct sched_class *class;
 | 
				
			||||||
	struct task_struct *p;
 | 
						struct task_struct *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rq->dl_server = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Optimization: we know that if all tasks are in the fair class we can
 | 
						 * Optimization: we know that if all tasks are in the fair class we can
 | 
				
			||||||
	 * call that function directly, but only if the @prev task wasn't of a
 | 
						 * call that function directly, but only if the @prev task wasn't of a
 | 
				
			||||||
| 
						 | 
					@ -5815,35 +5891,28 @@ __pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Assume the next prioritized class is idle_sched_class */
 | 
							/* Assume the next prioritized class is idle_sched_class */
 | 
				
			||||||
		if (!p) {
 | 
							if (!p) {
 | 
				
			||||||
			put_prev_task(rq, prev);
 | 
								p = pick_task_idle(rq);
 | 
				
			||||||
			p = pick_next_task_idle(rq);
 | 
								put_prev_set_next_task(rq, prev, p);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * This is the fast path; it cannot be a DL server pick;
 | 
					 | 
				
			||||||
		 * therefore even if @p == @prev, ->dl_server must be NULL.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if (p->dl_server)
 | 
					 | 
				
			||||||
			p->dl_server = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return p;
 | 
							return p;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
restart:
 | 
					restart:
 | 
				
			||||||
	put_prev_task_balance(rq, prev, rf);
 | 
						prev_balance(rq, prev, rf);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * We've updated @prev and no longer need the server link, clear it.
 | 
					 | 
				
			||||||
	 * Must be done before ->pick_next_task() because that can (re)set
 | 
					 | 
				
			||||||
	 * ->dl_server.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (prev->dl_server)
 | 
					 | 
				
			||||||
		prev->dl_server = NULL;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_class(class) {
 | 
						for_each_class(class) {
 | 
				
			||||||
		p = class->pick_next_task(rq);
 | 
							if (class->pick_next_task) {
 | 
				
			||||||
 | 
								p = class->pick_next_task(rq, prev);
 | 
				
			||||||
			if (p)
 | 
								if (p)
 | 
				
			||||||
				return p;
 | 
									return p;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								p = class->pick_task(rq);
 | 
				
			||||||
 | 
								if (p) {
 | 
				
			||||||
 | 
									put_prev_set_next_task(rq, prev, p);
 | 
				
			||||||
 | 
									return p;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BUG(); /* The idle class should always have a runnable task. */
 | 
						BUG(); /* The idle class should always have a runnable task. */
 | 
				
			||||||
| 
						 | 
					@ -5873,6 +5942,8 @@ static inline struct task_struct *pick_task(struct rq *rq)
 | 
				
			||||||
	const struct sched_class *class;
 | 
						const struct sched_class *class;
 | 
				
			||||||
	struct task_struct *p;
 | 
						struct task_struct *p;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rq->dl_server = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_class(class) {
 | 
						for_each_class(class) {
 | 
				
			||||||
		p = class->pick_task(rq);
 | 
							p = class->pick_task(rq);
 | 
				
			||||||
		if (p)
 | 
							if (p)
 | 
				
			||||||
| 
						 | 
					@ -5911,6 +5982,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 | 
				
			||||||
		 * another cpu during offline.
 | 
							 * another cpu during offline.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		rq->core_pick = NULL;
 | 
							rq->core_pick = NULL;
 | 
				
			||||||
 | 
							rq->core_dl_server = NULL;
 | 
				
			||||||
		return __pick_next_task(rq, prev, rf);
 | 
							return __pick_next_task(rq, prev, rf);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5929,16 +6001,13 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 | 
				
			||||||
		WRITE_ONCE(rq->core_sched_seq, rq->core->core_pick_seq);
 | 
							WRITE_ONCE(rq->core_sched_seq, rq->core->core_pick_seq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		next = rq->core_pick;
 | 
							next = rq->core_pick;
 | 
				
			||||||
		if (next != prev) {
 | 
							rq->dl_server = rq->core_dl_server;
 | 
				
			||||||
			put_prev_task(rq, prev);
 | 
					 | 
				
			||||||
			set_next_task(rq, next);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rq->core_pick = NULL;
 | 
							rq->core_pick = NULL;
 | 
				
			||||||
		goto out;
 | 
							rq->core_dl_server = NULL;
 | 
				
			||||||
 | 
							goto out_set_next;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	put_prev_task_balance(rq, prev, rf);
 | 
						prev_balance(rq, prev, rf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	smt_mask = cpu_smt_mask(cpu);
 | 
						smt_mask = cpu_smt_mask(cpu);
 | 
				
			||||||
	need_sync = !!rq->core->core_cookie;
 | 
						need_sync = !!rq->core->core_cookie;
 | 
				
			||||||
| 
						 | 
					@ -5979,6 +6048,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 | 
				
			||||||
		next = pick_task(rq);
 | 
							next = pick_task(rq);
 | 
				
			||||||
		if (!next->core_cookie) {
 | 
							if (!next->core_cookie) {
 | 
				
			||||||
			rq->core_pick = NULL;
 | 
								rq->core_pick = NULL;
 | 
				
			||||||
 | 
								rq->core_dl_server = NULL;
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * For robustness, update the min_vruntime_fi for
 | 
								 * For robustness, update the min_vruntime_fi for
 | 
				
			||||||
			 * unconstrained picks as well.
 | 
								 * unconstrained picks as well.
 | 
				
			||||||
| 
						 | 
					@ -6006,7 +6076,9 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 | 
				
			||||||
		if (i != cpu && (rq_i != rq->core || !core_clock_updated))
 | 
							if (i != cpu && (rq_i != rq->core || !core_clock_updated))
 | 
				
			||||||
			update_rq_clock(rq_i);
 | 
								update_rq_clock(rq_i);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		p = rq_i->core_pick = pick_task(rq_i);
 | 
							rq_i->core_pick = p = pick_task(rq_i);
 | 
				
			||||||
 | 
							rq_i->core_dl_server = rq_i->dl_server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!max || prio_less(max, p, fi_before))
 | 
							if (!max || prio_less(max, p, fi_before))
 | 
				
			||||||
			max = p;
 | 
								max = p;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -6030,6 +6102,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rq_i->core_pick = p;
 | 
							rq_i->core_pick = p;
 | 
				
			||||||
 | 
							rq_i->core_dl_server = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (p == rq_i->idle) {
 | 
							if (p == rq_i->idle) {
 | 
				
			||||||
			if (rq_i->nr_running) {
 | 
								if (rq_i->nr_running) {
 | 
				
			||||||
| 
						 | 
					@ -6090,6 +6163,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (i == cpu) {
 | 
							if (i == cpu) {
 | 
				
			||||||
			rq_i->core_pick = NULL;
 | 
								rq_i->core_pick = NULL;
 | 
				
			||||||
 | 
								rq_i->core_dl_server = NULL;
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6098,6 +6172,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (rq_i->curr == rq_i->core_pick) {
 | 
							if (rq_i->curr == rq_i->core_pick) {
 | 
				
			||||||
			rq_i->core_pick = NULL;
 | 
								rq_i->core_pick = NULL;
 | 
				
			||||||
 | 
								rq_i->core_dl_server = NULL;
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6105,8 +6180,7 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
out_set_next:
 | 
					out_set_next:
 | 
				
			||||||
	set_next_task(rq, next);
 | 
						put_prev_set_next_task(rq, prev, next);
 | 
				
			||||||
out:
 | 
					 | 
				
			||||||
	if (rq->core->core_forceidle_count && next == rq->idle)
 | 
						if (rq->core->core_forceidle_count && next == rq->idle)
 | 
				
			||||||
		queue_core_balance(rq);
 | 
							queue_core_balance(rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6342,19 +6416,12 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 | 
				
			||||||
 * Constants for the sched_mode argument of __schedule().
 | 
					 * Constants for the sched_mode argument of __schedule().
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * The mode argument allows RT enabled kernels to differentiate a
 | 
					 * The mode argument allows RT enabled kernels to differentiate a
 | 
				
			||||||
 * preemption from blocking on an 'sleeping' spin/rwlock. Note that
 | 
					 * preemption from blocking on an 'sleeping' spin/rwlock.
 | 
				
			||||||
 * SM_MASK_PREEMPT for !RT has all bits set, which allows the compiler to
 | 
					 | 
				
			||||||
 * optimize the AND operation out and just check for zero.
 | 
					 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define SM_NONE			0x0
 | 
					#define SM_IDLE			(-1)
 | 
				
			||||||
#define SM_PREEMPT		0x1
 | 
					#define SM_NONE			0
 | 
				
			||||||
#define SM_RTLOCK_WAIT		0x2
 | 
					#define SM_PREEMPT		1
 | 
				
			||||||
 | 
					#define SM_RTLOCK_WAIT		2
 | 
				
			||||||
#ifndef CONFIG_PREEMPT_RT
 | 
					 | 
				
			||||||
# define SM_MASK_PREEMPT	(~0U)
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
# define SM_MASK_PREEMPT	SM_PREEMPT
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * __schedule() is the main scheduler function.
 | 
					 * __schedule() is the main scheduler function.
 | 
				
			||||||
| 
						 | 
					@ -6395,9 +6462,14 @@ pick_next_task(struct rq *rq, struct task_struct *prev, struct rq_flags *rf)
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * WARNING: must be called with preemption disabled!
 | 
					 * WARNING: must be called with preemption disabled!
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void __sched notrace __schedule(unsigned int sched_mode)
 | 
					static void __sched notrace __schedule(int sched_mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct task_struct *prev, *next;
 | 
						struct task_struct *prev, *next;
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * On PREEMPT_RT kernel, SM_RTLOCK_WAIT is noted
 | 
				
			||||||
 | 
						 * as a preemption by schedule_debug() and RCU.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						bool preempt = sched_mode > SM_NONE;
 | 
				
			||||||
	unsigned long *switch_count;
 | 
						unsigned long *switch_count;
 | 
				
			||||||
	unsigned long prev_state;
 | 
						unsigned long prev_state;
 | 
				
			||||||
	struct rq_flags rf;
 | 
						struct rq_flags rf;
 | 
				
			||||||
| 
						 | 
					@ -6408,13 +6480,13 @@ static void __sched notrace __schedule(unsigned int sched_mode)
 | 
				
			||||||
	rq = cpu_rq(cpu);
 | 
						rq = cpu_rq(cpu);
 | 
				
			||||||
	prev = rq->curr;
 | 
						prev = rq->curr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	schedule_debug(prev, !!sched_mode);
 | 
						schedule_debug(prev, preempt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sched_feat(HRTICK) || sched_feat(HRTICK_DL))
 | 
						if (sched_feat(HRTICK) || sched_feat(HRTICK_DL))
 | 
				
			||||||
		hrtick_clear(rq);
 | 
							hrtick_clear(rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	local_irq_disable();
 | 
						local_irq_disable();
 | 
				
			||||||
	rcu_note_context_switch(!!sched_mode);
 | 
						rcu_note_context_switch(preempt);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Make sure that signal_pending_state()->signal_pending() below
 | 
						 * Make sure that signal_pending_state()->signal_pending() below
 | 
				
			||||||
| 
						 | 
					@ -6443,22 +6515,32 @@ static void __sched notrace __schedule(unsigned int sched_mode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch_count = &prev->nivcsw;
 | 
						switch_count = &prev->nivcsw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Task state changes only considers SM_PREEMPT as preemption */
 | 
				
			||||||
 | 
						preempt = sched_mode == SM_PREEMPT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * We must load prev->state once (task_struct::state is volatile), such
 | 
						 * We must load prev->state once (task_struct::state is volatile), such
 | 
				
			||||||
	 * that we form a control dependency vs deactivate_task() below.
 | 
						 * that we form a control dependency vs deactivate_task() below.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	prev_state = READ_ONCE(prev->__state);
 | 
						prev_state = READ_ONCE(prev->__state);
 | 
				
			||||||
	if (!(sched_mode & SM_MASK_PREEMPT) && prev_state) {
 | 
						if (sched_mode == SM_IDLE) {
 | 
				
			||||||
 | 
							if (!rq->nr_running) {
 | 
				
			||||||
 | 
								next = prev;
 | 
				
			||||||
 | 
								goto picked;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else if (!preempt && prev_state) {
 | 
				
			||||||
		if (signal_pending_state(prev_state, prev)) {
 | 
							if (signal_pending_state(prev_state, prev)) {
 | 
				
			||||||
			WRITE_ONCE(prev->__state, TASK_RUNNING);
 | 
								WRITE_ONCE(prev->__state, TASK_RUNNING);
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
 | 
								int flags = DEQUEUE_NOCLOCK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			prev->sched_contributes_to_load =
 | 
								prev->sched_contributes_to_load =
 | 
				
			||||||
				(prev_state & TASK_UNINTERRUPTIBLE) &&
 | 
									(prev_state & TASK_UNINTERRUPTIBLE) &&
 | 
				
			||||||
				!(prev_state & TASK_NOLOAD) &&
 | 
									!(prev_state & TASK_NOLOAD) &&
 | 
				
			||||||
				!(prev_state & TASK_FROZEN);
 | 
									!(prev_state & TASK_FROZEN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (prev->sched_contributes_to_load)
 | 
								if (unlikely(is_special_task_state(prev_state)))
 | 
				
			||||||
				rq->nr_uninterruptible++;
 | 
									flags |= DEQUEUE_SPECIAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * __schedule()			ttwu()
 | 
								 * __schedule()			ttwu()
 | 
				
			||||||
| 
						 | 
					@ -6471,17 +6553,13 @@ static void __sched notrace __schedule(unsigned int sched_mode)
 | 
				
			||||||
			 *
 | 
								 *
 | 
				
			||||||
			 * After this, schedule() must not care about p->state any more.
 | 
								 * After this, schedule() must not care about p->state any more.
 | 
				
			||||||
			 */
 | 
								 */
 | 
				
			||||||
			deactivate_task(rq, prev, DEQUEUE_SLEEP | DEQUEUE_NOCLOCK);
 | 
								block_task(rq, prev, flags);
 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (prev->in_iowait) {
 | 
					 | 
				
			||||||
				atomic_inc(&rq->nr_iowait);
 | 
					 | 
				
			||||||
				delayacct_blkio_start();
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		switch_count = &prev->nvcsw;
 | 
							switch_count = &prev->nvcsw;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	next = pick_next_task(rq, prev, &rf);
 | 
						next = pick_next_task(rq, prev, &rf);
 | 
				
			||||||
 | 
					picked:
 | 
				
			||||||
	clear_tsk_need_resched(prev);
 | 
						clear_tsk_need_resched(prev);
 | 
				
			||||||
	clear_preempt_need_resched();
 | 
						clear_preempt_need_resched();
 | 
				
			||||||
#ifdef CONFIG_SCHED_DEBUG
 | 
					#ifdef CONFIG_SCHED_DEBUG
 | 
				
			||||||
| 
						 | 
					@ -6523,7 +6601,7 @@ static void __sched notrace __schedule(unsigned int sched_mode)
 | 
				
			||||||
		psi_account_irqtime(rq, prev, next);
 | 
							psi_account_irqtime(rq, prev, next);
 | 
				
			||||||
		psi_sched_switch(prev, next, !task_on_rq_queued(prev));
 | 
							psi_sched_switch(prev, next, !task_on_rq_queued(prev));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		trace_sched_switch(sched_mode & SM_MASK_PREEMPT, prev, next, prev_state);
 | 
							trace_sched_switch(preempt, prev, next, prev_state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* Also unlocks the rq: */
 | 
							/* Also unlocks the rq: */
 | 
				
			||||||
		rq = context_switch(rq, prev, next, &rf);
 | 
							rq = context_switch(rq, prev, next, &rf);
 | 
				
			||||||
| 
						 | 
					@ -6599,7 +6677,7 @@ static void sched_update_worker(struct task_struct *tsk)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __always_inline void __schedule_loop(unsigned int sched_mode)
 | 
					static __always_inline void __schedule_loop(int sched_mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
		preempt_disable();
 | 
							preempt_disable();
 | 
				
			||||||
| 
						 | 
					@ -6644,7 +6722,7 @@ void __sched schedule_idle(void)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	WARN_ON_ONCE(current->__state);
 | 
						WARN_ON_ONCE(current->__state);
 | 
				
			||||||
	do {
 | 
						do {
 | 
				
			||||||
		__schedule(SM_NONE);
 | 
							__schedule(SM_IDLE);
 | 
				
			||||||
	} while (need_resched());
 | 
						} while (need_resched());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8228,8 +8306,6 @@ void __init sched_init(void)
 | 
				
			||||||
#endif /* CONFIG_RT_GROUP_SCHED */
 | 
					#endif /* CONFIG_RT_GROUP_SCHED */
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	init_rt_bandwidth(&def_rt_bandwidth, global_rt_period(), global_rt_runtime());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
	init_defrootdomain();
 | 
						init_defrootdomain();
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					@ -8284,8 +8360,13 @@ void __init sched_init(void)
 | 
				
			||||||
		init_tg_cfs_entry(&root_task_group, &rq->cfs, NULL, i, NULL);
 | 
							init_tg_cfs_entry(&root_task_group, &rq->cfs, NULL, i, NULL);
 | 
				
			||||||
#endif /* CONFIG_FAIR_GROUP_SCHED */
 | 
					#endif /* CONFIG_FAIR_GROUP_SCHED */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime;
 | 
					 | 
				
			||||||
#ifdef CONFIG_RT_GROUP_SCHED
 | 
					#ifdef CONFIG_RT_GROUP_SCHED
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * This is required for init cpu because rt.c:__enable_runtime()
 | 
				
			||||||
 | 
							 * starts working after scheduler_running, which is not the case
 | 
				
			||||||
 | 
							 * yet.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							rq->rt.rt_runtime = global_rt_runtime();
 | 
				
			||||||
		init_tg_rt_entry(&root_task_group, &rq->rt, NULL, i, NULL);
 | 
							init_tg_rt_entry(&root_task_group, &rq->rt, NULL, i, NULL);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
| 
						 | 
					@ -8317,10 +8398,12 @@ void __init sched_init(void)
 | 
				
			||||||
#endif /* CONFIG_SMP */
 | 
					#endif /* CONFIG_SMP */
 | 
				
			||||||
		hrtick_rq_init(rq);
 | 
							hrtick_rq_init(rq);
 | 
				
			||||||
		atomic_set(&rq->nr_iowait, 0);
 | 
							atomic_set(&rq->nr_iowait, 0);
 | 
				
			||||||
 | 
							fair_server_init(rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SCHED_CORE
 | 
					#ifdef CONFIG_SCHED_CORE
 | 
				
			||||||
		rq->core = rq;
 | 
							rq->core = rq;
 | 
				
			||||||
		rq->core_pick = NULL;
 | 
							rq->core_pick = NULL;
 | 
				
			||||||
 | 
							rq->core_dl_server = NULL;
 | 
				
			||||||
		rq->core_enabled = 0;
 | 
							rq->core_enabled = 0;
 | 
				
			||||||
		rq->core_tree = RB_ROOT;
 | 
							rq->core_tree = RB_ROOT;
 | 
				
			||||||
		rq->core_forceidle_count = 0;
 | 
							rq->core_forceidle_count = 0;
 | 
				
			||||||
| 
						 | 
					@ -8333,6 +8416,7 @@ void __init sched_init(void)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	set_load_weight(&init_task, false);
 | 
						set_load_weight(&init_task, false);
 | 
				
			||||||
 | 
						init_task.se.slice = sysctl_sched_base_slice,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The boot idle thread does lazy MMU switching as well:
 | 
						 * The boot idle thread does lazy MMU switching as well:
 | 
				
			||||||
| 
						 | 
					@ -8548,7 +8632,7 @@ void normalize_rt_tasks(void)
 | 
				
			||||||
		schedstat_set(p->stats.sleep_start, 0);
 | 
							schedstat_set(p->stats.sleep_start, 0);
 | 
				
			||||||
		schedstat_set(p->stats.block_start, 0);
 | 
							schedstat_set(p->stats.block_start, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!dl_task(p) && !rt_task(p)) {
 | 
							if (!rt_or_dl_task(p)) {
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * Renice negative nice level userspace
 | 
								 * Renice negative nice level userspace
 | 
				
			||||||
			 * tasks back to 0:
 | 
								 * tasks back to 0:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -654,9 +654,9 @@ static int sugov_kthread_create(struct sugov_policy *sg_policy)
 | 
				
			||||||
		 * Fake (unused) bandwidth; workaround to "fix"
 | 
							 * Fake (unused) bandwidth; workaround to "fix"
 | 
				
			||||||
		 * priority inheritance.
 | 
							 * priority inheritance.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		.sched_runtime	=  1000000,
 | 
							.sched_runtime	= NSEC_PER_MSEC,
 | 
				
			||||||
		.sched_deadline = 10000000,
 | 
							.sched_deadline = 10 * NSEC_PER_MSEC,
 | 
				
			||||||
		.sched_period	= 10000000,
 | 
							.sched_period	= 10 * NSEC_PER_MSEC,
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
	struct cpufreq_policy *policy = sg_policy->policy;
 | 
						struct cpufreq_policy *policy = sg_policy->policy;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -320,19 +320,12 @@ void sub_running_bw(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq)
 | 
				
			||||||
		__sub_running_bw(dl_se->dl_bw, dl_rq);
 | 
							__sub_running_bw(dl_se->dl_bw, dl_rq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dl_change_utilization(struct task_struct *p, u64 new_bw)
 | 
					static void dl_rq_change_utilization(struct rq *rq, struct sched_dl_entity *dl_se, u64 new_bw)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rq *rq;
 | 
						if (dl_se->dl_non_contending) {
 | 
				
			||||||
 | 
							sub_running_bw(dl_se, &rq->dl);
 | 
				
			||||||
 | 
							dl_se->dl_non_contending = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	WARN_ON_ONCE(p->dl.flags & SCHED_FLAG_SUGOV);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (task_on_rq_queued(p))
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rq = task_rq(p);
 | 
					 | 
				
			||||||
	if (p->dl.dl_non_contending) {
 | 
					 | 
				
			||||||
		sub_running_bw(&p->dl, &rq->dl);
 | 
					 | 
				
			||||||
		p->dl.dl_non_contending = 0;
 | 
					 | 
				
			||||||
		/*
 | 
							/*
 | 
				
			||||||
		 * If the timer handler is currently running and the
 | 
							 * If the timer handler is currently running and the
 | 
				
			||||||
		 * timer cannot be canceled, inactive_task_timer()
 | 
							 * timer cannot be canceled, inactive_task_timer()
 | 
				
			||||||
| 
						 | 
					@ -340,13 +333,25 @@ static void dl_change_utilization(struct task_struct *p, u64 new_bw)
 | 
				
			||||||
		 * will not touch the rq's active utilization,
 | 
							 * will not touch the rq's active utilization,
 | 
				
			||||||
		 * so we are still safe.
 | 
							 * so we are still safe.
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (hrtimer_try_to_cancel(&p->dl.inactive_timer) == 1)
 | 
							if (hrtimer_try_to_cancel(&dl_se->inactive_timer) == 1) {
 | 
				
			||||||
			put_task_struct(p);
 | 
								if (!dl_server(dl_se))
 | 
				
			||||||
 | 
									put_task_struct(dl_task_of(dl_se));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	__sub_rq_bw(p->dl.dl_bw, &rq->dl);
 | 
						}
 | 
				
			||||||
 | 
						__sub_rq_bw(dl_se->dl_bw, &rq->dl);
 | 
				
			||||||
	__add_rq_bw(new_bw, &rq->dl);
 | 
						__add_rq_bw(new_bw, &rq->dl);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void dl_change_utilization(struct task_struct *p, u64 new_bw)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						WARN_ON_ONCE(p->dl.flags & SCHED_FLAG_SUGOV);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (task_on_rq_queued(p))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dl_rq_change_utilization(task_rq(p), &p->dl, new_bw);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void __dl_clear_params(struct sched_dl_entity *dl_se);
 | 
					static void __dl_clear_params(struct sched_dl_entity *dl_se);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -771,6 +776,15 @@ static inline void replenish_dl_new_period(struct sched_dl_entity *dl_se,
 | 
				
			||||||
	/* for non-boosted task, pi_of(dl_se) == dl_se */
 | 
						/* for non-boosted task, pi_of(dl_se) == dl_se */
 | 
				
			||||||
	dl_se->deadline = rq_clock(rq) + pi_of(dl_se)->dl_deadline;
 | 
						dl_se->deadline = rq_clock(rq) + pi_of(dl_se)->dl_deadline;
 | 
				
			||||||
	dl_se->runtime = pi_of(dl_se)->dl_runtime;
 | 
						dl_se->runtime = pi_of(dl_se)->dl_runtime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If it is a deferred reservation, and the server
 | 
				
			||||||
 | 
						 * is not handling an starvation case, defer it.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (dl_se->dl_defer & !dl_se->dl_defer_running) {
 | 
				
			||||||
 | 
							dl_se->dl_throttled = 1;
 | 
				
			||||||
 | 
							dl_se->dl_defer_armed = 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -809,6 +823,9 @@ static inline void setup_new_dl_entity(struct sched_dl_entity *dl_se)
 | 
				
			||||||
	replenish_dl_new_period(dl_se, rq);
 | 
						replenish_dl_new_period(dl_se, rq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int start_dl_timer(struct sched_dl_entity *dl_se);
 | 
				
			||||||
 | 
					static bool dl_entity_overflow(struct sched_dl_entity *dl_se, u64 t);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Pure Earliest Deadline First (EDF) scheduling does not deal with the
 | 
					 * Pure Earliest Deadline First (EDF) scheduling does not deal with the
 | 
				
			||||||
 * possibility of a entity lasting more than what it declared, and thus
 | 
					 * possibility of a entity lasting more than what it declared, and thus
 | 
				
			||||||
| 
						 | 
					@ -837,9 +854,18 @@ static void replenish_dl_entity(struct sched_dl_entity *dl_se)
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * This could be the case for a !-dl task that is boosted.
 | 
						 * This could be the case for a !-dl task that is boosted.
 | 
				
			||||||
	 * Just go with full inherited parameters.
 | 
						 * Just go with full inherited parameters.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * Or, it could be the case of a deferred reservation that
 | 
				
			||||||
 | 
						 * was not able to consume its runtime in background and
 | 
				
			||||||
 | 
						 * reached this point with current u > U.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * In both cases, set a new period.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (dl_se->dl_deadline == 0)
 | 
						if (dl_se->dl_deadline == 0 ||
 | 
				
			||||||
		replenish_dl_new_period(dl_se, rq);
 | 
						    (dl_se->dl_defer_armed && dl_entity_overflow(dl_se, rq_clock(rq)))) {
 | 
				
			||||||
 | 
							dl_se->deadline = rq_clock(rq) + pi_of(dl_se)->dl_deadline;
 | 
				
			||||||
 | 
							dl_se->runtime = pi_of(dl_se)->dl_runtime;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dl_se->dl_yielded && dl_se->runtime > 0)
 | 
						if (dl_se->dl_yielded && dl_se->runtime > 0)
 | 
				
			||||||
		dl_se->runtime = 0;
 | 
							dl_se->runtime = 0;
 | 
				
			||||||
| 
						 | 
					@ -873,6 +899,44 @@ static void replenish_dl_entity(struct sched_dl_entity *dl_se)
 | 
				
			||||||
		dl_se->dl_yielded = 0;
 | 
							dl_se->dl_yielded = 0;
 | 
				
			||||||
	if (dl_se->dl_throttled)
 | 
						if (dl_se->dl_throttled)
 | 
				
			||||||
		dl_se->dl_throttled = 0;
 | 
							dl_se->dl_throttled = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If this is the replenishment of a deferred reservation,
 | 
				
			||||||
 | 
						 * clear the flag and return.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (dl_se->dl_defer_armed) {
 | 
				
			||||||
 | 
							dl_se->dl_defer_armed = 0;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * A this point, if the deferred server is not armed, and the deadline
 | 
				
			||||||
 | 
						 * is in the future, if it is not running already, throttle the server
 | 
				
			||||||
 | 
						 * and arm the defer timer.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (dl_se->dl_defer && !dl_se->dl_defer_running &&
 | 
				
			||||||
 | 
						    dl_time_before(rq_clock(dl_se->rq), dl_se->deadline - dl_se->runtime)) {
 | 
				
			||||||
 | 
							if (!is_dl_boosted(dl_se) && dl_se->server_has_tasks(dl_se)) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * Set dl_se->dl_defer_armed and dl_throttled variables to
 | 
				
			||||||
 | 
								 * inform the start_dl_timer() that this is a deferred
 | 
				
			||||||
 | 
								 * activation.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								dl_se->dl_defer_armed = 1;
 | 
				
			||||||
 | 
								dl_se->dl_throttled = 1;
 | 
				
			||||||
 | 
								if (!start_dl_timer(dl_se)) {
 | 
				
			||||||
 | 
									/*
 | 
				
			||||||
 | 
									 * If for whatever reason (delays), a previous timer was
 | 
				
			||||||
 | 
									 * queued but not serviced, cancel it and clean the
 | 
				
			||||||
 | 
									 * deferrable server variables intended for start_dl_timer().
 | 
				
			||||||
 | 
									 */
 | 
				
			||||||
 | 
									hrtimer_try_to_cancel(&dl_se->dl_timer);
 | 
				
			||||||
 | 
									dl_se->dl_defer_armed = 0;
 | 
				
			||||||
 | 
									dl_se->dl_throttled = 0;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -1023,6 +1087,15 @@ static void update_dl_entity(struct sched_dl_entity *dl_se)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		replenish_dl_new_period(dl_se, rq);
 | 
							replenish_dl_new_period(dl_se, rq);
 | 
				
			||||||
 | 
						} else if (dl_server(dl_se) && dl_se->dl_defer) {
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * The server can still use its previous deadline, so check if
 | 
				
			||||||
 | 
							 * it left the dl_defer_running state.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (!dl_se->dl_defer_running) {
 | 
				
			||||||
 | 
								dl_se->dl_defer_armed = 1;
 | 
				
			||||||
 | 
								dl_se->dl_throttled = 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1055,8 +1128,21 @@ static int start_dl_timer(struct sched_dl_entity *dl_se)
 | 
				
			||||||
	 * We want the timer to fire at the deadline, but considering
 | 
						 * We want the timer to fire at the deadline, but considering
 | 
				
			||||||
	 * that it is actually coming from rq->clock and not from
 | 
						 * that it is actually coming from rq->clock and not from
 | 
				
			||||||
	 * hrtimer's time base reading.
 | 
						 * hrtimer's time base reading.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * The deferred reservation will have its timer set to
 | 
				
			||||||
 | 
						 * (deadline - runtime). At that point, the CBS rule will decide
 | 
				
			||||||
 | 
						 * if the current deadline can be used, or if a replenishment is
 | 
				
			||||||
 | 
						 * required to avoid add too much pressure on the system
 | 
				
			||||||
 | 
						 * (current u > U).
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
						if (dl_se->dl_defer_armed) {
 | 
				
			||||||
 | 
							WARN_ON_ONCE(!dl_se->dl_throttled);
 | 
				
			||||||
 | 
							act = ns_to_ktime(dl_se->deadline - dl_se->runtime);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							/* act = deadline - rel-deadline + period */
 | 
				
			||||||
		act = ns_to_ktime(dl_next_period(dl_se));
 | 
							act = ns_to_ktime(dl_next_period(dl_se));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	now = hrtimer_cb_get_time(timer);
 | 
						now = hrtimer_cb_get_time(timer);
 | 
				
			||||||
	delta = ktime_to_ns(now) - rq_clock(rq);
 | 
						delta = ktime_to_ns(now) - rq_clock(rq);
 | 
				
			||||||
	act = ktime_add_ns(act, delta);
 | 
						act = ktime_add_ns(act, delta);
 | 
				
			||||||
| 
						 | 
					@ -1106,6 +1192,62 @@ static void __push_dl_task(struct rq *rq, struct rq_flags *rf)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* a defer timer will not be reset if the runtime consumed was < dl_server_min_res */
 | 
				
			||||||
 | 
					static const u64 dl_server_min_res = 1 * NSEC_PER_MSEC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static enum hrtimer_restart dl_server_timer(struct hrtimer *timer, struct sched_dl_entity *dl_se)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rq *rq = rq_of_dl_se(dl_se);
 | 
				
			||||||
 | 
						u64 fw;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						scoped_guard (rq_lock, rq) {
 | 
				
			||||||
 | 
							struct rq_flags *rf = &scope.rf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!dl_se->dl_throttled || !dl_se->dl_runtime)
 | 
				
			||||||
 | 
								return HRTIMER_NORESTART;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							sched_clock_tick();
 | 
				
			||||||
 | 
							update_rq_clock(rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!dl_se->dl_runtime)
 | 
				
			||||||
 | 
								return HRTIMER_NORESTART;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!dl_se->server_has_tasks(dl_se)) {
 | 
				
			||||||
 | 
								replenish_dl_entity(dl_se);
 | 
				
			||||||
 | 
								return HRTIMER_NORESTART;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (dl_se->dl_defer_armed) {
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * First check if the server could consume runtime in background.
 | 
				
			||||||
 | 
								 * If so, it is possible to push the defer timer for this amount
 | 
				
			||||||
 | 
								 * of time. The dl_server_min_res serves as a limit to avoid
 | 
				
			||||||
 | 
								 * forwarding the timer for a too small amount of time.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								if (dl_time_before(rq_clock(dl_se->rq),
 | 
				
			||||||
 | 
										   (dl_se->deadline - dl_se->runtime - dl_server_min_res))) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* reset the defer timer */
 | 
				
			||||||
 | 
									fw = dl_se->deadline - rq_clock(dl_se->rq) - dl_se->runtime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									hrtimer_forward_now(timer, ns_to_ktime(fw));
 | 
				
			||||||
 | 
									return HRTIMER_RESTART;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								dl_se->dl_defer_running = 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							enqueue_dl_entity(dl_se, ENQUEUE_REPLENISH);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!dl_task(dl_se->rq->curr) || dl_entity_preempt(dl_se, &dl_se->rq->curr->dl))
 | 
				
			||||||
 | 
								resched_curr(rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							__push_dl_task(rq, rf);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return HRTIMER_NORESTART;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This is the bandwidth enforcement timer callback. If here, we know
 | 
					 * This is the bandwidth enforcement timer callback. If here, we know
 | 
				
			||||||
 * a task is not on its dl_rq, since the fact that the timer was running
 | 
					 * a task is not on its dl_rq, since the fact that the timer was running
 | 
				
			||||||
| 
						 | 
					@ -1128,28 +1270,8 @@ static enum hrtimer_restart dl_task_timer(struct hrtimer *timer)
 | 
				
			||||||
	struct rq_flags rf;
 | 
						struct rq_flags rf;
 | 
				
			||||||
	struct rq *rq;
 | 
						struct rq *rq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dl_server(dl_se)) {
 | 
						if (dl_server(dl_se))
 | 
				
			||||||
		struct rq *rq = rq_of_dl_se(dl_se);
 | 
							return dl_server_timer(timer, dl_se);
 | 
				
			||||||
		struct rq_flags rf;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		rq_lock(rq, &rf);
 | 
					 | 
				
			||||||
		if (dl_se->dl_throttled) {
 | 
					 | 
				
			||||||
			sched_clock_tick();
 | 
					 | 
				
			||||||
			update_rq_clock(rq);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			if (dl_se->server_has_tasks(dl_se)) {
 | 
					 | 
				
			||||||
				enqueue_dl_entity(dl_se, ENQUEUE_REPLENISH);
 | 
					 | 
				
			||||||
				resched_curr(rq);
 | 
					 | 
				
			||||||
				__push_dl_task(rq, &rf);
 | 
					 | 
				
			||||||
			} else {
 | 
					 | 
				
			||||||
				replenish_dl_entity(dl_se);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		rq_unlock(rq, &rf);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return HRTIMER_NORESTART;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p = dl_task_of(dl_se);
 | 
						p = dl_task_of(dl_se);
 | 
				
			||||||
	rq = task_rq_lock(p, &rf);
 | 
						rq = task_rq_lock(p, &rf);
 | 
				
			||||||
| 
						 | 
					@ -1319,22 +1441,10 @@ static u64 grub_reclaim(u64 delta, struct rq *rq, struct sched_dl_entity *dl_se)
 | 
				
			||||||
	return (delta * u_act) >> BW_SHIFT;
 | 
						return (delta * u_act) >> BW_SHIFT;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void
 | 
					s64 dl_scaled_delta_exec(struct rq *rq, struct sched_dl_entity *dl_se, s64 delta_exec)
 | 
				
			||||||
update_stats_dequeue_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se,
 | 
					 | 
				
			||||||
                        int flags);
 | 
					 | 
				
			||||||
static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64 delta_exec)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	s64 scaled_delta_exec;
 | 
						s64 scaled_delta_exec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (unlikely(delta_exec <= 0)) {
 | 
					 | 
				
			||||||
		if (unlikely(dl_se->dl_yielded))
 | 
					 | 
				
			||||||
			goto throttle;
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (dl_entity_is_special(dl_se))
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * For tasks that participate in GRUB, we implement GRUB-PA: the
 | 
						 * For tasks that participate in GRUB, we implement GRUB-PA: the
 | 
				
			||||||
	 * spare reclaimed bandwidth is used to clock down frequency.
 | 
						 * spare reclaimed bandwidth is used to clock down frequency.
 | 
				
			||||||
| 
						 | 
					@ -1353,8 +1463,64 @@ static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64
 | 
				
			||||||
		scaled_delta_exec = cap_scale(scaled_delta_exec, scale_cpu);
 | 
							scaled_delta_exec = cap_scale(scaled_delta_exec, scale_cpu);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return scaled_delta_exec;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					update_stats_dequeue_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se,
 | 
				
			||||||
 | 
								int flags);
 | 
				
			||||||
 | 
					static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64 delta_exec)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						s64 scaled_delta_exec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (unlikely(delta_exec <= 0)) {
 | 
				
			||||||
 | 
							if (unlikely(dl_se->dl_yielded))
 | 
				
			||||||
 | 
								goto throttle;
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dl_server(dl_se) && dl_se->dl_throttled && !dl_se->dl_defer)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dl_entity_is_special(dl_se))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						scaled_delta_exec = dl_scaled_delta_exec(rq, dl_se, delta_exec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dl_se->runtime -= scaled_delta_exec;
 | 
						dl_se->runtime -= scaled_delta_exec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * The fair server can consume its runtime while throttled (not queued/
 | 
				
			||||||
 | 
						 * running as regular CFS).
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * If the server consumes its entire runtime in this state. The server
 | 
				
			||||||
 | 
						 * is not required for the current period. Thus, reset the server by
 | 
				
			||||||
 | 
						 * starting a new period, pushing the activation.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (dl_se->dl_defer && dl_se->dl_throttled && dl_runtime_exceeded(dl_se)) {
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * If the server was previously activated - the starving condition
 | 
				
			||||||
 | 
							 * took place, it this point it went away because the fair scheduler
 | 
				
			||||||
 | 
							 * was able to get runtime in background. So return to the initial
 | 
				
			||||||
 | 
							 * state.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							dl_se->dl_defer_running = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							hrtimer_try_to_cancel(&dl_se->dl_timer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							replenish_dl_new_period(dl_se, dl_se->rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Not being able to start the timer seems problematic. If it could not
 | 
				
			||||||
 | 
							 * be started for whatever reason, we need to "unthrottle" the DL server
 | 
				
			||||||
 | 
							 * and queue right away. Otherwise nothing might queue it. That's similar
 | 
				
			||||||
 | 
							 * to what enqueue_dl_entity() does on start_dl_timer==0. For now, just warn.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							WARN_ON_ONCE(!start_dl_timer(dl_se));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
throttle:
 | 
					throttle:
 | 
				
			||||||
	if (dl_runtime_exceeded(dl_se) || dl_se->dl_yielded) {
 | 
						if (dl_runtime_exceeded(dl_se) || dl_se->dl_yielded) {
 | 
				
			||||||
		dl_se->dl_throttled = 1;
 | 
							dl_se->dl_throttled = 1;
 | 
				
			||||||
| 
						 | 
					@ -1381,6 +1547,14 @@ static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64
 | 
				
			||||||
			resched_curr(rq);
 | 
								resched_curr(rq);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * The fair server (sole dl_server) does not account for real-time
 | 
				
			||||||
 | 
						 * workload because it is running fair work.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (dl_se == &rq->fair_server)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_RT_GROUP_SCHED
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Because -- for now -- we share the rt bandwidth, we need to
 | 
						 * Because -- for now -- we share the rt bandwidth, we need to
 | 
				
			||||||
	 * account our runtime there too, otherwise actual rt tasks
 | 
						 * account our runtime there too, otherwise actual rt tasks
 | 
				
			||||||
| 
						 | 
					@ -1405,34 +1579,155 @@ static void update_curr_dl_se(struct rq *rq, struct sched_dl_entity *dl_se, s64
 | 
				
			||||||
			rt_rq->rt_time += delta_exec;
 | 
								rt_rq->rt_time += delta_exec;
 | 
				
			||||||
		raw_spin_unlock(&rt_rq->rt_runtime_lock);
 | 
							raw_spin_unlock(&rt_rq->rt_runtime_lock);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * In the non-defer mode, the idle time is not accounted, as the
 | 
				
			||||||
 | 
					 * server provides a guarantee.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * If the dl_server is in defer mode, the idle time is also considered
 | 
				
			||||||
 | 
					 * as time available for the fair server, avoiding a penalty for the
 | 
				
			||||||
 | 
					 * rt scheduler that did not consumed that time.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void dl_server_update_idle_time(struct rq *rq, struct task_struct *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						s64 delta_exec, scaled_delta_exec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!rq->fair_server.dl_defer)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* no need to discount more */
 | 
				
			||||||
 | 
						if (rq->fair_server.runtime < 0)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						delta_exec = rq_clock_task(rq) - p->se.exec_start;
 | 
				
			||||||
 | 
						if (delta_exec < 0)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						scaled_delta_exec = dl_scaled_delta_exec(rq, &rq->fair_server, delta_exec);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						rq->fair_server.runtime -= scaled_delta_exec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rq->fair_server.runtime < 0) {
 | 
				
			||||||
 | 
							rq->fair_server.dl_defer_running = 0;
 | 
				
			||||||
 | 
							rq->fair_server.runtime = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						p->se.exec_start = rq_clock_task(rq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec)
 | 
					void dl_server_update(struct sched_dl_entity *dl_se, s64 delta_exec)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						/* 0 runtime = fair server disabled */
 | 
				
			||||||
 | 
						if (dl_se->dl_runtime)
 | 
				
			||||||
		update_curr_dl_se(dl_se->rq, dl_se, delta_exec);
 | 
							update_curr_dl_se(dl_se->rq, dl_se, delta_exec);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void dl_server_start(struct sched_dl_entity *dl_se)
 | 
					void dl_server_start(struct sched_dl_entity *dl_se)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct rq *rq = dl_se->rq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * XXX: the apply do not work fine at the init phase for the
 | 
				
			||||||
 | 
						 * fair server because things are not yet set. We need to improve
 | 
				
			||||||
 | 
						 * this before getting generic.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
	if (!dl_server(dl_se)) {
 | 
						if (!dl_server(dl_se)) {
 | 
				
			||||||
 | 
							u64 runtime =  50 * NSEC_PER_MSEC;
 | 
				
			||||||
 | 
							u64 period = 1000 * NSEC_PER_MSEC;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dl_server_apply_params(dl_se, runtime, period, 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		dl_se->dl_server = 1;
 | 
							dl_se->dl_server = 1;
 | 
				
			||||||
 | 
							dl_se->dl_defer = 1;
 | 
				
			||||||
		setup_new_dl_entity(dl_se);
 | 
							setup_new_dl_entity(dl_se);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dl_se->dl_runtime)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	enqueue_dl_entity(dl_se, ENQUEUE_WAKEUP);
 | 
						enqueue_dl_entity(dl_se, ENQUEUE_WAKEUP);
 | 
				
			||||||
 | 
						if (!dl_task(dl_se->rq->curr) || dl_entity_preempt(dl_se, &rq->curr->dl))
 | 
				
			||||||
 | 
							resched_curr(dl_se->rq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void dl_server_stop(struct sched_dl_entity *dl_se)
 | 
					void dl_server_stop(struct sched_dl_entity *dl_se)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if (!dl_se->dl_runtime)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dequeue_dl_entity(dl_se, DEQUEUE_SLEEP);
 | 
						dequeue_dl_entity(dl_se, DEQUEUE_SLEEP);
 | 
				
			||||||
 | 
						hrtimer_try_to_cancel(&dl_se->dl_timer);
 | 
				
			||||||
 | 
						dl_se->dl_defer_armed = 0;
 | 
				
			||||||
 | 
						dl_se->dl_throttled = 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,
 | 
					void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,
 | 
				
			||||||
		    dl_server_has_tasks_f has_tasks,
 | 
							    dl_server_has_tasks_f has_tasks,
 | 
				
			||||||
		    dl_server_pick_f pick)
 | 
							    dl_server_pick_f pick_task)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dl_se->rq = rq;
 | 
						dl_se->rq = rq;
 | 
				
			||||||
	dl_se->server_has_tasks = has_tasks;
 | 
						dl_se->server_has_tasks = has_tasks;
 | 
				
			||||||
	dl_se->server_pick = pick;
 | 
						dl_se->server_pick_task = pick_task;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void __dl_server_attach_root(struct sched_dl_entity *dl_se, struct rq *rq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u64 new_bw = dl_se->dl_bw;
 | 
				
			||||||
 | 
						int cpu = cpu_of(rq);
 | 
				
			||||||
 | 
						struct dl_bw *dl_b;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dl_b = dl_bw_of(cpu_of(rq));
 | 
				
			||||||
 | 
						guard(raw_spinlock)(&dl_b->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dl_bw_cpus(cpu))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__dl_add(dl_b, new_bw, dl_bw_cpus(cpu));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int dl_server_apply_params(struct sched_dl_entity *dl_se, u64 runtime, u64 period, bool init)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						u64 old_bw = init ? 0 : to_ratio(dl_se->dl_period, dl_se->dl_runtime);
 | 
				
			||||||
 | 
						u64 new_bw = to_ratio(period, runtime);
 | 
				
			||||||
 | 
						struct rq *rq = dl_se->rq;
 | 
				
			||||||
 | 
						int cpu = cpu_of(rq);
 | 
				
			||||||
 | 
						struct dl_bw *dl_b;
 | 
				
			||||||
 | 
						unsigned long cap;
 | 
				
			||||||
 | 
						int retval = 0;
 | 
				
			||||||
 | 
						int cpus;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dl_b = dl_bw_of(cpu);
 | 
				
			||||||
 | 
						guard(raw_spinlock)(&dl_b->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cpus = dl_bw_cpus(cpu);
 | 
				
			||||||
 | 
						cap = dl_bw_capacity(cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (__dl_overflow(dl_b, cap, old_bw, new_bw))
 | 
				
			||||||
 | 
							return -EBUSY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (init) {
 | 
				
			||||||
 | 
							__add_rq_bw(new_bw, &rq->dl);
 | 
				
			||||||
 | 
							__dl_add(dl_b, new_bw, cpus);
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							__dl_sub(dl_b, dl_se->dl_bw, cpus);
 | 
				
			||||||
 | 
							__dl_add(dl_b, new_bw, cpus);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							dl_rq_change_utilization(rq, dl_se, new_bw);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dl_se->dl_runtime = runtime;
 | 
				
			||||||
 | 
						dl_se->dl_deadline = period;
 | 
				
			||||||
 | 
						dl_se->dl_period = period;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dl_se->runtime = 0;
 | 
				
			||||||
 | 
						dl_se->deadline = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dl_se->dl_bw = to_ratio(dl_se->dl_period, dl_se->dl_runtime);
 | 
				
			||||||
 | 
						dl_se->dl_density = to_ratio(dl_se->dl_deadline, dl_se->dl_runtime);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -1599,45 +1894,39 @@ static inline bool __dl_less(struct rb_node *a, const struct rb_node *b)
 | 
				
			||||||
	return dl_time_before(__node_2_dle(a)->deadline, __node_2_dle(b)->deadline);
 | 
						return dl_time_before(__node_2_dle(a)->deadline, __node_2_dle(b)->deadline);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline struct sched_statistics *
 | 
					static __always_inline struct sched_statistics *
 | 
				
			||||||
__schedstats_from_dl_se(struct sched_dl_entity *dl_se)
 | 
					__schedstats_from_dl_se(struct sched_dl_entity *dl_se)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if (!schedstat_enabled())
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dl_server(dl_se))
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return &dl_task_of(dl_se)->stats;
 | 
						return &dl_task_of(dl_se)->stats;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void
 | 
					static inline void
 | 
				
			||||||
update_stats_wait_start_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se)
 | 
					update_stats_wait_start_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sched_statistics *stats;
 | 
						struct sched_statistics *stats = __schedstats_from_dl_se(dl_se);
 | 
				
			||||||
 | 
						if (stats)
 | 
				
			||||||
	if (!schedstat_enabled())
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stats = __schedstats_from_dl_se(dl_se);
 | 
					 | 
				
			||||||
		__update_stats_wait_start(rq_of_dl_rq(dl_rq), dl_task_of(dl_se), stats);
 | 
							__update_stats_wait_start(rq_of_dl_rq(dl_rq), dl_task_of(dl_se), stats);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void
 | 
					static inline void
 | 
				
			||||||
update_stats_wait_end_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se)
 | 
					update_stats_wait_end_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sched_statistics *stats;
 | 
						struct sched_statistics *stats = __schedstats_from_dl_se(dl_se);
 | 
				
			||||||
 | 
						if (stats)
 | 
				
			||||||
	if (!schedstat_enabled())
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stats = __schedstats_from_dl_se(dl_se);
 | 
					 | 
				
			||||||
		__update_stats_wait_end(rq_of_dl_rq(dl_rq), dl_task_of(dl_se), stats);
 | 
							__update_stats_wait_end(rq_of_dl_rq(dl_rq), dl_task_of(dl_se), stats);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void
 | 
					static inline void
 | 
				
			||||||
update_stats_enqueue_sleeper_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se)
 | 
					update_stats_enqueue_sleeper_dl(struct dl_rq *dl_rq, struct sched_dl_entity *dl_se)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sched_statistics *stats;
 | 
						struct sched_statistics *stats = __schedstats_from_dl_se(dl_se);
 | 
				
			||||||
 | 
						if (stats)
 | 
				
			||||||
	if (!schedstat_enabled())
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	stats = __schedstats_from_dl_se(dl_se);
 | 
					 | 
				
			||||||
		__update_stats_enqueue_sleeper(rq_of_dl_rq(dl_rq), dl_task_of(dl_se), stats);
 | 
							__update_stats_enqueue_sleeper(rq_of_dl_rq(dl_rq), dl_task_of(dl_se), stats);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1735,7 +2024,7 @@ enqueue_dl_entity(struct sched_dl_entity *dl_se, int flags)
 | 
				
			||||||
	 * be counted in the active utilization; hence, we need to call
 | 
						 * be counted in the active utilization; hence, we need to call
 | 
				
			||||||
	 * add_running_bw().
 | 
						 * add_running_bw().
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (dl_se->dl_throttled && !(flags & ENQUEUE_REPLENISH)) {
 | 
						if (!dl_se->dl_defer && dl_se->dl_throttled && !(flags & ENQUEUE_REPLENISH)) {
 | 
				
			||||||
		if (flags & ENQUEUE_WAKEUP)
 | 
							if (flags & ENQUEUE_WAKEUP)
 | 
				
			||||||
			task_contending(dl_se, flags);
 | 
								task_contending(dl_se, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1757,6 +2046,25 @@ enqueue_dl_entity(struct sched_dl_entity *dl_se, int flags)
 | 
				
			||||||
		setup_new_dl_entity(dl_se);
 | 
							setup_new_dl_entity(dl_se);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * If the reservation is still throttled, e.g., it got replenished but is a
 | 
				
			||||||
 | 
						 * deferred task and still got to wait, don't enqueue.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (dl_se->dl_throttled && start_dl_timer(dl_se))
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * We're about to enqueue, make sure we're not ->dl_throttled!
 | 
				
			||||||
 | 
						 * In case the timer was not started, say because the defer time
 | 
				
			||||||
 | 
						 * has passed, mark as not throttled and mark unarmed.
 | 
				
			||||||
 | 
						 * Also cancel earlier timers, since letting those run is pointless.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (dl_se->dl_throttled) {
 | 
				
			||||||
 | 
							hrtimer_try_to_cancel(&dl_se->dl_timer);
 | 
				
			||||||
 | 
							dl_se->dl_defer_armed = 0;
 | 
				
			||||||
 | 
							dl_se->dl_throttled = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	__enqueue_dl_entity(dl_se);
 | 
						__enqueue_dl_entity(dl_se);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1846,7 +2154,7 @@ static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
		enqueue_pushable_dl_task(rq, p);
 | 
							enqueue_pushable_dl_task(rq, p);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags)
 | 
					static bool dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	update_curr_dl(rq);
 | 
						update_curr_dl(rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1856,6 +2164,8 @@ static void dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
	dequeue_dl_entity(&p->dl, flags);
 | 
						dequeue_dl_entity(&p->dl, flags);
 | 
				
			||||||
	if (!p->dl.dl_throttled && !dl_server(&p->dl))
 | 
						if (!p->dl.dl_throttled && !dl_server(&p->dl))
 | 
				
			||||||
		dequeue_pushable_dl_task(rq, p);
 | 
							dequeue_pushable_dl_task(rq, p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -2074,6 +2384,9 @@ static void set_next_task_dl(struct rq *rq, struct task_struct *p, bool first)
 | 
				
			||||||
		update_dl_rq_load_avg(rq_clock_pelt(rq), rq, 0);
 | 
							update_dl_rq_load_avg(rq_clock_pelt(rq), rq, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	deadline_queue_push_tasks(rq);
 | 
						deadline_queue_push_tasks(rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (hrtick_enabled(rq))
 | 
				
			||||||
 | 
							start_hrtick_dl(rq, &p->dl);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct sched_dl_entity *pick_next_dl_entity(struct dl_rq *dl_rq)
 | 
					static struct sched_dl_entity *pick_next_dl_entity(struct dl_rq *dl_rq)
 | 
				
			||||||
| 
						 | 
					@ -2086,7 +2399,11 @@ static struct sched_dl_entity *pick_next_dl_entity(struct dl_rq *dl_rq)
 | 
				
			||||||
	return __node_2_dle(left);
 | 
						return __node_2_dle(left);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct task_struct *pick_task_dl(struct rq *rq)
 | 
					/*
 | 
				
			||||||
 | 
					 * __pick_next_task_dl - Helper to pick the next -deadline task to run.
 | 
				
			||||||
 | 
					 * @rq: The runqueue to pick the next task from.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct task_struct *__pick_task_dl(struct rq *rq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sched_dl_entity *dl_se;
 | 
						struct sched_dl_entity *dl_se;
 | 
				
			||||||
	struct dl_rq *dl_rq = &rq->dl;
 | 
						struct dl_rq *dl_rq = &rq->dl;
 | 
				
			||||||
| 
						 | 
					@ -2100,14 +2417,13 @@ static struct task_struct *pick_task_dl(struct rq *rq)
 | 
				
			||||||
	WARN_ON_ONCE(!dl_se);
 | 
						WARN_ON_ONCE(!dl_se);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dl_server(dl_se)) {
 | 
						if (dl_server(dl_se)) {
 | 
				
			||||||
		p = dl_se->server_pick(dl_se);
 | 
							p = dl_se->server_pick_task(dl_se);
 | 
				
			||||||
		if (!p) {
 | 
							if (!p) {
 | 
				
			||||||
			WARN_ON_ONCE(1);
 | 
					 | 
				
			||||||
			dl_se->dl_yielded = 1;
 | 
								dl_se->dl_yielded = 1;
 | 
				
			||||||
			update_curr_dl_se(rq, dl_se, 0);
 | 
								update_curr_dl_se(rq, dl_se, 0);
 | 
				
			||||||
			goto again;
 | 
								goto again;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		p->dl_server = dl_se;
 | 
							rq->dl_server = dl_se;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		p = dl_task_of(dl_se);
 | 
							p = dl_task_of(dl_se);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -2115,24 +2431,12 @@ static struct task_struct *pick_task_dl(struct rq *rq)
 | 
				
			||||||
	return p;
 | 
						return p;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct task_struct *pick_next_task_dl(struct rq *rq)
 | 
					static struct task_struct *pick_task_dl(struct rq *rq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct task_struct *p;
 | 
						return __pick_task_dl(rq);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	p = pick_task_dl(rq);
 | 
					 | 
				
			||||||
	if (!p)
 | 
					 | 
				
			||||||
		return p;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!p->dl_server)
 | 
					 | 
				
			||||||
		set_next_task_dl(rq, p, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (hrtick_enabled(rq))
 | 
					 | 
				
			||||||
		start_hrtick_dl(rq, &p->dl);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return p;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void put_prev_task_dl(struct rq *rq, struct task_struct *p)
 | 
					static void put_prev_task_dl(struct rq *rq, struct task_struct *p, struct task_struct *next)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sched_dl_entity *dl_se = &p->dl;
 | 
						struct sched_dl_entity *dl_se = &p->dl;
 | 
				
			||||||
	struct dl_rq *dl_rq = &rq->dl;
 | 
						struct dl_rq *dl_rq = &rq->dl;
 | 
				
			||||||
| 
						 | 
					@ -2824,13 +3128,12 @@ DEFINE_SCHED_CLASS(dl) = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.wakeup_preempt		= wakeup_preempt_dl,
 | 
						.wakeup_preempt		= wakeup_preempt_dl,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.pick_next_task		= pick_next_task_dl,
 | 
						.pick_task		= pick_task_dl,
 | 
				
			||||||
	.put_prev_task		= put_prev_task_dl,
 | 
						.put_prev_task		= put_prev_task_dl,
 | 
				
			||||||
	.set_next_task		= set_next_task_dl,
 | 
						.set_next_task		= set_next_task_dl,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
	.balance		= balance_dl,
 | 
						.balance		= balance_dl,
 | 
				
			||||||
	.pick_task		= pick_task_dl,
 | 
					 | 
				
			||||||
	.select_task_rq		= select_task_rq_dl,
 | 
						.select_task_rq		= select_task_rq_dl,
 | 
				
			||||||
	.migrate_task_rq	= migrate_task_rq_dl,
 | 
						.migrate_task_rq	= migrate_task_rq_dl,
 | 
				
			||||||
	.set_cpus_allowed       = set_cpus_allowed_dl,
 | 
						.set_cpus_allowed       = set_cpus_allowed_dl,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -333,8 +333,165 @@ static const struct file_operations sched_debug_fops = {
 | 
				
			||||||
	.release	= seq_release,
 | 
						.release	= seq_release,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum dl_param {
 | 
				
			||||||
 | 
						DL_RUNTIME = 0,
 | 
				
			||||||
 | 
						DL_PERIOD,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static unsigned long fair_server_period_max = (1UL << 22) * NSEC_PER_USEC; /* ~4 seconds */
 | 
				
			||||||
 | 
					static unsigned long fair_server_period_min = (100) * NSEC_PER_USEC;     /* 100 us */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t sched_fair_server_write(struct file *filp, const char __user *ubuf,
 | 
				
			||||||
 | 
									       size_t cnt, loff_t *ppos, enum dl_param param)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						long cpu = (long) ((struct seq_file *) filp->private_data)->private;
 | 
				
			||||||
 | 
						struct rq *rq = cpu_rq(cpu);
 | 
				
			||||||
 | 
						u64 runtime, period;
 | 
				
			||||||
 | 
						size_t err;
 | 
				
			||||||
 | 
						int retval;
 | 
				
			||||||
 | 
						u64 value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						err = kstrtoull_from_user(ubuf, cnt, 10, &value);
 | 
				
			||||||
 | 
						if (err)
 | 
				
			||||||
 | 
							return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						scoped_guard (rq_lock_irqsave, rq) {
 | 
				
			||||||
 | 
							runtime  = rq->fair_server.dl_runtime;
 | 
				
			||||||
 | 
							period = rq->fair_server.dl_period;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							switch (param) {
 | 
				
			||||||
 | 
							case DL_RUNTIME:
 | 
				
			||||||
 | 
								if (runtime == value)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								runtime = value;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case DL_PERIOD:
 | 
				
			||||||
 | 
								if (value == period)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								period = value;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (runtime > period ||
 | 
				
			||||||
 | 
							    period > fair_server_period_max ||
 | 
				
			||||||
 | 
							    period < fair_server_period_min) {
 | 
				
			||||||
 | 
								return  -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (rq->cfs.h_nr_running) {
 | 
				
			||||||
 | 
								update_rq_clock(rq);
 | 
				
			||||||
 | 
								dl_server_stop(&rq->fair_server);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							retval = dl_server_apply_params(&rq->fair_server, runtime, period, 0);
 | 
				
			||||||
 | 
							if (retval)
 | 
				
			||||||
 | 
								cnt = retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!runtime)
 | 
				
			||||||
 | 
								printk_deferred("Fair server disabled in CPU %d, system may crash due to starvation.\n",
 | 
				
			||||||
 | 
										cpu_of(rq));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (rq->cfs.h_nr_running)
 | 
				
			||||||
 | 
								dl_server_start(&rq->fair_server);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*ppos += cnt;
 | 
				
			||||||
 | 
						return cnt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static size_t sched_fair_server_show(struct seq_file *m, void *v, enum dl_param param)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long cpu = (unsigned long) m->private;
 | 
				
			||||||
 | 
						struct rq *rq = cpu_rq(cpu);
 | 
				
			||||||
 | 
						u64 value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (param) {
 | 
				
			||||||
 | 
						case DL_RUNTIME:
 | 
				
			||||||
 | 
							value = rq->fair_server.dl_runtime;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case DL_PERIOD:
 | 
				
			||||||
 | 
							value = rq->fair_server.dl_period;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						seq_printf(m, "%llu\n", value);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t
 | 
				
			||||||
 | 
					sched_fair_server_runtime_write(struct file *filp, const char __user *ubuf,
 | 
				
			||||||
 | 
									size_t cnt, loff_t *ppos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return sched_fair_server_write(filp, ubuf, cnt, ppos, DL_RUNTIME);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int sched_fair_server_runtime_show(struct seq_file *m, void *v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return sched_fair_server_show(m, v, DL_RUNTIME);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int sched_fair_server_runtime_open(struct inode *inode, struct file *filp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return single_open(filp, sched_fair_server_runtime_show, inode->i_private);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct file_operations fair_server_runtime_fops = {
 | 
				
			||||||
 | 
						.open		= sched_fair_server_runtime_open,
 | 
				
			||||||
 | 
						.write		= sched_fair_server_runtime_write,
 | 
				
			||||||
 | 
						.read		= seq_read,
 | 
				
			||||||
 | 
						.llseek		= seq_lseek,
 | 
				
			||||||
 | 
						.release	= single_release,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t
 | 
				
			||||||
 | 
					sched_fair_server_period_write(struct file *filp, const char __user *ubuf,
 | 
				
			||||||
 | 
								       size_t cnt, loff_t *ppos)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return sched_fair_server_write(filp, ubuf, cnt, ppos, DL_PERIOD);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int sched_fair_server_period_show(struct seq_file *m, void *v)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return sched_fair_server_show(m, v, DL_PERIOD);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int sched_fair_server_period_open(struct inode *inode, struct file *filp)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return single_open(filp, sched_fair_server_period_show, inode->i_private);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct file_operations fair_server_period_fops = {
 | 
				
			||||||
 | 
						.open		= sched_fair_server_period_open,
 | 
				
			||||||
 | 
						.write		= sched_fair_server_period_write,
 | 
				
			||||||
 | 
						.read		= seq_read,
 | 
				
			||||||
 | 
						.llseek		= seq_lseek,
 | 
				
			||||||
 | 
						.release	= single_release,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct dentry *debugfs_sched;
 | 
					static struct dentry *debugfs_sched;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void debugfs_fair_server_init(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct dentry *d_fair;
 | 
				
			||||||
 | 
						unsigned long cpu;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						d_fair = debugfs_create_dir("fair_server", debugfs_sched);
 | 
				
			||||||
 | 
						if (!d_fair)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for_each_possible_cpu(cpu) {
 | 
				
			||||||
 | 
							struct dentry *d_cpu;
 | 
				
			||||||
 | 
							char buf[32];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							snprintf(buf, sizeof(buf), "cpu%lu", cpu);
 | 
				
			||||||
 | 
							d_cpu = debugfs_create_dir(buf, d_fair);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							debugfs_create_file("runtime", 0644, d_cpu, (void *) cpu, &fair_server_runtime_fops);
 | 
				
			||||||
 | 
							debugfs_create_file("period", 0644, d_cpu, (void *) cpu, &fair_server_period_fops);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __init int sched_init_debug(void)
 | 
					static __init int sched_init_debug(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dentry __maybe_unused *numa;
 | 
						struct dentry __maybe_unused *numa;
 | 
				
			||||||
| 
						 | 
					@ -374,6 +531,8 @@ static __init int sched_init_debug(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	debugfs_create_file("debug", 0444, debugfs_sched, NULL, &sched_debug_fops);
 | 
						debugfs_create_file("debug", 0444, debugfs_sched, NULL, &sched_debug_fops);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						debugfs_fair_server_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
late_initcall(sched_init_debug);
 | 
					late_initcall(sched_init_debug);
 | 
				
			||||||
| 
						 | 
					@ -580,19 +739,19 @@ print_task(struct seq_file *m, struct rq *rq, struct task_struct *p)
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		SEQ_printf(m, " %c", task_state_to_char(p));
 | 
							SEQ_printf(m, " %c", task_state_to_char(p));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SEQ_printf(m, "%15s %5d %9Ld.%06ld %c %9Ld.%06ld %9Ld.%06ld %9Ld.%06ld %9Ld %5d ",
 | 
						SEQ_printf(m, " %15s %5d %9Ld.%06ld   %c   %9Ld.%06ld %c %9Ld.%06ld %9Ld.%06ld %9Ld   %5d ",
 | 
				
			||||||
		p->comm, task_pid_nr(p),
 | 
							p->comm, task_pid_nr(p),
 | 
				
			||||||
		SPLIT_NS(p->se.vruntime),
 | 
							SPLIT_NS(p->se.vruntime),
 | 
				
			||||||
		entity_eligible(cfs_rq_of(&p->se), &p->se) ? 'E' : 'N',
 | 
							entity_eligible(cfs_rq_of(&p->se), &p->se) ? 'E' : 'N',
 | 
				
			||||||
		SPLIT_NS(p->se.deadline),
 | 
							SPLIT_NS(p->se.deadline),
 | 
				
			||||||
 | 
							p->se.custom_slice ? 'S' : ' ',
 | 
				
			||||||
		SPLIT_NS(p->se.slice),
 | 
							SPLIT_NS(p->se.slice),
 | 
				
			||||||
		SPLIT_NS(p->se.sum_exec_runtime),
 | 
							SPLIT_NS(p->se.sum_exec_runtime),
 | 
				
			||||||
		(long long)(p->nvcsw + p->nivcsw),
 | 
							(long long)(p->nvcsw + p->nivcsw),
 | 
				
			||||||
		p->prio);
 | 
							p->prio);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SEQ_printf(m, "%9lld.%06ld %9lld.%06ld %9lld.%06ld %9lld.%06ld",
 | 
						SEQ_printf(m, "%9lld.%06ld %9lld.%06ld %9lld.%06ld",
 | 
				
			||||||
		SPLIT_NS(schedstat_val_or_zero(p->stats.wait_sum)),
 | 
							SPLIT_NS(schedstat_val_or_zero(p->stats.wait_sum)),
 | 
				
			||||||
		SPLIT_NS(p->se.sum_exec_runtime),
 | 
					 | 
				
			||||||
		SPLIT_NS(schedstat_val_or_zero(p->stats.sum_sleep_runtime)),
 | 
							SPLIT_NS(schedstat_val_or_zero(p->stats.sum_sleep_runtime)),
 | 
				
			||||||
		SPLIT_NS(schedstat_val_or_zero(p->stats.sum_block_runtime)));
 | 
							SPLIT_NS(schedstat_val_or_zero(p->stats.sum_block_runtime)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -612,10 +771,26 @@ static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SEQ_printf(m, "\n");
 | 
						SEQ_printf(m, "\n");
 | 
				
			||||||
	SEQ_printf(m, "runnable tasks:\n");
 | 
						SEQ_printf(m, "runnable tasks:\n");
 | 
				
			||||||
	SEQ_printf(m, " S            task   PID         tree-key  switches  prio"
 | 
						SEQ_printf(m, " S            task   PID       vruntime   eligible    "
 | 
				
			||||||
		   "     wait-time             sum-exec        sum-sleep\n");
 | 
							   "deadline             slice          sum-exec      switches  "
 | 
				
			||||||
 | 
							   "prio         wait-time        sum-sleep       sum-block"
 | 
				
			||||||
 | 
					#ifdef CONFIG_NUMA_BALANCING
 | 
				
			||||||
 | 
							   "  node   group-id"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CONFIG_CGROUP_SCHED
 | 
				
			||||||
 | 
							   "  group-path"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							   "\n");
 | 
				
			||||||
	SEQ_printf(m, "-------------------------------------------------------"
 | 
						SEQ_printf(m, "-------------------------------------------------------"
 | 
				
			||||||
		   "------------------------------------------------------\n");
 | 
							   "------------------------------------------------------"
 | 
				
			||||||
 | 
							   "------------------------------------------------------"
 | 
				
			||||||
 | 
					#ifdef CONFIG_NUMA_BALANCING
 | 
				
			||||||
 | 
							   "--------------"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifdef CONFIG_CGROUP_SCHED
 | 
				
			||||||
 | 
							   "--------------"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							   "\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_lock();
 | 
						rcu_read_lock();
 | 
				
			||||||
	for_each_process_thread(g, p) {
 | 
						for_each_process_thread(g, p) {
 | 
				
			||||||
| 
						 | 
					@ -641,8 +816,6 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
 | 
				
			||||||
	SEQ_printf(m, "\n");
 | 
						SEQ_printf(m, "\n");
 | 
				
			||||||
	SEQ_printf(m, "cfs_rq[%d]:\n", cpu);
 | 
						SEQ_printf(m, "cfs_rq[%d]:\n", cpu);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "exec_clock",
 | 
					 | 
				
			||||||
			SPLIT_NS(cfs_rq->exec_clock));
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	raw_spin_rq_lock_irqsave(rq, flags);
 | 
						raw_spin_rq_lock_irqsave(rq, flags);
 | 
				
			||||||
	root = __pick_root_entity(cfs_rq);
 | 
						root = __pick_root_entity(cfs_rq);
 | 
				
			||||||
| 
						 | 
					@ -669,8 +842,6 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)
 | 
				
			||||||
			SPLIT_NS(right_vruntime));
 | 
								SPLIT_NS(right_vruntime));
 | 
				
			||||||
	spread = right_vruntime - left_vruntime;
 | 
						spread = right_vruntime - left_vruntime;
 | 
				
			||||||
	SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "spread", SPLIT_NS(spread));
 | 
						SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", "spread", SPLIT_NS(spread));
 | 
				
			||||||
	SEQ_printf(m, "  .%-30s: %d\n", "nr_spread_over",
 | 
					 | 
				
			||||||
			cfs_rq->nr_spread_over);
 | 
					 | 
				
			||||||
	SEQ_printf(m, "  .%-30s: %d\n", "nr_running", cfs_rq->nr_running);
 | 
						SEQ_printf(m, "  .%-30s: %d\n", "nr_running", cfs_rq->nr_running);
 | 
				
			||||||
	SEQ_printf(m, "  .%-30s: %d\n", "h_nr_running", cfs_rq->h_nr_running);
 | 
						SEQ_printf(m, "  .%-30s: %d\n", "h_nr_running", cfs_rq->h_nr_running);
 | 
				
			||||||
	SEQ_printf(m, "  .%-30s: %d\n", "idle_nr_running",
 | 
						SEQ_printf(m, "  .%-30s: %d\n", "idle_nr_running",
 | 
				
			||||||
| 
						 | 
					@ -730,9 +901,12 @@ void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq)
 | 
				
			||||||
	SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", #x, SPLIT_NS(rt_rq->x))
 | 
						SEQ_printf(m, "  .%-30s: %Ld.%06ld\n", #x, SPLIT_NS(rt_rq->x))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	PU(rt_nr_running);
 | 
						PU(rt_nr_running);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_RT_GROUP_SCHED
 | 
				
			||||||
	P(rt_throttled);
 | 
						P(rt_throttled);
 | 
				
			||||||
	PN(rt_time);
 | 
						PN(rt_time);
 | 
				
			||||||
	PN(rt_runtime);
 | 
						PN(rt_runtime);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#undef PN
 | 
					#undef PN
 | 
				
			||||||
#undef PU
 | 
					#undef PU
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
					@ -5,8 +5,24 @@
 | 
				
			||||||
 * sleep+wake cycles. EEVDF placement strategy #1, #2 if disabled.
 | 
					 * sleep+wake cycles. EEVDF placement strategy #1, #2 if disabled.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
SCHED_FEAT(PLACE_LAG, true)
 | 
					SCHED_FEAT(PLACE_LAG, true)
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Give new tasks half a slice to ease into the competition.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
SCHED_FEAT(PLACE_DEADLINE_INITIAL, true)
 | 
					SCHED_FEAT(PLACE_DEADLINE_INITIAL, true)
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Preserve relative virtual deadline on 'migration'.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SCHED_FEAT(PLACE_REL_DEADLINE, true)
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Inhibit (wakeup) preemption until the current task has either matched the
 | 
				
			||||||
 | 
					 * 0-lag point or until is has exhausted it's slice.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
SCHED_FEAT(RUN_TO_PARITY, true)
 | 
					SCHED_FEAT(RUN_TO_PARITY, true)
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Allow wakeup of tasks with a shorter slice to cancel RESPECT_SLICE for
 | 
				
			||||||
 | 
					 * current.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SCHED_FEAT(PREEMPT_SHORT, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Prefer to schedule the task we woke last (assuming it failed
 | 
					 * Prefer to schedule the task we woke last (assuming it failed
 | 
				
			||||||
| 
						 | 
					@ -21,6 +37,18 @@ SCHED_FEAT(NEXT_BUDDY, false)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
SCHED_FEAT(CACHE_HOT_BUDDY, true)
 | 
					SCHED_FEAT(CACHE_HOT_BUDDY, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Delay dequeueing tasks until they get selected or woken.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * By delaying the dequeue for non-eligible tasks, they remain in the
 | 
				
			||||||
 | 
					 * competition and can burn off their negative lag. When they get selected
 | 
				
			||||||
 | 
					 * they'll have positive lag by definition.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * DELAY_ZERO clips the lag on dequeue (or wakeup) to 0.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					SCHED_FEAT(DELAY_DEQUEUE, true)
 | 
				
			||||||
 | 
					SCHED_FEAT(DELAY_ZERO, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Allow wakeup-time preemption of the current task:
 | 
					 * Allow wakeup-time preemption of the current task:
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -85,5 +113,3 @@ SCHED_FEAT(WA_BIAS, true)
 | 
				
			||||||
SCHED_FEAT(UTIL_EST, true)
 | 
					SCHED_FEAT(UTIL_EST, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SCHED_FEAT(LATENCY_WARN, false)
 | 
					SCHED_FEAT(LATENCY_WARN, false)
 | 
				
			||||||
 | 
					 | 
				
			||||||
SCHED_FEAT(HZ_BW, true)
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -450,43 +450,35 @@ static void wakeup_preempt_idle(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
	resched_curr(rq);
 | 
						resched_curr(rq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void put_prev_task_idle(struct rq *rq, struct task_struct *prev)
 | 
					static void put_prev_task_idle(struct rq *rq, struct task_struct *prev, struct task_struct *next)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						dl_server_update_idle_time(rq, prev);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void set_next_task_idle(struct rq *rq, struct task_struct *next, bool first)
 | 
					static void set_next_task_idle(struct rq *rq, struct task_struct *next, bool first)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	update_idle_core(rq);
 | 
						update_idle_core(rq);
 | 
				
			||||||
	schedstat_inc(rq->sched_goidle);
 | 
						schedstat_inc(rq->sched_goidle);
 | 
				
			||||||
 | 
						next->se.exec_start = rq_clock_task(rq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					struct task_struct *pick_task_idle(struct rq *rq)
 | 
				
			||||||
static struct task_struct *pick_task_idle(struct rq *rq)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return rq->idle;
 | 
						return rq->idle;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct task_struct *pick_next_task_idle(struct rq *rq)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct task_struct *next = rq->idle;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	set_next_task_idle(rq, next, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return next;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * It is not legal to sleep in the idle task - print a warning
 | 
					 * It is not legal to sleep in the idle task - print a warning
 | 
				
			||||||
 * message if some code attempts to do it:
 | 
					 * message if some code attempts to do it:
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void
 | 
					static bool
 | 
				
			||||||
dequeue_task_idle(struct rq *rq, struct task_struct *p, int flags)
 | 
					dequeue_task_idle(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	raw_spin_rq_unlock_irq(rq);
 | 
						raw_spin_rq_unlock_irq(rq);
 | 
				
			||||||
	printk(KERN_ERR "bad: scheduling from the idle thread!\n");
 | 
						printk(KERN_ERR "bad: scheduling from the idle thread!\n");
 | 
				
			||||||
	dump_stack();
 | 
						dump_stack();
 | 
				
			||||||
	raw_spin_rq_lock_irq(rq);
 | 
						raw_spin_rq_lock_irq(rq);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -528,13 +520,12 @@ DEFINE_SCHED_CLASS(idle) = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.wakeup_preempt		= wakeup_preempt_idle,
 | 
						.wakeup_preempt		= wakeup_preempt_idle,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.pick_next_task		= pick_next_task_idle,
 | 
						.pick_task		= pick_task_idle,
 | 
				
			||||||
	.put_prev_task		= put_prev_task_idle,
 | 
						.put_prev_task		= put_prev_task_idle,
 | 
				
			||||||
	.set_next_task          = set_next_task_idle,
 | 
						.set_next_task          = set_next_task_idle,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
	.balance		= balance_idle,
 | 
						.balance		= balance_idle,
 | 
				
			||||||
	.pick_task		= pick_task_idle,
 | 
					 | 
				
			||||||
	.select_task_rq		= select_task_rq_idle,
 | 
						.select_task_rq		= select_task_rq_idle,
 | 
				
			||||||
	.set_cpus_allowed	= set_cpus_allowed_common,
 | 
						.set_cpus_allowed	= set_cpus_allowed_common,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,10 +8,6 @@ int sched_rr_timeslice = RR_TIMESLICE;
 | 
				
			||||||
/* More than 4 hours if BW_SHIFT equals 20. */
 | 
					/* More than 4 hours if BW_SHIFT equals 20. */
 | 
				
			||||||
static const u64 max_rt_runtime = MAX_BW;
 | 
					static const u64 max_rt_runtime = MAX_BW;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct rt_bandwidth def_rt_bandwidth;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * period over which we measure -rt task CPU usage in us.
 | 
					 * period over which we measure -rt task CPU usage in us.
 | 
				
			||||||
 * default: 1s
 | 
					 * default: 1s
 | 
				
			||||||
| 
						 | 
					@ -66,6 +62,40 @@ static int __init sched_rt_sysctl_init(void)
 | 
				
			||||||
late_initcall(sched_rt_sysctl_init);
 | 
					late_initcall(sched_rt_sysctl_init);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void init_rt_rq(struct rt_rq *rt_rq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rt_prio_array *array;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						array = &rt_rq->active;
 | 
				
			||||||
 | 
						for (i = 0; i < MAX_RT_PRIO; i++) {
 | 
				
			||||||
 | 
							INIT_LIST_HEAD(array->queue + i);
 | 
				
			||||||
 | 
							__clear_bit(i, array->bitmap);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						/* delimiter for bitsearch: */
 | 
				
			||||||
 | 
						__set_bit(MAX_RT_PRIO, array->bitmap);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined CONFIG_SMP
 | 
				
			||||||
 | 
						rt_rq->highest_prio.curr = MAX_RT_PRIO-1;
 | 
				
			||||||
 | 
						rt_rq->highest_prio.next = MAX_RT_PRIO-1;
 | 
				
			||||||
 | 
						rt_rq->overloaded = 0;
 | 
				
			||||||
 | 
						plist_head_init(&rt_rq->pushable_tasks);
 | 
				
			||||||
 | 
					#endif /* CONFIG_SMP */
 | 
				
			||||||
 | 
						/* We start is dequeued state, because no RT tasks are queued */
 | 
				
			||||||
 | 
						rt_rq->rt_queued = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_RT_GROUP_SCHED
 | 
				
			||||||
 | 
						rt_rq->rt_time = 0;
 | 
				
			||||||
 | 
						rt_rq->rt_throttled = 0;
 | 
				
			||||||
 | 
						rt_rq->rt_runtime = 0;
 | 
				
			||||||
 | 
						raw_spin_lock_init(&rt_rq->rt_runtime_lock);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_RT_GROUP_SCHED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static enum hrtimer_restart sched_rt_period_timer(struct hrtimer *timer)
 | 
					static enum hrtimer_restart sched_rt_period_timer(struct hrtimer *timer)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rt_bandwidth *rt_b =
 | 
						struct rt_bandwidth *rt_b =
 | 
				
			||||||
| 
						 | 
					@ -130,35 +160,6 @@ static void start_rt_bandwidth(struct rt_bandwidth *rt_b)
 | 
				
			||||||
	do_start_rt_bandwidth(rt_b);
 | 
						do_start_rt_bandwidth(rt_b);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void init_rt_rq(struct rt_rq *rt_rq)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct rt_prio_array *array;
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	array = &rt_rq->active;
 | 
					 | 
				
			||||||
	for (i = 0; i < MAX_RT_PRIO; i++) {
 | 
					 | 
				
			||||||
		INIT_LIST_HEAD(array->queue + i);
 | 
					 | 
				
			||||||
		__clear_bit(i, array->bitmap);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	/* delimiter for bit-search: */
 | 
					 | 
				
			||||||
	__set_bit(MAX_RT_PRIO, array->bitmap);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined CONFIG_SMP
 | 
					 | 
				
			||||||
	rt_rq->highest_prio.curr = MAX_RT_PRIO-1;
 | 
					 | 
				
			||||||
	rt_rq->highest_prio.next = MAX_RT_PRIO-1;
 | 
					 | 
				
			||||||
	rt_rq->overloaded = 0;
 | 
					 | 
				
			||||||
	plist_head_init(&rt_rq->pushable_tasks);
 | 
					 | 
				
			||||||
#endif /* CONFIG_SMP */
 | 
					 | 
				
			||||||
	/* We start is dequeued state, because no RT tasks are queued */
 | 
					 | 
				
			||||||
	rt_rq->rt_queued = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	rt_rq->rt_time = 0;
 | 
					 | 
				
			||||||
	rt_rq->rt_throttled = 0;
 | 
					 | 
				
			||||||
	rt_rq->rt_runtime = 0;
 | 
					 | 
				
			||||||
	raw_spin_lock_init(&rt_rq->rt_runtime_lock);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_RT_GROUP_SCHED
 | 
					 | 
				
			||||||
static void destroy_rt_bandwidth(struct rt_bandwidth *rt_b)
 | 
					static void destroy_rt_bandwidth(struct rt_bandwidth *rt_b)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	hrtimer_cancel(&rt_b->rt_period_timer);
 | 
						hrtimer_cancel(&rt_b->rt_period_timer);
 | 
				
			||||||
| 
						 | 
					@ -195,7 +196,6 @@ void unregister_rt_sched_group(struct task_group *tg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (tg->rt_se)
 | 
						if (tg->rt_se)
 | 
				
			||||||
		destroy_rt_bandwidth(&tg->rt_bandwidth);
 | 
							destroy_rt_bandwidth(&tg->rt_bandwidth);
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void free_rt_sched_group(struct task_group *tg)
 | 
					void free_rt_sched_group(struct task_group *tg)
 | 
				
			||||||
| 
						 | 
					@ -253,8 +253,7 @@ int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent)
 | 
				
			||||||
	if (!tg->rt_se)
 | 
						if (!tg->rt_se)
 | 
				
			||||||
		goto err;
 | 
							goto err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	init_rt_bandwidth(&tg->rt_bandwidth,
 | 
						init_rt_bandwidth(&tg->rt_bandwidth, ktime_to_ns(global_rt_period()), 0);
 | 
				
			||||||
			ktime_to_ns(def_rt_bandwidth.rt_period), 0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for_each_possible_cpu(i) {
 | 
						for_each_possible_cpu(i) {
 | 
				
			||||||
		rt_rq = kzalloc_node(sizeof(struct rt_rq),
 | 
							rt_rq = kzalloc_node(sizeof(struct rt_rq),
 | 
				
			||||||
| 
						 | 
					@ -604,70 +603,6 @@ static inline struct rt_bandwidth *sched_rt_bandwidth(struct rt_rq *rt_rq)
 | 
				
			||||||
	return &rt_rq->tg->rt_bandwidth;
 | 
						return &rt_rq->tg->rt_bandwidth;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#else /* !CONFIG_RT_GROUP_SCHED */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline u64 sched_rt_runtime(struct rt_rq *rt_rq)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return rt_rq->rt_runtime;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline u64 sched_rt_period(struct rt_rq *rt_rq)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return ktime_to_ns(def_rt_bandwidth.rt_period);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typedef struct rt_rq *rt_rq_iter_t;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define for_each_rt_rq(rt_rq, iter, rq) \
 | 
					 | 
				
			||||||
	for ((void) iter, rt_rq = &rq->rt; rt_rq; rt_rq = NULL)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define for_each_sched_rt_entity(rt_se) \
 | 
					 | 
				
			||||||
	for (; rt_se; rt_se = NULL)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void sched_rt_rq_enqueue(struct rt_rq *rt_rq)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct rq *rq = rq_of_rt_rq(rt_rq);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!rt_rq->rt_nr_running)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	enqueue_top_rt_rq(rt_rq);
 | 
					 | 
				
			||||||
	resched_curr(rq);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline void sched_rt_rq_dequeue(struct rt_rq *rt_rq)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	dequeue_top_rt_rq(rt_rq, rt_rq->rt_nr_running);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline int rt_rq_throttled(struct rt_rq *rt_rq)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return rt_rq->rt_throttled;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline const struct cpumask *sched_rt_period_mask(void)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return cpu_online_mask;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline
 | 
					 | 
				
			||||||
struct rt_rq *sched_rt_period_rt_rq(struct rt_bandwidth *rt_b, int cpu)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return &cpu_rq(cpu)->rt;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static inline struct rt_bandwidth *sched_rt_bandwidth(struct rt_rq *rt_rq)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return &def_rt_bandwidth;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif /* CONFIG_RT_GROUP_SCHED */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool sched_rt_bandwidth_account(struct rt_rq *rt_rq)
 | 
					bool sched_rt_bandwidth_account(struct rt_rq *rt_rq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);
 | 
						struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq);
 | 
				
			||||||
| 
						 | 
					@ -859,7 +794,7 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun)
 | 
				
			||||||
	const struct cpumask *span;
 | 
						const struct cpumask *span;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	span = sched_rt_period_mask();
 | 
						span = sched_rt_period_mask();
 | 
				
			||||||
#ifdef CONFIG_RT_GROUP_SCHED
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * FIXME: isolated CPUs should really leave the root task group,
 | 
						 * FIXME: isolated CPUs should really leave the root task group,
 | 
				
			||||||
	 * whether they are isolcpus or were isolated via cpusets, lest
 | 
						 * whether they are isolcpus or were isolated via cpusets, lest
 | 
				
			||||||
| 
						 | 
					@ -871,7 +806,7 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun)
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (rt_b == &root_task_group.rt_bandwidth)
 | 
						if (rt_b == &root_task_group.rt_bandwidth)
 | 
				
			||||||
		span = cpu_online_mask;
 | 
							span = cpu_online_mask;
 | 
				
			||||||
#endif
 | 
					
 | 
				
			||||||
	for_each_cpu(i, span) {
 | 
						for_each_cpu(i, span) {
 | 
				
			||||||
		int enqueue = 0;
 | 
							int enqueue = 0;
 | 
				
			||||||
		struct rt_rq *rt_rq = sched_rt_period_rt_rq(rt_b, i);
 | 
							struct rt_rq *rt_rq = sched_rt_period_rt_rq(rt_b, i);
 | 
				
			||||||
| 
						 | 
					@ -938,18 +873,6 @@ static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun)
 | 
				
			||||||
	return idle;
 | 
						return idle;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int rt_se_prio(struct sched_rt_entity *rt_se)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
#ifdef CONFIG_RT_GROUP_SCHED
 | 
					 | 
				
			||||||
	struct rt_rq *rt_rq = group_rt_rq(rt_se);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (rt_rq)
 | 
					 | 
				
			||||||
		return rt_rq->highest_prio.curr;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return rt_task_of(rt_se)->prio;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int sched_rt_runtime_exceeded(struct rt_rq *rt_rq)
 | 
					static int sched_rt_runtime_exceeded(struct rt_rq *rt_rq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u64 runtime = sched_rt_runtime(rt_rq);
 | 
						u64 runtime = sched_rt_runtime(rt_rq);
 | 
				
			||||||
| 
						 | 
					@ -993,6 +916,72 @@ static int sched_rt_runtime_exceeded(struct rt_rq *rt_rq)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#else /* !CONFIG_RT_GROUP_SCHED */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct rt_rq *rt_rq_iter_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define for_each_rt_rq(rt_rq, iter, rq) \
 | 
				
			||||||
 | 
						for ((void) iter, rt_rq = &rq->rt; rt_rq; rt_rq = NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define for_each_sched_rt_entity(rt_se) \
 | 
				
			||||||
 | 
						for (; rt_se; rt_se = NULL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void sched_rt_rq_enqueue(struct rt_rq *rt_rq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct rq *rq = rq_of_rt_rq(rt_rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!rt_rq->rt_nr_running)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						enqueue_top_rt_rq(rt_rq);
 | 
				
			||||||
 | 
						resched_curr(rq);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void sched_rt_rq_dequeue(struct rt_rq *rt_rq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						dequeue_top_rt_rq(rt_rq, rt_rq->rt_nr_running);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int rt_rq_throttled(struct rt_rq *rt_rq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return false;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline const struct cpumask *sched_rt_period_mask(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return cpu_online_mask;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline
 | 
				
			||||||
 | 
					struct rt_rq *sched_rt_period_rt_rq(struct rt_bandwidth *rt_b, int cpu)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return &cpu_rq(cpu)->rt;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
 | 
					static void __enable_runtime(struct rq *rq) { }
 | 
				
			||||||
 | 
					static void __disable_runtime(struct rq *rq) { }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* CONFIG_RT_GROUP_SCHED */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline int rt_se_prio(struct sched_rt_entity *rt_se)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					#ifdef CONFIG_RT_GROUP_SCHED
 | 
				
			||||||
 | 
						struct rt_rq *rt_rq = group_rt_rq(rt_se);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (rt_rq)
 | 
				
			||||||
 | 
							return rt_rq->highest_prio.curr;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return rt_task_of(rt_se)->prio;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Update the current task's runtime statistics. Skip current tasks that
 | 
					 * Update the current task's runtime statistics. Skip current tasks that
 | 
				
			||||||
 * are not in our scheduling class.
 | 
					 * are not in our scheduling class.
 | 
				
			||||||
| 
						 | 
					@ -1000,7 +989,6 @@ static int sched_rt_runtime_exceeded(struct rt_rq *rt_rq)
 | 
				
			||||||
static void update_curr_rt(struct rq *rq)
 | 
					static void update_curr_rt(struct rq *rq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct task_struct *curr = rq->curr;
 | 
						struct task_struct *curr = rq->curr;
 | 
				
			||||||
	struct sched_rt_entity *rt_se = &curr->rt;
 | 
					 | 
				
			||||||
	s64 delta_exec;
 | 
						s64 delta_exec;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (curr->sched_class != &rt_sched_class)
 | 
						if (curr->sched_class != &rt_sched_class)
 | 
				
			||||||
| 
						 | 
					@ -1010,6 +998,9 @@ static void update_curr_rt(struct rq *rq)
 | 
				
			||||||
	if (unlikely(delta_exec <= 0))
 | 
						if (unlikely(delta_exec <= 0))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_RT_GROUP_SCHED
 | 
				
			||||||
 | 
						struct sched_rt_entity *rt_se = &curr->rt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!rt_bandwidth_enabled())
 | 
						if (!rt_bandwidth_enabled())
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1028,6 +1019,7 @@ static void update_curr_rt(struct rq *rq)
 | 
				
			||||||
				do_start_rt_bandwidth(sched_rt_bandwidth(rt_rq));
 | 
									do_start_rt_bandwidth(sched_rt_bandwidth(rt_rq));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -1184,7 +1176,6 @@ dec_rt_group(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
inc_rt_group(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
 | 
					inc_rt_group(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	start_rt_bandwidth(&def_rt_bandwidth);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline
 | 
					static inline
 | 
				
			||||||
| 
						 | 
					@ -1492,7 +1483,7 @@ enqueue_task_rt(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
		enqueue_pushable_task(rq, p);
 | 
							enqueue_pushable_task(rq, p);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags)
 | 
					static bool dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sched_rt_entity *rt_se = &p->rt;
 | 
						struct sched_rt_entity *rt_se = &p->rt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1500,6 +1491,8 @@ static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
	dequeue_rt_entity(rt_se, flags);
 | 
						dequeue_rt_entity(rt_se, flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dequeue_pushable_task(rq, p);
 | 
						dequeue_pushable_task(rq, p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -1755,17 +1748,7 @@ static struct task_struct *pick_task_rt(struct rq *rq)
 | 
				
			||||||
	return p;
 | 
						return p;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct task_struct *pick_next_task_rt(struct rq *rq)
 | 
					static void put_prev_task_rt(struct rq *rq, struct task_struct *p, struct task_struct *next)
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct task_struct *p = pick_task_rt(rq);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (p)
 | 
					 | 
				
			||||||
		set_next_task_rt(rq, p, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return p;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void put_prev_task_rt(struct rq *rq, struct task_struct *p)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct sched_rt_entity *rt_se = &p->rt;
 | 
						struct sched_rt_entity *rt_se = &p->rt;
 | 
				
			||||||
	struct rt_rq *rt_rq = &rq->rt;
 | 
						struct rt_rq *rt_rq = &rq->rt;
 | 
				
			||||||
| 
						 | 
					@ -2652,13 +2635,12 @@ DEFINE_SCHED_CLASS(rt) = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.wakeup_preempt		= wakeup_preempt_rt,
 | 
						.wakeup_preempt		= wakeup_preempt_rt,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.pick_next_task		= pick_next_task_rt,
 | 
						.pick_task		= pick_task_rt,
 | 
				
			||||||
	.put_prev_task		= put_prev_task_rt,
 | 
						.put_prev_task		= put_prev_task_rt,
 | 
				
			||||||
	.set_next_task          = set_next_task_rt,
 | 
						.set_next_task          = set_next_task_rt,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
	.balance		= balance_rt,
 | 
						.balance		= balance_rt,
 | 
				
			||||||
	.pick_task		= pick_task_rt,
 | 
					 | 
				
			||||||
	.select_task_rq		= select_task_rq_rt,
 | 
						.select_task_rq		= select_task_rq_rt,
 | 
				
			||||||
	.set_cpus_allowed       = set_cpus_allowed_common,
 | 
						.set_cpus_allowed       = set_cpus_allowed_common,
 | 
				
			||||||
	.rq_online              = rq_online_rt,
 | 
						.rq_online              = rq_online_rt,
 | 
				
			||||||
| 
						 | 
					@ -2912,19 +2894,6 @@ int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk)
 | 
				
			||||||
#ifdef CONFIG_SYSCTL
 | 
					#ifdef CONFIG_SYSCTL
 | 
				
			||||||
static int sched_rt_global_constraints(void)
 | 
					static int sched_rt_global_constraints(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long flags;
 | 
					 | 
				
			||||||
	int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	raw_spin_lock_irqsave(&def_rt_bandwidth.rt_runtime_lock, flags);
 | 
					 | 
				
			||||||
	for_each_possible_cpu(i) {
 | 
					 | 
				
			||||||
		struct rt_rq *rt_rq = &cpu_rq(i)->rt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		raw_spin_lock(&rt_rq->rt_runtime_lock);
 | 
					 | 
				
			||||||
		rt_rq->rt_runtime = global_rt_runtime();
 | 
					 | 
				
			||||||
		raw_spin_unlock(&rt_rq->rt_runtime_lock);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	raw_spin_unlock_irqrestore(&def_rt_bandwidth.rt_runtime_lock, flags);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif /* CONFIG_SYSCTL */
 | 
					#endif /* CONFIG_SYSCTL */
 | 
				
			||||||
| 
						 | 
					@ -2944,12 +2913,6 @@ static int sched_rt_global_validate(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void sched_rt_do_global(void)
 | 
					static void sched_rt_do_global(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	unsigned long flags;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	raw_spin_lock_irqsave(&def_rt_bandwidth.rt_runtime_lock, flags);
 | 
					 | 
				
			||||||
	def_rt_bandwidth.rt_runtime = global_rt_runtime();
 | 
					 | 
				
			||||||
	def_rt_bandwidth.rt_period = ns_to_ktime(global_rt_period());
 | 
					 | 
				
			||||||
	raw_spin_unlock_irqrestore(&def_rt_bandwidth.rt_runtime_lock, flags);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int sched_rt_handler(const struct ctl_table *table, int write, void *buffer,
 | 
					static int sched_rt_handler(const struct ctl_table *table, int write, void *buffer,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,6 +68,7 @@
 | 
				
			||||||
#include <linux/wait_api.h>
 | 
					#include <linux/wait_api.h>
 | 
				
			||||||
#include <linux/wait_bit.h>
 | 
					#include <linux/wait_bit.h>
 | 
				
			||||||
#include <linux/workqueue_api.h>
 | 
					#include <linux/workqueue_api.h>
 | 
				
			||||||
 | 
					#include <linux/delayacct.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <trace/events/power.h>
 | 
					#include <trace/events/power.h>
 | 
				
			||||||
#include <trace/events/sched.h>
 | 
					#include <trace/events/sched.h>
 | 
				
			||||||
| 
						 | 
					@ -335,7 +336,7 @@ extern bool __checkparam_dl(const struct sched_attr *attr);
 | 
				
			||||||
extern bool dl_param_changed(struct task_struct *p, const struct sched_attr *attr);
 | 
					extern bool dl_param_changed(struct task_struct *p, const struct sched_attr *attr);
 | 
				
			||||||
extern int  dl_cpuset_cpumask_can_shrink(const struct cpumask *cur, const struct cpumask *trial);
 | 
					extern int  dl_cpuset_cpumask_can_shrink(const struct cpumask *cur, const struct cpumask *trial);
 | 
				
			||||||
extern int  dl_bw_check_overflow(int cpu);
 | 
					extern int  dl_bw_check_overflow(int cpu);
 | 
				
			||||||
 | 
					extern s64 dl_scaled_delta_exec(struct rq *rq, struct sched_dl_entity *dl_se, s64 delta_exec);
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * SCHED_DEADLINE supports servers (nested scheduling) with the following
 | 
					 * SCHED_DEADLINE supports servers (nested scheduling) with the following
 | 
				
			||||||
 * interface:
 | 
					 * interface:
 | 
				
			||||||
| 
						 | 
					@ -361,7 +362,14 @@ extern void dl_server_start(struct sched_dl_entity *dl_se);
 | 
				
			||||||
extern void dl_server_stop(struct sched_dl_entity *dl_se);
 | 
					extern void dl_server_stop(struct sched_dl_entity *dl_se);
 | 
				
			||||||
extern void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,
 | 
					extern void dl_server_init(struct sched_dl_entity *dl_se, struct rq *rq,
 | 
				
			||||||
		    dl_server_has_tasks_f has_tasks,
 | 
							    dl_server_has_tasks_f has_tasks,
 | 
				
			||||||
		    dl_server_pick_f pick);
 | 
							    dl_server_pick_f pick_task);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void dl_server_update_idle_time(struct rq *rq,
 | 
				
			||||||
 | 
							    struct task_struct *p);
 | 
				
			||||||
 | 
					extern void fair_server_init(struct rq *rq);
 | 
				
			||||||
 | 
					extern void __dl_server_attach_root(struct sched_dl_entity *dl_se, struct rq *rq);
 | 
				
			||||||
 | 
					extern int dl_server_apply_params(struct sched_dl_entity *dl_se,
 | 
				
			||||||
 | 
							    u64 runtime, u64 period, bool init);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_CGROUP_SCHED
 | 
					#ifdef CONFIG_CGROUP_SCHED
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -599,17 +607,12 @@ struct cfs_rq {
 | 
				
			||||||
	s64			avg_vruntime;
 | 
						s64			avg_vruntime;
 | 
				
			||||||
	u64			avg_load;
 | 
						u64			avg_load;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	u64			exec_clock;
 | 
					 | 
				
			||||||
	u64			min_vruntime;
 | 
						u64			min_vruntime;
 | 
				
			||||||
#ifdef CONFIG_SCHED_CORE
 | 
					#ifdef CONFIG_SCHED_CORE
 | 
				
			||||||
	unsigned int		forceidle_seq;
 | 
						unsigned int		forceidle_seq;
 | 
				
			||||||
	u64			min_vruntime_fi;
 | 
						u64			min_vruntime_fi;
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef CONFIG_64BIT
 | 
					 | 
				
			||||||
	u64			min_vruntime_copy;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct rb_root_cached	tasks_timeline;
 | 
						struct rb_root_cached	tasks_timeline;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -619,10 +622,6 @@ struct cfs_rq {
 | 
				
			||||||
	struct sched_entity	*curr;
 | 
						struct sched_entity	*curr;
 | 
				
			||||||
	struct sched_entity	*next;
 | 
						struct sched_entity	*next;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef	CONFIG_SCHED_DEBUG
 | 
					 | 
				
			||||||
	unsigned int		nr_spread_over;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * CFS load tracking
 | 
						 * CFS load tracking
 | 
				
			||||||
| 
						 | 
					@ -726,13 +725,13 @@ struct rt_rq {
 | 
				
			||||||
#endif /* CONFIG_SMP */
 | 
					#endif /* CONFIG_SMP */
 | 
				
			||||||
	int			rt_queued;
 | 
						int			rt_queued;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_RT_GROUP_SCHED
 | 
				
			||||||
	int			rt_throttled;
 | 
						int			rt_throttled;
 | 
				
			||||||
	u64			rt_time;
 | 
						u64			rt_time;
 | 
				
			||||||
	u64			rt_runtime;
 | 
						u64			rt_runtime;
 | 
				
			||||||
	/* Nests inside the rq lock: */
 | 
						/* Nests inside the rq lock: */
 | 
				
			||||||
	raw_spinlock_t		rt_runtime_lock;
 | 
						raw_spinlock_t		rt_runtime_lock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_RT_GROUP_SCHED
 | 
					 | 
				
			||||||
	unsigned int		rt_nr_boosted;
 | 
						unsigned int		rt_nr_boosted;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct rq		*rq;
 | 
						struct rq		*rq;
 | 
				
			||||||
| 
						 | 
					@ -820,6 +819,9 @@ static inline void se_update_runnable(struct sched_entity *se)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline long se_runnable(struct sched_entity *se)
 | 
					static inline long se_runnable(struct sched_entity *se)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if (se->sched_delayed)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (entity_is_task(se))
 | 
						if (entity_is_task(se))
 | 
				
			||||||
		return !!se->on_rq;
 | 
							return !!se->on_rq;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
| 
						 | 
					@ -834,6 +836,9 @@ static inline void se_update_runnable(struct sched_entity *se) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline long se_runnable(struct sched_entity *se)
 | 
					static inline long se_runnable(struct sched_entity *se)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if (se->sched_delayed)
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return !!se->on_rq;
 | 
						return !!se->on_rq;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1044,6 +1049,8 @@ struct rq {
 | 
				
			||||||
	struct rt_rq		rt;
 | 
						struct rt_rq		rt;
 | 
				
			||||||
	struct dl_rq		dl;
 | 
						struct dl_rq		dl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct sched_dl_entity	fair_server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_FAIR_GROUP_SCHED
 | 
					#ifdef CONFIG_FAIR_GROUP_SCHED
 | 
				
			||||||
	/* list of leaf cfs_rq on this CPU: */
 | 
						/* list of leaf cfs_rq on this CPU: */
 | 
				
			||||||
	struct list_head	leaf_cfs_rq_list;
 | 
						struct list_head	leaf_cfs_rq_list;
 | 
				
			||||||
| 
						 | 
					@ -1059,6 +1066,7 @@ struct rq {
 | 
				
			||||||
	unsigned int		nr_uninterruptible;
 | 
						unsigned int		nr_uninterruptible;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct task_struct __rcu	*curr;
 | 
						struct task_struct __rcu	*curr;
 | 
				
			||||||
 | 
						struct sched_dl_entity	*dl_server;
 | 
				
			||||||
	struct task_struct	*idle;
 | 
						struct task_struct	*idle;
 | 
				
			||||||
	struct task_struct	*stop;
 | 
						struct task_struct	*stop;
 | 
				
			||||||
	unsigned long		next_balance;
 | 
						unsigned long		next_balance;
 | 
				
			||||||
| 
						 | 
					@ -1158,7 +1166,6 @@ struct rq {
 | 
				
			||||||
	/* latency stats */
 | 
						/* latency stats */
 | 
				
			||||||
	struct sched_info	rq_sched_info;
 | 
						struct sched_info	rq_sched_info;
 | 
				
			||||||
	unsigned long long	rq_cpu_time;
 | 
						unsigned long long	rq_cpu_time;
 | 
				
			||||||
	/* could above be rq->cfs_rq.exec_clock + rq->rt_rq.rt_runtime ? */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* sys_sched_yield() stats */
 | 
						/* sys_sched_yield() stats */
 | 
				
			||||||
	unsigned int		yld_count;
 | 
						unsigned int		yld_count;
 | 
				
			||||||
| 
						 | 
					@ -1187,6 +1194,7 @@ struct rq {
 | 
				
			||||||
	/* per rq */
 | 
						/* per rq */
 | 
				
			||||||
	struct rq		*core;
 | 
						struct rq		*core;
 | 
				
			||||||
	struct task_struct	*core_pick;
 | 
						struct task_struct	*core_pick;
 | 
				
			||||||
 | 
						struct sched_dl_entity	*core_dl_server;
 | 
				
			||||||
	unsigned int		core_enabled;
 | 
						unsigned int		core_enabled;
 | 
				
			||||||
	unsigned int		core_sched_seq;
 | 
						unsigned int		core_sched_seq;
 | 
				
			||||||
	struct rb_root		core_tree;
 | 
						struct rb_root		core_tree;
 | 
				
			||||||
| 
						 | 
					@ -2247,11 +2255,13 @@ extern const u32		sched_prio_to_wmult[40];
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DEQUEUE_SLEEP		0x01
 | 
					#define DEQUEUE_SLEEP		0x01 /* Matches ENQUEUE_WAKEUP */
 | 
				
			||||||
#define DEQUEUE_SAVE		0x02 /* Matches ENQUEUE_RESTORE */
 | 
					#define DEQUEUE_SAVE		0x02 /* Matches ENQUEUE_RESTORE */
 | 
				
			||||||
#define DEQUEUE_MOVE		0x04 /* Matches ENQUEUE_MOVE */
 | 
					#define DEQUEUE_MOVE		0x04 /* Matches ENQUEUE_MOVE */
 | 
				
			||||||
#define DEQUEUE_NOCLOCK		0x08 /* Matches ENQUEUE_NOCLOCK */
 | 
					#define DEQUEUE_NOCLOCK		0x08 /* Matches ENQUEUE_NOCLOCK */
 | 
				
			||||||
 | 
					#define DEQUEUE_SPECIAL		0x10
 | 
				
			||||||
#define DEQUEUE_MIGRATING	0x100 /* Matches ENQUEUE_MIGRATING */
 | 
					#define DEQUEUE_MIGRATING	0x100 /* Matches ENQUEUE_MIGRATING */
 | 
				
			||||||
 | 
					#define DEQUEUE_DELAYED		0x200 /* Matches ENQUEUE_DELAYED */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ENQUEUE_WAKEUP		0x01
 | 
					#define ENQUEUE_WAKEUP		0x01
 | 
				
			||||||
#define ENQUEUE_RESTORE		0x02
 | 
					#define ENQUEUE_RESTORE		0x02
 | 
				
			||||||
| 
						 | 
					@ -2267,6 +2277,7 @@ extern const u32		sched_prio_to_wmult[40];
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
#define ENQUEUE_INITIAL		0x80
 | 
					#define ENQUEUE_INITIAL		0x80
 | 
				
			||||||
#define ENQUEUE_MIGRATING	0x100
 | 
					#define ENQUEUE_MIGRATING	0x100
 | 
				
			||||||
 | 
					#define ENQUEUE_DELAYED		0x200
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define RETRY_TASK		((void *)-1UL)
 | 
					#define RETRY_TASK		((void *)-1UL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2285,23 +2296,31 @@ struct sched_class {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);
 | 
						void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags);
 | 
				
			||||||
	void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);
 | 
						bool (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags);
 | 
				
			||||||
	void (*yield_task)   (struct rq *rq);
 | 
						void (*yield_task)   (struct rq *rq);
 | 
				
			||||||
	bool (*yield_to_task)(struct rq *rq, struct task_struct *p);
 | 
						bool (*yield_to_task)(struct rq *rq, struct task_struct *p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void (*wakeup_preempt)(struct rq *rq, struct task_struct *p, int flags);
 | 
						void (*wakeup_preempt)(struct rq *rq, struct task_struct *p, int flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct task_struct *(*pick_next_task)(struct rq *rq);
 | 
						struct task_struct *(*pick_task)(struct rq *rq);
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Optional! When implemented pick_next_task() should be equivalent to:
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 *   next = pick_task();
 | 
				
			||||||
 | 
						 *   if (next) {
 | 
				
			||||||
 | 
						 *       put_prev_task(prev);
 | 
				
			||||||
 | 
						 *       set_next_task_first(next);
 | 
				
			||||||
 | 
						 *   }
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						struct task_struct *(*pick_next_task)(struct rq *rq, struct task_struct *prev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void (*put_prev_task)(struct rq *rq, struct task_struct *p);
 | 
						void (*put_prev_task)(struct rq *rq, struct task_struct *p, struct task_struct *next);
 | 
				
			||||||
	void (*set_next_task)(struct rq *rq, struct task_struct *p, bool first);
 | 
						void (*set_next_task)(struct rq *rq, struct task_struct *p, bool first);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
	int (*balance)(struct rq *rq, struct task_struct *prev, struct rq_flags *rf);
 | 
						int (*balance)(struct rq *rq, struct task_struct *prev, struct rq_flags *rf);
 | 
				
			||||||
	int  (*select_task_rq)(struct task_struct *p, int task_cpu, int flags);
 | 
						int  (*select_task_rq)(struct task_struct *p, int task_cpu, int flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct task_struct * (*pick_task)(struct rq *rq);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	void (*migrate_task_rq)(struct task_struct *p, int new_cpu);
 | 
						void (*migrate_task_rq)(struct task_struct *p, int new_cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void (*task_woken)(struct rq *this_rq, struct task_struct *task);
 | 
						void (*task_woken)(struct rq *this_rq, struct task_struct *task);
 | 
				
			||||||
| 
						 | 
					@ -2345,7 +2364,7 @@ struct sched_class {
 | 
				
			||||||
static inline void put_prev_task(struct rq *rq, struct task_struct *prev)
 | 
					static inline void put_prev_task(struct rq *rq, struct task_struct *prev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	WARN_ON_ONCE(rq->curr != prev);
 | 
						WARN_ON_ONCE(rq->curr != prev);
 | 
				
			||||||
	prev->sched_class->put_prev_task(rq, prev);
 | 
						prev->sched_class->put_prev_task(rq, prev, NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void set_next_task(struct rq *rq, struct task_struct *next)
 | 
					static inline void set_next_task(struct rq *rq, struct task_struct *next)
 | 
				
			||||||
| 
						 | 
					@ -2353,6 +2372,30 @@ static inline void set_next_task(struct rq *rq, struct task_struct *next)
 | 
				
			||||||
	next->sched_class->set_next_task(rq, next, false);
 | 
						next->sched_class->set_next_task(rq, next, false);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void
 | 
				
			||||||
 | 
					__put_prev_set_next_dl_server(struct rq *rq,
 | 
				
			||||||
 | 
								      struct task_struct *prev,
 | 
				
			||||||
 | 
								      struct task_struct *next)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						prev->dl_server = NULL;
 | 
				
			||||||
 | 
						next->dl_server = rq->dl_server;
 | 
				
			||||||
 | 
						rq->dl_server = NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void put_prev_set_next_task(struct rq *rq,
 | 
				
			||||||
 | 
										  struct task_struct *prev,
 | 
				
			||||||
 | 
										  struct task_struct *next)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						WARN_ON_ONCE(rq->curr != prev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__put_prev_set_next_dl_server(rq, prev, next);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (next == prev)
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						prev->sched_class->put_prev_task(rq, prev, next);
 | 
				
			||||||
 | 
						next->sched_class->set_next_task(rq, next, true);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Helper to define a sched_class instance; each one is placed in a separate
 | 
					 * Helper to define a sched_class instance; each one is placed in a separate
 | 
				
			||||||
| 
						 | 
					@ -2408,7 +2451,7 @@ static inline bool sched_fair_runnable(struct rq *rq)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct task_struct *pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf);
 | 
					extern struct task_struct *pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct rq_flags *rf);
 | 
				
			||||||
extern struct task_struct *pick_next_task_idle(struct rq *rq);
 | 
					extern struct task_struct *pick_task_idle(struct rq *rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SCA_CHECK		0x01
 | 
					#define SCA_CHECK		0x01
 | 
				
			||||||
#define SCA_MIGRATE_DISABLE	0x02
 | 
					#define SCA_MIGRATE_DISABLE	0x02
 | 
				
			||||||
| 
						 | 
					@ -2515,7 +2558,6 @@ extern void reweight_task(struct task_struct *p, const struct load_weight *lw);
 | 
				
			||||||
extern void resched_curr(struct rq *rq);
 | 
					extern void resched_curr(struct rq *rq);
 | 
				
			||||||
extern void resched_cpu(int cpu);
 | 
					extern void resched_cpu(int cpu);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern struct rt_bandwidth def_rt_bandwidth;
 | 
					 | 
				
			||||||
extern void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime);
 | 
					extern void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime);
 | 
				
			||||||
extern bool sched_rt_bandwidth_account(struct rt_rq *rt_rq);
 | 
					extern bool sched_rt_bandwidth_account(struct rt_rq *rt_rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2586,6 +2628,19 @@ static inline void sub_nr_running(struct rq *rq, unsigned count)
 | 
				
			||||||
	sched_update_tick_dependency(rq);
 | 
						sched_update_tick_dependency(rq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline void __block_task(struct rq *rq, struct task_struct *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						WRITE_ONCE(p->on_rq, 0);
 | 
				
			||||||
 | 
						ASSERT_EXCLUSIVE_WRITER(p->on_rq);
 | 
				
			||||||
 | 
						if (p->sched_contributes_to_load)
 | 
				
			||||||
 | 
							rq->nr_uninterruptible++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p->in_iowait) {
 | 
				
			||||||
 | 
							atomic_inc(&rq->nr_iowait);
 | 
				
			||||||
 | 
							delayacct_blkio_start();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void activate_task(struct rq *rq, struct task_struct *p, int flags);
 | 
					extern void activate_task(struct rq *rq, struct task_struct *p, int flags);
 | 
				
			||||||
extern void deactivate_task(struct rq *rq, struct task_struct *p, int flags);
 | 
					extern void deactivate_task(struct rq *rq, struct task_struct *p, int flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3607,7 +3662,7 @@ extern int __sched_setaffinity(struct task_struct *p, struct affinity_context *c
 | 
				
			||||||
extern void __setscheduler_prio(struct task_struct *p, int prio);
 | 
					extern void __setscheduler_prio(struct task_struct *p, int prio);
 | 
				
			||||||
extern void set_load_weight(struct task_struct *p, bool update_load);
 | 
					extern void set_load_weight(struct task_struct *p, bool update_load);
 | 
				
			||||||
extern void enqueue_task(struct rq *rq, struct task_struct *p, int flags);
 | 
					extern void enqueue_task(struct rq *rq, struct task_struct *p, int flags);
 | 
				
			||||||
extern void dequeue_task(struct rq *rq, struct task_struct *p, int flags);
 | 
					extern bool dequeue_task(struct rq *rq, struct task_struct *p, int flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern void check_class_changed(struct rq *rq, struct task_struct *p,
 | 
					extern void check_class_changed(struct rq *rq, struct task_struct *p,
 | 
				
			||||||
				const struct sched_class *prev_class,
 | 
									const struct sched_class *prev_class,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,26 +41,17 @@ static struct task_struct *pick_task_stop(struct rq *rq)
 | 
				
			||||||
	return rq->stop;
 | 
						return rq->stop;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct task_struct *pick_next_task_stop(struct rq *rq)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct task_struct *p = pick_task_stop(rq);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (p)
 | 
					 | 
				
			||||||
		set_next_task_stop(rq, p, true);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return p;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
enqueue_task_stop(struct rq *rq, struct task_struct *p, int flags)
 | 
					enqueue_task_stop(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	add_nr_running(rq, 1);
 | 
						add_nr_running(rq, 1);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static bool
 | 
				
			||||||
dequeue_task_stop(struct rq *rq, struct task_struct *p, int flags)
 | 
					dequeue_task_stop(struct rq *rq, struct task_struct *p, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	sub_nr_running(rq, 1);
 | 
						sub_nr_running(rq, 1);
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void yield_task_stop(struct rq *rq)
 | 
					static void yield_task_stop(struct rq *rq)
 | 
				
			||||||
| 
						 | 
					@ -68,7 +59,7 @@ static void yield_task_stop(struct rq *rq)
 | 
				
			||||||
	BUG(); /* the stop task should never yield, its pointless. */
 | 
						BUG(); /* the stop task should never yield, its pointless. */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void put_prev_task_stop(struct rq *rq, struct task_struct *prev)
 | 
					static void put_prev_task_stop(struct rq *rq, struct task_struct *prev, struct task_struct *next)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	update_curr_common(rq);
 | 
						update_curr_common(rq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -111,13 +102,12 @@ DEFINE_SCHED_CLASS(stop) = {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.wakeup_preempt		= wakeup_preempt_stop,
 | 
						.wakeup_preempt		= wakeup_preempt_stop,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.pick_next_task		= pick_next_task_stop,
 | 
						.pick_task		= pick_task_stop,
 | 
				
			||||||
	.put_prev_task		= put_prev_task_stop,
 | 
						.put_prev_task		= put_prev_task_stop,
 | 
				
			||||||
	.set_next_task          = set_next_task_stop,
 | 
						.set_next_task          = set_next_task_stop,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					#ifdef CONFIG_SMP
 | 
				
			||||||
	.balance		= balance_stop,
 | 
						.balance		= balance_stop,
 | 
				
			||||||
	.pick_task		= pick_task_stop,
 | 
					 | 
				
			||||||
	.select_task_rq		= select_task_rq_stop,
 | 
						.select_task_rq		= select_task_rq_stop,
 | 
				
			||||||
	.set_cpus_allowed	= set_cpus_allowed_common,
 | 
						.set_cpus_allowed	= set_cpus_allowed_common,
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,7 +57,7 @@ static int effective_prio(struct task_struct *p)
 | 
				
			||||||
	 * keep the priority unchanged. Otherwise, update priority
 | 
						 * keep the priority unchanged. Otherwise, update priority
 | 
				
			||||||
	 * to the normal priority:
 | 
						 * to the normal priority:
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (!rt_prio(p->prio))
 | 
						if (!rt_or_dl_prio(p->prio))
 | 
				
			||||||
		return p->normal_prio;
 | 
							return p->normal_prio;
 | 
				
			||||||
	return p->prio;
 | 
						return p->prio;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -258,107 +258,6 @@ int sched_core_idle_cpu(int cpu)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_SMP
 | 
					 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * This function computes an effective utilization for the given CPU, to be
 | 
					 | 
				
			||||||
 * used for frequency selection given the linear relation: f = u * f_max.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The scheduler tracks the following metrics:
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 *   cpu_util_{cfs,rt,dl,irq}()
 | 
					 | 
				
			||||||
 *   cpu_bw_dl()
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Where the cfs,rt and dl util numbers are tracked with the same metric and
 | 
					 | 
				
			||||||
 * synchronized windows and are thus directly comparable.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The cfs,rt,dl utilization are the running times measured with rq->clock_task
 | 
					 | 
				
			||||||
 * which excludes things like IRQ and steal-time. These latter are then accrued
 | 
					 | 
				
			||||||
 * in the IRQ utilization.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The DL bandwidth number OTOH is not a measured metric but a value computed
 | 
					 | 
				
			||||||
 * based on the task model parameters and gives the minimal utilization
 | 
					 | 
				
			||||||
 * required to meet deadlines.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
unsigned long effective_cpu_util(int cpu, unsigned long util_cfs,
 | 
					 | 
				
			||||||
				 unsigned long *min,
 | 
					 | 
				
			||||||
				 unsigned long *max)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned long util, irq, scale;
 | 
					 | 
				
			||||||
	struct rq *rq = cpu_rq(cpu);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	scale = arch_scale_cpu_capacity(cpu);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Early check to see if IRQ/steal time saturates the CPU, can be
 | 
					 | 
				
			||||||
	 * because of inaccuracies in how we track these -- see
 | 
					 | 
				
			||||||
	 * update_irq_load_avg().
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	irq = cpu_util_irq(rq);
 | 
					 | 
				
			||||||
	if (unlikely(irq >= scale)) {
 | 
					 | 
				
			||||||
		if (min)
 | 
					 | 
				
			||||||
			*min = scale;
 | 
					 | 
				
			||||||
		if (max)
 | 
					 | 
				
			||||||
			*max = scale;
 | 
					 | 
				
			||||||
		return scale;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (min) {
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * The minimum utilization returns the highest level between:
 | 
					 | 
				
			||||||
		 * - the computed DL bandwidth needed with the IRQ pressure which
 | 
					 | 
				
			||||||
		 *   steals time to the deadline task.
 | 
					 | 
				
			||||||
		 * - The minimum performance requirement for CFS and/or RT.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		*min = max(irq + cpu_bw_dl(rq), uclamp_rq_get(rq, UCLAMP_MIN));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * When an RT task is runnable and uclamp is not used, we must
 | 
					 | 
				
			||||||
		 * ensure that the task will run at maximum compute capacity.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if (!uclamp_is_used() && rt_rq_is_runnable(&rq->rt))
 | 
					 | 
				
			||||||
			*min = max(*min, scale);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * Because the time spend on RT/DL tasks is visible as 'lost' time to
 | 
					 | 
				
			||||||
	 * CFS tasks and we use the same metric to track the effective
 | 
					 | 
				
			||||||
	 * utilization (PELT windows are synchronized) we can directly add them
 | 
					 | 
				
			||||||
	 * to obtain the CPU's actual utilization.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	util = util_cfs + cpu_util_rt(rq);
 | 
					 | 
				
			||||||
	util += cpu_util_dl(rq);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * The maximum hint is a soft bandwidth requirement, which can be lower
 | 
					 | 
				
			||||||
	 * than the actual utilization because of uclamp_max requirements.
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	if (max)
 | 
					 | 
				
			||||||
		*max = min(scale, uclamp_rq_get(rq, UCLAMP_MAX));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (util >= scale)
 | 
					 | 
				
			||||||
		return scale;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/*
 | 
					 | 
				
			||||||
	 * There is still idle time; further improve the number by using the
 | 
					 | 
				
			||||||
	 * IRQ metric. Because IRQ/steal time is hidden from the task clock we
 | 
					 | 
				
			||||||
	 * need to scale the task numbers:
 | 
					 | 
				
			||||||
	 *
 | 
					 | 
				
			||||||
	 *              max - irq
 | 
					 | 
				
			||||||
	 *   U' = irq + --------- * U
 | 
					 | 
				
			||||||
	 *                 max
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
	util = scale_irq_capacity(util, irq, scale);
 | 
					 | 
				
			||||||
	util += irq;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return min(scale, util);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
unsigned long sched_cpu_util(int cpu)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return effective_cpu_util(cpu, cpu_util_cfs(cpu), NULL, NULL);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif /* CONFIG_SMP */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * find_process_by_pid - find a process with a matching PID value.
 | 
					 * find_process_by_pid - find a process with a matching PID value.
 | 
				
			||||||
 * @pid: the pid in question.
 | 
					 * @pid: the pid in question.
 | 
				
			||||||
| 
						 | 
					@ -401,13 +300,23 @@ static void __setscheduler_params(struct task_struct *p,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p->policy = policy;
 | 
						p->policy = policy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dl_policy(policy))
 | 
						if (dl_policy(policy)) {
 | 
				
			||||||
		__setparam_dl(p, attr);
 | 
							__setparam_dl(p, attr);
 | 
				
			||||||
	else if (fair_policy(policy))
 | 
						} else if (fair_policy(policy)) {
 | 
				
			||||||
		p->static_prio = NICE_TO_PRIO(attr->sched_nice);
 | 
							p->static_prio = NICE_TO_PRIO(attr->sched_nice);
 | 
				
			||||||
 | 
							if (attr->sched_runtime) {
 | 
				
			||||||
 | 
								p->se.custom_slice = 1;
 | 
				
			||||||
 | 
								p->se.slice = clamp_t(u64, attr->sched_runtime,
 | 
				
			||||||
 | 
										      NSEC_PER_MSEC/10,   /* HZ=1000 * 10 */
 | 
				
			||||||
 | 
										      NSEC_PER_MSEC*100); /* HZ=100  / 10 */
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								p->se.custom_slice = 0;
 | 
				
			||||||
 | 
								p->se.slice = sysctl_sched_base_slice;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* rt-policy tasks do not have a timerslack */
 | 
						/* rt-policy tasks do not have a timerslack */
 | 
				
			||||||
	if (task_is_realtime(p)) {
 | 
						if (rt_or_dl_task_policy(p)) {
 | 
				
			||||||
		p->timer_slack_ns = 0;
 | 
							p->timer_slack_ns = 0;
 | 
				
			||||||
	} else if (p->timer_slack_ns == 0) {
 | 
						} else if (p->timer_slack_ns == 0) {
 | 
				
			||||||
		/* when switching back to non-rt policy, restore timerslack */
 | 
							/* when switching back to non-rt policy, restore timerslack */
 | 
				
			||||||
| 
						 | 
					@ -708,7 +617,9 @@ int __sched_setscheduler(struct task_struct *p,
 | 
				
			||||||
	 * but store a possible modification of reset_on_fork.
 | 
						 * but store a possible modification of reset_on_fork.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (unlikely(policy == p->policy)) {
 | 
						if (unlikely(policy == p->policy)) {
 | 
				
			||||||
		if (fair_policy(policy) && attr->sched_nice != task_nice(p))
 | 
							if (fair_policy(policy) &&
 | 
				
			||||||
 | 
							    (attr->sched_nice != task_nice(p) ||
 | 
				
			||||||
 | 
							     (attr->sched_runtime != p->se.slice)))
 | 
				
			||||||
			goto change;
 | 
								goto change;
 | 
				
			||||||
		if (rt_policy(policy) && attr->sched_priority != p->rt_priority)
 | 
							if (rt_policy(policy) && attr->sched_priority != p->rt_priority)
 | 
				
			||||||
			goto change;
 | 
								goto change;
 | 
				
			||||||
| 
						 | 
					@ -854,6 +765,9 @@ static int _sched_setscheduler(struct task_struct *p, int policy,
 | 
				
			||||||
		.sched_nice	= PRIO_TO_NICE(p->static_prio),
 | 
							.sched_nice	= PRIO_TO_NICE(p->static_prio),
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (p->se.custom_slice)
 | 
				
			||||||
 | 
							attr.sched_runtime = p->se.slice;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* Fixup the legacy SCHED_RESET_ON_FORK hack. */
 | 
						/* Fixup the legacy SCHED_RESET_ON_FORK hack. */
 | 
				
			||||||
	if ((policy != SETPARAM_POLICY) && (policy & SCHED_RESET_ON_FORK)) {
 | 
						if ((policy != SETPARAM_POLICY) && (policy & SCHED_RESET_ON_FORK)) {
 | 
				
			||||||
		attr.sched_flags |= SCHED_FLAG_RESET_ON_FORK;
 | 
							attr.sched_flags |= SCHED_FLAG_RESET_ON_FORK;
 | 
				
			||||||
| 
						 | 
					@ -1020,12 +934,14 @@ static int sched_copy_attr(struct sched_attr __user *uattr, struct sched_attr *a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void get_params(struct task_struct *p, struct sched_attr *attr)
 | 
					static void get_params(struct task_struct *p, struct sched_attr *attr)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (task_has_dl_policy(p))
 | 
						if (task_has_dl_policy(p)) {
 | 
				
			||||||
		__getparam_dl(p, attr);
 | 
							__getparam_dl(p, attr);
 | 
				
			||||||
	else if (task_has_rt_policy(p))
 | 
						} else if (task_has_rt_policy(p)) {
 | 
				
			||||||
		attr->sched_priority = p->rt_priority;
 | 
							attr->sched_priority = p->rt_priority;
 | 
				
			||||||
	else
 | 
						} else {
 | 
				
			||||||
		attr->sched_nice = task_nice(p);
 | 
							attr->sched_nice = task_nice(p);
 | 
				
			||||||
 | 
							attr->sched_runtime = p->se.slice;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -516,6 +516,14 @@ void rq_attach_root(struct rq *rq, struct root_domain *rd)
 | 
				
			||||||
	if (cpumask_test_cpu(rq->cpu, cpu_active_mask))
 | 
						if (cpumask_test_cpu(rq->cpu, cpu_active_mask))
 | 
				
			||||||
		set_rq_online(rq);
 | 
							set_rq_online(rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Because the rq is not a task, dl_add_task_root_domain() did not
 | 
				
			||||||
 | 
						 * move the fair server bw to the rd if it already started.
 | 
				
			||||||
 | 
						 * Add it now.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (rq->fair_server.dl_server)
 | 
				
			||||||
 | 
							__dl_server_attach_root(&rq->fair_server, rq);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rq_unlock_irqrestore(rq, &rf);
 | 
						rq_unlock_irqrestore(rq, &rf);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (old_rd)
 | 
						if (old_rd)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2557,7 +2557,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
 | 
				
			||||||
			error = current->timer_slack_ns;
 | 
								error = current->timer_slack_ns;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	case PR_SET_TIMERSLACK:
 | 
						case PR_SET_TIMERSLACK:
 | 
				
			||||||
		if (task_is_realtime(current))
 | 
							if (rt_or_dl_task_policy(current))
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		if (arg2 <= 0)
 | 
							if (arg2 <= 0)
 | 
				
			||||||
			current->timer_slack_ns =
 | 
								current->timer_slack_ns =
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1977,7 +1977,7 @@ static void __hrtimer_init_sleeper(struct hrtimer_sleeper *sl,
 | 
				
			||||||
	 * expiry.
 | 
						 * expiry.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
 | 
						if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
 | 
				
			||||||
		if (task_is_realtime(current) && !(mode & HRTIMER_MODE_SOFT))
 | 
							if (rt_or_dl_task_policy(current) && !(mode & HRTIMER_MODE_SOFT))
 | 
				
			||||||
			mode |= HRTIMER_MODE_HARD;
 | 
								mode |= HRTIMER_MODE_HARD;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -547,7 +547,7 @@ probe_wakeup(void *ignore, struct task_struct *p)
 | 
				
			||||||
	 *  - wakeup_dl handles tasks belonging to sched_dl class only.
 | 
						 *  - wakeup_dl handles tasks belonging to sched_dl class only.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (tracing_dl || (wakeup_dl && !dl_task(p)) ||
 | 
						if (tracing_dl || (wakeup_dl && !dl_task(p)) ||
 | 
				
			||||||
	    (wakeup_rt && !dl_task(p) && !rt_task(p)) ||
 | 
						    (wakeup_rt && !rt_or_dl_task(p)) ||
 | 
				
			||||||
	    (!dl_task(p) && (p->prio >= wakeup_prio || p->prio >= current->prio)))
 | 
						    (!dl_task(p) && (p->prio >= wakeup_prio || p->prio >= current->prio)))
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -418,7 +418,7 @@ static void domain_dirty_limits(struct dirty_throttle_control *dtc)
 | 
				
			||||||
		bg_thresh = (bg_ratio * available_memory) / PAGE_SIZE;
 | 
							bg_thresh = (bg_ratio * available_memory) / PAGE_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tsk = current;
 | 
						tsk = current;
 | 
				
			||||||
	if (rt_task(tsk)) {
 | 
						if (rt_or_dl_task(tsk)) {
 | 
				
			||||||
		bg_thresh += bg_thresh / 4 + global_wb_domain.dirty_limit / 32;
 | 
							bg_thresh += bg_thresh / 4 + global_wb_domain.dirty_limit / 32;
 | 
				
			||||||
		thresh += thresh / 4 + global_wb_domain.dirty_limit / 32;
 | 
							thresh += thresh / 4 + global_wb_domain.dirty_limit / 32;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -477,7 +477,7 @@ static unsigned long node_dirty_limit(struct pglist_data *pgdat)
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		dirty = vm_dirty_ratio * node_memory / 100;
 | 
							dirty = vm_dirty_ratio * node_memory / 100;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (rt_task(tsk))
 | 
						if (rt_or_dl_task(tsk))
 | 
				
			||||||
		dirty += dirty / 4;
 | 
							dirty += dirty / 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4004,7 +4004,7 @@ gfp_to_alloc_flags(gfp_t gfp_mask, unsigned int order)
 | 
				
			||||||
		 */
 | 
							 */
 | 
				
			||||||
		if (alloc_flags & ALLOC_MIN_RESERVE)
 | 
							if (alloc_flags & ALLOC_MIN_RESERVE)
 | 
				
			||||||
			alloc_flags &= ~ALLOC_CPUSET;
 | 
								alloc_flags &= ~ALLOC_CPUSET;
 | 
				
			||||||
	} else if (unlikely(rt_task(current)) && in_task())
 | 
						} else if (unlikely(rt_or_dl_task(current)) && in_task())
 | 
				
			||||||
		alloc_flags |= ALLOC_MIN_RESERVE;
 | 
							alloc_flags |= ALLOC_MIN_RESERVE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	alloc_flags = gfp_to_alloc_flags_cma(gfp_mask, alloc_flags);
 | 
						alloc_flags = gfp_to_alloc_flags_cma(gfp_mask, alloc_flags);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue