Blame view

kernel/sched_autogroup.c 6.03 KB
5091faa44   Mike Galbraith   sched: Add 'autog...
1
2
3
4
5
6
7
8
9
10
  #ifdef CONFIG_SCHED_AUTOGROUP
  
  #include <linux/proc_fs.h>
  #include <linux/seq_file.h>
  #include <linux/kallsyms.h>
  #include <linux/utsname.h>
  
  unsigned int __read_mostly sysctl_sched_autogroup_enabled = 1;
  static struct autogroup autogroup_default;
  static atomic_t autogroup_seq_nr;
0ca087355   Yong Zhang   sched: Mark autog...
11
  static void __init autogroup_init(struct task_struct *init_task)
5091faa44   Mike Galbraith   sched: Add 'autog...
12
  {
07e06b011   Yong Zhang   sched: Consolidat...
13
  	autogroup_default.tg = &root_task_group;
5091faa44   Mike Galbraith   sched: Add 'autog...
14
15
16
17
18
19
20
21
22
23
24
25
26
  	kref_init(&autogroup_default.kref);
  	init_rwsem(&autogroup_default.lock);
  	init_task->signal->autogroup = &autogroup_default;
  }
  
  static inline void autogroup_free(struct task_group *tg)
  {
  	kfree(tg->autogroup);
  }
  
  static inline void autogroup_destroy(struct kref *kref)
  {
  	struct autogroup *ag = container_of(kref, struct autogroup, kref);
f44937718   Mike Galbraith   sched, autogroup:...
27
28
29
30
31
  #ifdef CONFIG_RT_GROUP_SCHED
  	/* We've redirected RT tasks to the root task group... */
  	ag->tg->rt_se = NULL;
  	ag->tg->rt_rq = NULL;
  #endif
5091faa44   Mike Galbraith   sched: Add 'autog...
32
33
34
35
36
37
38
39
40
41
42
43
44
  	sched_destroy_group(ag->tg);
  }
  
  static inline void autogroup_kref_put(struct autogroup *ag)
  {
  	kref_put(&ag->kref, autogroup_destroy);
  }
  
  static inline struct autogroup *autogroup_kref_get(struct autogroup *ag)
  {
  	kref_get(&ag->kref);
  	return ag;
  }
4f8219875   Mike Galbraith   sched, autogroup:...
45
46
47
48
49
50
51
52
53
54
55
56
57
  static inline struct autogroup *autogroup_task_get(struct task_struct *p)
  {
  	struct autogroup *ag;
  	unsigned long flags;
  
  	if (!lock_task_sighand(p, &flags))
  		return autogroup_kref_get(&autogroup_default);
  
  	ag = autogroup_kref_get(p->signal->autogroup);
  	unlock_task_sighand(p, &flags);
  
  	return ag;
  }
f44937718   Mike Galbraith   sched, autogroup:...
58
59
60
  #ifdef CONFIG_RT_GROUP_SCHED
  static void free_rt_sched_group(struct task_group *tg);
  #endif
