summaryrefslogtreecommitdiffstats
path: root/debian/patches-rt/psi-replace-delayed-work-with-timer-work.patch
blob: c0cf3b5e721f26834e5406e9d9caa83d63994b5e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
From: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Date: Tue, 12 Feb 2019 15:03:03 +0100
Subject: [PATCH] psi: replace delayed work with timer + work
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.0/older/patches-5.0.7-rt5.tar.xz

psi_task_change() is invoked with disabled interrupts and this does not
allow to use schedule_delayed_work().

Replace schedule_delayed_work() with a timer which schedules the work
immediately.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 include/linux/psi_types.h |    3 ++-
 kernel/sched/psi.c        |   39 ++++++++++++++++++++++++++++++---------
 2 files changed, 32 insertions(+), 10 deletions(-)

--- a/include/linux/psi_types.h
+++ b/include/linux/psi_types.h
@@ -76,7 +76,8 @@ struct psi_group {
 	u64 total_prev[NR_PSI_STATES - 1];
 	u64 last_update;
 	u64 next_update;
-	struct delayed_work clock_work;
+	struct work_struct clock_work;
+	struct timer_list clock_work_timer;
 
 	/* Total stall times and sampled pressure averages */
 	u64 total[NR_PSI_STATES - 1];
--- a/kernel/sched/psi.c
+++ b/kernel/sched/psi.c
@@ -124,6 +124,7 @@
  * sampling of the aggregate task states would be.
  */
 
+#include <linux/sched.h>
 #include "../workqueue_internal.h"
 #include <linux/sched/loadavg.h>
 #include <linux/seq_file.h>
@@ -131,7 +132,6 @@
 #include <linux/seqlock.h>
 #include <linux/cgroup.h>
 #include <linux/module.h>
-#include <linux/sched.h>
 #include <linux/psi.h>
 #include "sched.h"
 
@@ -166,6 +166,7 @@ static struct psi_group psi_system = {
 };
 
 static void psi_update_work(struct work_struct *work);
+static void psi_sched_update_work(struct timer_list *t);
 
 static void group_init(struct psi_group *group)
 {
@@ -174,7 +175,8 @@ static void group_init(struct psi_group
 	for_each_possible_cpu(cpu)
 		seqcount_init(&per_cpu_ptr(group->pcpu, cpu)->seq);
 	group->next_update = sched_clock() + psi_period;
-	INIT_DELAYED_WORK(&group->clock_work, psi_update_work);
+	INIT_WORK(&group->clock_work, psi_update_work);
+	timer_setup(&group->clock_work_timer, psi_sched_update_work, 0);
 	mutex_init(&group->stat_lock);
 }
 
@@ -367,14 +369,14 @@ static bool update_stats(struct psi_grou
 	return nonidle_total;
 }
 
+static void psi_sched_delayed_work(struct psi_group *group, unsigned long delay);
+
 static void psi_update_work(struct work_struct *work)
 {
-	struct delayed_work *dwork;
 	struct psi_group *group;
 	bool nonidle;
 
-	dwork = to_delayed_work(work);
-	group = container_of(dwork, struct psi_group, clock_work);
+	group = container_of(work, struct psi_group, clock_work);
 
 	/*
 	 * If there is task activity, periodically fold the per-cpu
@@ -393,7 +395,7 @@ static void psi_update_work(struct work_
 		now = sched_clock();
 		if (group->next_update > now)
 			delay = nsecs_to_jiffies(group->next_update - now) + 1;
-		schedule_delayed_work(dwork, delay);
+		psi_sched_delayed_work(group, delay);
 	}
 }
 
@@ -507,6 +509,20 @@ static struct psi_group *iterate_groups(
 	return &psi_system;
 }
 
+static void psi_sched_update_work(struct timer_list *t)
+{
+	struct psi_group *group = from_timer(group, t, clock_work_timer);
+
+	schedule_work(&group->clock_work);
+}
+
+static void psi_sched_delayed_work(struct psi_group *group, unsigned long delay)
+{
+	if (!timer_pending(&group->clock_work_timer) &&
+	    !work_pending(&group->clock_work))
+		mod_timer(&group->clock_work_timer, delay);
+}
+
 void psi_task_change(struct task_struct *task, int clear, int set)
 {
 	int cpu = task_cpu(task);
@@ -540,10 +556,14 @@ void psi_task_change(struct task_struct
 		     wq_worker_last_func(task) == psi_update_work))
 		wake_clock = false;
 
+	if (wake_clock) {
+		if (task_is_ktimer_softirqd(task))
+			wake_clock = false;
+	}
 	while ((group = iterate_groups(task, &iter))) {
 		psi_group_change(group, cpu, clear, set);
-		if (wake_clock && !delayed_work_pending(&group->clock_work))
-			schedule_delayed_work(&group->clock_work, PSI_FREQ);
+		if (wake_clock)
+			psi_sched_delayed_work(group, PSI_FREQ);
 	}
 }
 
@@ -640,7 +660,8 @@ void psi_cgroup_free(struct cgroup *cgro
 	if (static_branch_likely(&psi_disabled))
 		return;
 
-	cancel_delayed_work_sync(&cgroup->psi.clock_work);
+	del_timer_sync(&cgroup->psi.clock_work_timer);
+	cancel_work_sync(&cgroup->psi.clock_work);
 	free_percpu(cgroup->psi.pcpu);
 }