fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / kernel / vserver / sched.c
1 /*
2  *  linux/kernel/vserver/sched.c
3  *
4  *  Virtual Server: Scheduler Support
5  *
6  *  Copyright (C) 2004-2007  Herbert Pƶtzl
7  *
8  *  V0.01  adapted Sam Vilains version to 2.6.3
9  *  V0.02  removed legacy interface
10  *  V0.03  changed vcmds to vxi arg
11  *
12  */
13
14 #include <linux/sched.h>
15 #include <linux/vs_context.h>
16 #include <linux/vs_sched.h>
17 #include <linux/vserver/sched_cmd.h>
18
19 #include <asm/errno.h>
20 #include <asm/uaccess.h>
21
22 #define vxd_check_range(val, min, max) do {             \
23         vxlprintk((val<min) || (val>max),               \
24                 "check_range(%ld,%ld,%ld)",             \
25                 (long)val, (long)min, (long)max,        \
26                 __FILE__, __LINE__);                    \
27         } while (0)
28
29
30 void vx_update_sched_param(struct _vx_sched *sched,
31         struct _vx_sched_pc *sched_pc)
32 {
33         unsigned int set_mask = sched->update_mask;
34
35         if (set_mask & VXSM_FILL_RATE)
36                 sched_pc->fill_rate[0] = sched->fill_rate[0];
37         if (set_mask & VXSM_INTERVAL)
38                 sched_pc->interval[0] = sched->interval[0];
39         if (set_mask & VXSM_FILL_RATE2)
40                 sched_pc->fill_rate[1] = sched->fill_rate[1];
41         if (set_mask & VXSM_INTERVAL2)
42                 sched_pc->interval[1] = sched->interval[1];
43         if (set_mask & VXSM_TOKENS)
44                 sched_pc->tokens = sched->tokens;
45         if (set_mask & VXSM_TOKENS_MIN)
46                 sched_pc->tokens_min = sched->tokens_min;
47         if (set_mask & VXSM_TOKENS_MAX)
48                 sched_pc->tokens_max = sched->tokens_max;
49         if (set_mask & VXSM_PRIO_BIAS)
50                 sched_pc->prio_bias = sched->prio_bias;
51
52         if (set_mask & VXSM_IDLE_TIME)
53                 sched_pc->flags |= VXSF_IDLE_TIME;
54         else
55                 sched_pc->flags &= ~VXSF_IDLE_TIME;
56
57         /* reset time */
58         sched_pc->norm_time = jiffies;
59 }
60
61
62 /*
63  * recalculate the context's scheduling tokens
64  *
65  * ret > 0 : number of tokens available
66  * ret < 0 : on hold, check delta_min[]
67  *           -1 only jiffies
68  *           -2 also idle time
69  *
70  */
71 int vx_tokens_recalc(struct _vx_sched_pc *sched_pc,
72         unsigned long *norm_time, unsigned long *idle_time, int delta_min[2])
73 {
74         long delta;
75         long tokens = 0;
76         int flags = sched_pc->flags;
77
78         /* how much time did pass? */
79         delta = *norm_time - sched_pc->norm_time;
80         vxd_check_range(delta, 0, INT_MAX);
81
82         if (delta >= sched_pc->interval[0]) {
83                 long tokens, integral;
84
85                 /* calc integral token part */
86                 tokens = delta / sched_pc->interval[0];
87                 integral = tokens * sched_pc->interval[0];
88                 tokens *= sched_pc->fill_rate[0];
89 #ifdef  CONFIG_VSERVER_HARDCPU
90                 delta_min[0] = delta - integral;
91                 vxd_check_range(delta_min[0], 0, sched_pc->interval[0]);
92 #endif
93                 /* advance time */
94                 sched_pc->norm_time += delta;
95
96                 /* add tokens */
97                 sched_pc->tokens += tokens;
98                 sched_pc->token_time += tokens;
99         }
100         else
101                 delta_min[0] = delta;
102
103 #ifdef  CONFIG_VSERVER_IDLETIME
104         if (!(flags & VXSF_IDLE_TIME))
105                 goto skip_idle;
106
107         /* how much was the idle skip? */
108         delta = *idle_time - sched_pc->idle_time;
109         vxd_check_range(delta, 0, INT_MAX);
110
111         if (delta >= sched_pc->interval[1]) {
112                 long tokens, integral;
113
114                 /* calc fair share token part */
115                 tokens = delta / sched_pc->interval[1];
116                 integral = tokens * sched_pc->interval[1];
117                 tokens *= sched_pc->fill_rate[1];
118                 delta_min[1] = delta - integral;
119                 vxd_check_range(delta_min[1], 0, sched_pc->interval[1]);
120
121                 /* advance idle time */
122                 sched_pc->idle_time += integral;
123
124                 /* add tokens */
125                 sched_pc->tokens += tokens;
126                 sched_pc->token_time += tokens;
127         }
128         else
129                 delta_min[1] = delta;
130 skip_idle:
131 #endif
132
133         /* clip at maximum */
134         if (sched_pc->tokens > sched_pc->tokens_max)
135                 sched_pc->tokens = sched_pc->tokens_max;
136         tokens = sched_pc->tokens;
137
138         if ((flags & VXSF_ONHOLD)) {
139                 /* can we unhold? */
140                 if (tokens >= sched_pc->tokens_min) {
141                         flags &= ~VXSF_ONHOLD;
142                         sched_pc->hold_ticks +=
143                                 *norm_time - sched_pc->onhold;
144                 }
145                 else
146                         goto on_hold;
147         } else {
148                 /* put on hold? */
149                 if (tokens <= 0) {
150                         flags |= VXSF_ONHOLD;
151                         sched_pc->onhold = *norm_time;
152                         goto on_hold;
153                 }
154         }
155         sched_pc->flags = flags;
156         return tokens;
157
158 on_hold:
159         tokens = sched_pc->tokens_min - tokens;
160         sched_pc->flags = flags;
161         BUG_ON(tokens < 0);
162
163 #ifdef  CONFIG_VSERVER_HARDCPU
164         /* next interval? */
165         if (!sched_pc->fill_rate[0])
166                 delta_min[0] = HZ;
167         else if (tokens > sched_pc->fill_rate[0])
168                 delta_min[0] += sched_pc->interval[0] *
169                         tokens / sched_pc->fill_rate[0];
170         else
171                 delta_min[0] = sched_pc->interval[0] - delta_min[0];
172         vxd_check_range(delta_min[0], 0, INT_MAX);
173
174 #ifdef  CONFIG_VSERVER_IDLETIME
175         if (!(flags & VXSF_IDLE_TIME))
176                 return -1;
177
178         /* next interval? */
179         if (!sched_pc->fill_rate[1])
180                 delta_min[1] = HZ;
181         else if (tokens > sched_pc->fill_rate[1])
182                 delta_min[1] += sched_pc->interval[1] *
183                         tokens / sched_pc->fill_rate[1];
184         else
185                 delta_min[1] = sched_pc->interval[1] - delta_min[1];
186         vxd_check_range(delta_min[1], 0, INT_MAX);
187
188         return -2;
189 #else
190         return -1;
191 #endif /* CONFIG_VSERVER_IDLETIME */
192 #else
193         return 0;
194 #endif /* CONFIG_VSERVER_HARDCPU */
195 }
196
197 static inline unsigned long msec_to_ticks(unsigned long msec)
198 {
199         return msecs_to_jiffies(msec);
200 }
201
202 static inline unsigned long ticks_to_msec(unsigned long ticks)
203 {
204         return jiffies_to_msecs(ticks);
205 }
206
207 static inline unsigned long ticks_to_usec(unsigned long ticks)
208 {
209         return jiffies_to_usecs(ticks);
210 }
211
212
213 static int do_set_sched(struct vx_info *vxi, struct vcmd_sched_v5 *data)
214 {
215         unsigned int set_mask = data->mask;
216         unsigned int update_mask;
217         int i, cpu;
218
219         /* Sanity check data values */
220         if (data->tokens_max <= 0)
221                 data->tokens_max = HZ;
222         if (data->tokens_min < 0)
223                 data->tokens_min = HZ/3;
224         if (data->tokens_min >= data->tokens_max)
225                 data->tokens_min = data->tokens_max;
226
227         if (data->prio_bias > MAX_PRIO_BIAS)
228                 data->prio_bias = MAX_PRIO_BIAS;
229         if (data->prio_bias < MIN_PRIO_BIAS)
230                 data->prio_bias = MIN_PRIO_BIAS;
231
232         spin_lock(&vxi->sched.tokens_lock);
233
234         /* sync up on delayed updates */
235         for_each_cpu_mask(cpu, vxi->sched.update)
236                 vx_update_sched_param(&vxi->sched,
237                         &vx_per_cpu(vxi, sched_pc, cpu));
238
239         if (set_mask & VXSM_FILL_RATE)
240                 vxi->sched.fill_rate[0] = data->fill_rate[0];
241         if (set_mask & VXSM_FILL_RATE2)
242                 vxi->sched.fill_rate[1] = data->fill_rate[1];
243         if (set_mask & VXSM_INTERVAL)
244                 vxi->sched.interval[0] = (set_mask & VXSM_MSEC) ?
245                         msec_to_ticks(data->interval[0]) : data->interval[0];
246         if (set_mask & VXSM_INTERVAL2)
247                 vxi->sched.interval[1] = (set_mask & VXSM_MSEC) ?
248                         msec_to_ticks(data->interval[1]) : data->interval[1];
249         if (set_mask & VXSM_TOKENS)
250                 vxi->sched.tokens = data->tokens;
251         if (set_mask & VXSM_TOKENS_MIN)
252                 vxi->sched.tokens_min = data->tokens_min;
253         if (set_mask & VXSM_TOKENS_MAX)
254                 vxi->sched.tokens_max = data->tokens_max;
255         if (set_mask & VXSM_PRIO_BIAS)
256                 vxi->sched.prio_bias = data->prio_bias;
257
258         /* Sanity check rate/interval */
259         for (i=0; i<2; i++) {
260                 if (data->fill_rate[i] < 0)
261                         data->fill_rate[i] = 0;
262                 if (data->interval[i] <= 0)
263                         data->interval[i] = HZ;
264         }
265
266         update_mask = vxi->sched.update_mask & VXSM_SET_MASK;
267         update_mask |= (set_mask & (VXSM_SET_MASK|VXSM_IDLE_TIME));
268         vxi->sched.update_mask = update_mask;
269 #ifdef  CONFIG_SMP
270         rmb();
271         if (set_mask & VXSM_CPU_ID) {
272                 vxi->sched.update = cpumask_of_cpu(data->cpu_id);
273                 cpus_and(vxi->sched.update, cpu_online_map,
274                         vxi->sched.update);
275         }
276         else
277                 vxi->sched.update = cpu_online_map;
278
279         /* forced reload? */
280         if (set_mask & VXSM_FORCE) {
281                 for_each_cpu_mask(cpu, vxi->sched.update)
282                         vx_update_sched_param(&vxi->sched,
283                                 &vx_per_cpu(vxi, sched_pc, cpu));
284                 vxi->sched.update = CPU_MASK_NONE;
285         }
286 #else
287         /* on UP we update immediately */
288         vx_update_sched_param(&vxi->sched,
289                 &vx_per_cpu(vxi, sched_pc, 0));
290 #endif
291
292         spin_unlock(&vxi->sched.tokens_lock);
293         return 0;
294 }
295
296 #define COPY_IDS(C) C(cpu_id); C(bucket_id)
297 #define COPY_PRI(C) C(prio_bias)
298 #define COPY_TOK(C) C(tokens); C(tokens_min); C(tokens_max)
299 #define COPY_FRI(C) C(fill_rate[0]); C(interval[0]);    \
300                     C(fill_rate[1]); C(interval[1]);
301
302 #define COPY_VALUE(name) vc_data.name = data->name
303
304 static int do_set_sched_v4(struct vx_info *vxi, struct vcmd_set_sched_v4 *data)
305 {
306         struct vcmd_sched_v5 vc_data;
307
308         vc_data.mask = data->set_mask;
309         COPY_IDS(COPY_VALUE);
310         COPY_PRI(COPY_VALUE);
311         COPY_TOK(COPY_VALUE);
312         vc_data.fill_rate[0] = vc_data.fill_rate[1] = data->fill_rate;
313         vc_data.interval[0] = vc_data.interval[1] = data->interval;
314         return do_set_sched(vxi, &vc_data);
315 }
316
317 #ifdef  CONFIG_VSERVER_LEGACY
318
319 #define COPY_MASK_V2(name, mask)                        \
320         if (vc_data.name != SCHED_KEEP) {               \
321                 vc_data_v4.name = vc_data.name;         \
322                 vc_data_v4.set_mask |= mask;            \
323         }
324
325 int vc_set_sched_v2(struct vx_info *vxi, void __user *data)
326 {
327         struct vcmd_set_sched_v2 vc_data;
328         struct vcmd_set_sched_v4 vc_data_v4 = { .set_mask = 0 };
329
330         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
331                 return -EFAULT;
332
333         COPY_MASK_V2(fill_rate,  VXSM_FILL_RATE);
334         COPY_MASK_V2(interval,   VXSM_INTERVAL);
335         COPY_MASK_V2(tokens,     VXSM_TOKENS);
336         COPY_MASK_V2(tokens_min, VXSM_TOKENS_MIN);
337         COPY_MASK_V2(tokens_max, VXSM_TOKENS_MAX);
338         vc_data_v4.bucket_id = 0;
339
340         do_set_sched_v4(vxi, &vc_data_v4);
341         return 0;
342 }
343 #endif
344
345 int vc_set_sched_v3(struct vx_info *vxi, void __user *data)
346 {
347         struct vcmd_set_sched_v3 vc_data;
348         struct vcmd_set_sched_v4 vc_data_v4;
349
350         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
351                 return -EFAULT;
352
353         /* structures are binary compatible */
354         memcpy(&vc_data_v4, &vc_data, sizeof(vc_data));
355         vc_data_v4.set_mask &= VXSM_V3_MASK;
356         vc_data_v4.bucket_id = 0;
357
358         return do_set_sched_v4(vxi, &vc_data_v4);
359 }
360
361 int vc_set_sched_v4(struct vx_info *vxi, void __user *data)
362 {
363         struct vcmd_set_sched_v4 vc_data;
364
365         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
366                 return -EFAULT;
367
368         return do_set_sched_v4(vxi, &vc_data);
369 }
370
371         /* latest interface is v5 */
372
373 int vc_set_sched(struct vx_info *vxi, void __user *data)
374 {
375         struct vcmd_sched_v5 vc_data;
376
377         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
378                 return -EFAULT;
379
380         return do_set_sched(vxi, &vc_data);
381 }
382
383
384 int vc_get_sched(struct vx_info *vxi, void __user *data)
385 {
386         struct vcmd_sched_v5 vc_data;
387
388         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
389                 return -EFAULT;
390
391         if (vc_data.mask & VXSM_CPU_ID) {
392                 int cpu = vc_data.cpu_id;
393                 struct _vx_sched_pc *data;
394
395                 if (!cpu_possible(cpu))
396                         return -EINVAL;
397
398                 data = &vx_per_cpu(vxi, sched_pc, cpu);
399                 COPY_TOK(COPY_VALUE);
400                 COPY_PRI(COPY_VALUE);
401                 COPY_FRI(COPY_VALUE);
402
403                 if (data->flags & VXSF_IDLE_TIME)
404                         vc_data.mask |= VXSM_IDLE_TIME;
405         } else {
406                 struct _vx_sched *data = &vxi->sched;
407
408                 COPY_TOK(COPY_VALUE);
409                 COPY_PRI(COPY_VALUE);
410                 COPY_FRI(COPY_VALUE);
411         }
412
413         if (vc_data.mask & VXSM_MSEC) {
414                 vc_data.interval[0] = ticks_to_msec(vc_data.interval[0]);
415                 vc_data.interval[1] = ticks_to_msec(vc_data.interval[1]);
416         }
417
418         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
419                 return -EFAULT;
420         return 0;
421 }
422
423
424 int vc_sched_info(struct vx_info *vxi, void __user *data)
425 {
426         struct vcmd_sched_info vc_data;
427         int cpu;
428
429         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
430                 return -EFAULT;
431
432         cpu = vc_data.cpu_id;
433         if (!cpu_possible(cpu))
434                 return -EINVAL;
435
436         if (vxi) {
437                 struct _vx_sched_pc *sched_pc =
438                         &vx_per_cpu(vxi, sched_pc, cpu);
439
440                 vc_data.user_msec = ticks_to_msec(sched_pc->user_ticks);
441                 vc_data.sys_msec = ticks_to_msec(sched_pc->sys_ticks);
442                 vc_data.hold_msec = ticks_to_msec(sched_pc->hold_ticks);
443                 vc_data.vavavoom = sched_pc->vavavoom;
444         }
445         vc_data.token_usec = ticks_to_usec(1);
446
447         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
448                 return -EFAULT;
449         return 0;
450 }
451