5091faa44   Mike Galbraith   sched: Add 'autog...
61
62
63
64
65
66
67
  static inline struct autogroup *autogroup_create(void)
  {
  	struct autogroup *ag = kzalloc(sizeof(*ag), GFP_KERNEL);
  	struct task_group *tg;
  
  	if (!ag)
  		goto out_fail;
07e06b011   Yong Zhang   sched: Consolidat...
68
  	tg = sched_create_group(&root_task_group);
5091faa44   Mike Galbraith   sched: Add 'autog...
69
70
71
72
73
74
75
76
  
  	if (IS_ERR(tg))
  		goto out_free;
  
  	kref_init(&ag->kref);
  	init_rwsem(&ag->lock);
  	ag->id = atomic_inc_return(&autogroup_seq_nr);
  	ag->tg = tg;
f44937718   Mike Galbraith   sched, autogroup:...
77
78
79
80
81
82
83
84
85
86
87
88
89
  #ifdef CONFIG_RT_GROUP_SCHED
  	/*
  	 * Autogroup RT tasks are redirected to the root task group
  	 * so we don't have to move tasks around upon policy change,
  	 * or flail around trying to allocate bandwidth on the fly.
  	 * A bandwidth exception in __sched_setscheduler() allows
  	 * the policy change to proceed.  Thereafter, task_group()
  	 * returns &root_task_group, so zero bandwidth is required.
  	 */
  	free_rt_sched_group(tg);
  	tg->rt_se = root_task_group.rt_se;
  	tg->rt_rq = root_task_group.rt_rq;
  #endif
5091faa44   Mike Galbraith   sched: Add 'autog...
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
  	tg->autogroup = ag;
  
  	return ag;
  
  out_free:
  	kfree(ag);
  out_fail:
  	if (printk_ratelimit()) {
  		printk(KERN_WARNING "autogroup_create: %s failure.
  ",
  			ag ? "sched_create_group()" : "kmalloc()");
  	}
  
  	return autogroup_kref_get(&autogroup_default);
  }
  
  static inline bool
  task_wants_autogroup(struct task_struct *p, struct task_group *tg)
  {
  	if (tg != &root_task_group)
  		return false;
  
  	if (p->sched_class != &fair_sched_class)
  		return false;
  
  	/*
  	 * We can only assume the task group can't go away on us if
  	 * autogroup_move_group() can see us on ->thread_group list.
  	 */
  	if (p->flags & PF_EXITING)
  		return false;
  
  	return true;
  }
f44937718   Mike Galbraith   sched, autogroup:...
124
125
  static inline bool task_group_is_autogroup(struct task_group *tg)
  {
511f67a59   Mike Galbraith   sched, autogroup:...
126
  	return !!tg->autogroup;
f44937718   Mike Galbraith   sched, autogroup:...
127
  }
5091faa44   Mike Galbraith   sched: Add 'autog...
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
  static inline struct task_group *
  autogroup_task_group(struct task_struct *p, struct task_group *tg)
  {
  	int enabled = ACCESS_ONCE(sysctl_sched_autogroup_enabled);
  
  	if (enabled && task_wants_autogroup(p, tg))
  		return p->signal->autogroup->tg;
  
  	return tg;
  }
  
  static void
  autogroup_move_group(struct task_struct *p, struct autogroup *ag)
  {
  	struct autogroup *prev;
  	struct task_struct *t;
  	unsigned long flags;
  
  	BUG_ON(!lock_task_sighand(p, &flags));
  
  	prev = p->signal->autogroup;
  	if (prev == ag) {
  		unlock_task_sighand(p, &flags);
  		return;
  	}
  
  	p->signal->autogroup = autogroup_kref_get(ag);
800d4d30c   Yong Zhang   sched, autogroup:...
155
156
  	if (!ACCESS_ONCE(sysctl_sched_autogroup_enabled))
  		goto out;
5091faa44   Mike Galbraith   sched: Add 'autog...
157
158
159
160
  	t = p;
  	do {
  		sched_move_task(t);
  	} while_each_thread(p, t);
800d4d30c   Yong Zhang   sched, autogroup:...
161
  out:
5091faa44   Mike Galbraith   sched: Add 'autog...
162
163
164
165
166
167
168
169
170
171
  	unlock_task_sighand(p, &flags);
  	autogroup_kref_put(prev);
  }
  
  /* Allocates GFP_KERNEL, cannot be called under any spinlock */
  void sched_autogroup_create_attach(struct task_struct *p)
  {
  	struct autogroup *ag = autogroup_create();
  
  	autogroup_move_group(p, ag);
25985edce   Lucas De Marchi   Fix common misspe...
172
  	/* drop extra reference added by autogroup_create() */
5091faa44   Mike Galbraith   sched: Add 'autog...
173
174
175
176
177
178
179
180
181
182
183
184
185
  	autogroup_kref_put(ag);
  }
  EXPORT_SYMBOL(sched_autogroup_create_attach);
  
  /* Cannot be called under siglock.  Currently has no users */
  void sched_autogroup_detach(struct task_struct *p)
  {
  	autogroup_move_group(p, &autogroup_default);
  }
  EXPORT_SYMBOL(sched_autogroup_detach);
  
  void sched_autogroup_fork(struct signal_struct *sig)
  {
4f8219875   Mike Galbraith   sched, autogroup:...
186
  	sig->autogroup = autogroup_task_get(current);
5091faa44   Mike Galbraith   sched: Add 'autog...
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
  }
  
  void sched_autogroup_exit(struct signal_struct *sig)
  {
  	autogroup_kref_put(sig->autogroup);
  }
  
  static int __init setup_autogroup(char *str)
  {
  	sysctl_sched_autogroup_enabled = 0;
  
  	return 1;
  }
  
  __setup("noautogroup", setup_autogroup);
  
  #ifdef CONFIG_PROC_FS
5091faa44   Mike Galbraith   sched: Add 'autog...
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  int proc_sched_autogroup_set_nice(struct task_struct *p, int *nice)
  {
  	static unsigned long next = INITIAL_JIFFIES;
  	struct autogroup *ag;
  	int err;
  
  	if (*nice < -20 || *nice > 19)
  		return -EINVAL;
  
  	err = security_task_setnice(current, *nice);
  	if (err)
  		return err;
  
  	if (*nice < 0 && !can_nice(current, *nice))
  		return -EPERM;
  
  	/* this is a heavy operation taking global locks.. */
  	if (!capable(CAP_SYS_ADMIN) && time_before(jiffies, next))
  		return -EAGAIN;
  
  	next = HZ / 10 + jiffies;
4f8219875   Mike Galbraith   sched, autogroup:...
225
  	ag = autogroup_task_get(p);
5091faa44   Mike Galbraith   sched: Add 'autog...
226
227
228
229
230
231
232
233
234
235
236
237
238
239
  
  	down_write(&ag->lock);
  	err = sched_group_set_shares(ag->tg, prio_to_weight[*nice + 20]);
  	if (!err)
  		ag->nice = *nice;
  	up_write(&ag->lock);
  
  	autogroup_kref_put(ag);
  
  	return err;
  }
  
  void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m)
  {
4f8219875   Mike Galbraith   sched, autogroup:...
240
  	struct autogroup *ag = autogroup_task_get(p);
5091faa44   Mike Galbraith   sched: Add 'autog...
241

511f67a59   Mike Galbraith   sched, autogroup:...
242
243
  	if (!task_group_is_autogroup(ag->tg))
  		goto out;
5091faa44   Mike Galbraith   sched: Add 'autog...
244
245
246
247
  	down_read(&ag->lock);
  	seq_printf(m, "/autogroup-%ld nice %d
  ", ag->id, ag->nice);
  	up_read(&ag->lock);
511f67a59   Mike Galbraith   sched, autogroup:...
248
  out:
5091faa44   Mike Galbraith   sched: Add 'autog...
249
250
251
252
253
254
255
  	autogroup_kref_put(ag);
  }
  #endif /* CONFIG_PROC_FS */
  
  #ifdef CONFIG_SCHED_DEBUG
  static inline int autogroup_path(struct task_group *tg, char *buf, int buflen)
  {
511f67a59   Mike Galbraith   sched, autogroup:...
256
  	if (!task_group_is_autogroup(tg))
8ecedd7a0   Bharata B Rao   sched: Display au...
257
  		return 0;
5091faa44   Mike Galbraith   sched: Add 'autog...
258
259
260
261
262
  	return snprintf(buf, buflen, "%s-%ld", "/autogroup", tg->autogroup->id);
  }
  #endif /* CONFIG_SCHED_DEBUG */
  
  #endif /* CONFIG_SCHED_AUTOGROUP */