backported vs2.1.x fix to irq handling, which caused incorrect scheduler behavior
[linux-2.6.git] / kernel / vserver / cvirt.c
1 /*
2  *  linux/kernel/vserver/cvirt.c
3  *
4  *  Virtual Server: Context Virtualization
5  *
6  *  Copyright (C) 2004-2005  Herbert Pƶtzl
7  *
8  *  V0.01  broken out from limit.c
9  *  V0.02  added utsname stuff
10  *
11  */
12
13 #include <linux/sched.h>
14 #include <linux/sysctl.h>
15 #include <linux/types.h>
16 #include <linux/vs_base.h>
17 #include <linux/vs_context.h>
18 #include <linux/vs_cvirt.h>
19 #include <linux/vserver/switch.h>
20 #include <linux/vserver/cvirt_cmd.h>
21
22 #include <asm/errno.h>
23 #include <asm/uaccess.h>
24
25
26 void vx_vsi_uptime(struct timespec *uptime, struct timespec *idle)
27 {
28         struct vx_info *vxi = current->vx_info;
29
30         set_normalized_timespec(uptime,
31                 uptime->tv_sec - vxi->cvirt.bias_uptime.tv_sec,
32                 uptime->tv_nsec - vxi->cvirt.bias_uptime.tv_nsec);
33         if (!idle)
34                 return;
35         set_normalized_timespec(idle,
36                 idle->tv_sec - vxi->cvirt.bias_idle.tv_sec,
37                 idle->tv_nsec - vxi->cvirt.bias_idle.tv_nsec);
38         return;
39 }
40
41 uint64_t vx_idle_jiffies(void)
42 {
43         return init_task.utime + init_task.stime;
44 }
45
46
47
48 static inline uint32_t __update_loadavg(uint32_t load,
49         int wsize, int delta, int n)
50 {
51         unsigned long long calc, prev;
52
53         /* just set it to n */
54         if (unlikely(delta >= wsize))
55                 return (n << FSHIFT);
56
57         calc = delta * n;
58         calc <<= FSHIFT;
59         prev = (wsize - delta);
60         prev *= load;
61         calc += prev;
62         do_div(calc, wsize);
63         return calc;
64 }
65
66
67 void vx_update_load(struct vx_info *vxi)
68 {
69         uint32_t now, last, delta;
70         unsigned int nr_running, nr_uninterruptible;
71         unsigned int total;
72         unsigned long flags;
73
74         spin_lock_irqsave(&vxi->cvirt.load_lock, flags);
75
76         now = jiffies;
77         last = vxi->cvirt.load_last;
78         delta = now - last;
79
80         if (delta < 5*HZ)
81                 goto out;
82
83         nr_running = atomic_read(&vxi->cvirt.nr_running);
84         nr_uninterruptible = atomic_read(&vxi->cvirt.nr_uninterruptible);
85         total = nr_running + nr_uninterruptible;
86
87         vxi->cvirt.load[0] = __update_loadavg(vxi->cvirt.load[0],
88                 60*HZ, delta, total);
89         vxi->cvirt.load[1] = __update_loadavg(vxi->cvirt.load[1],
90                 5*60*HZ, delta, total);
91         vxi->cvirt.load[2] = __update_loadavg(vxi->cvirt.load[2],
92                 15*60*HZ, delta, total);
93
94         vxi->cvirt.load_last = now;
95 out:
96         atomic_inc(&vxi->cvirt.load_updates);
97         spin_unlock_irqrestore(&vxi->cvirt.load_lock, flags);
98 }
99
100
101 int vx_uts_virt_handler(struct ctl_table *ctl, int write, xid_t xid,
102         void **datap, size_t *lenp)
103 {
104         switch (ctl->ctl_name) {
105         case KERN_OSTYPE:
106                 *datap = vx_new_uts(sysname);
107                 break;
108         case KERN_OSRELEASE:
109                 *datap = vx_new_uts(release);
110                 break;
111         case KERN_VERSION:
112                 *datap = vx_new_uts(version);
113                 break;
114         case KERN_NODENAME:
115                 *datap = vx_new_uts(nodename);
116                 break;
117         case KERN_DOMAINNAME:
118                 *datap = vx_new_uts(domainname);
119                 break;
120         }
121
122         return 0;
123 }
124
125
126
127 /*
128  * Commands to do_syslog:
129  *
130  *      0 -- Close the log.  Currently a NOP.
131  *      1 -- Open the log. Currently a NOP.
132  *      2 -- Read from the log.
133  *      3 -- Read all messages remaining in the ring buffer.
134  *      4 -- Read and clear all messages remaining in the ring buffer
135  *      5 -- Clear ring buffer.
136  *      6 -- Disable printk's to console
137  *      7 -- Enable printk's to console
138  *      8 -- Set level of messages printed to console
139  *      9 -- Return number of unread characters in the log buffer
140  *     10 -- Return size of the log buffer
141  */
142 int vx_do_syslog(int type, char __user *buf, int len)
143 {
144         int error = 0;
145         int do_clear = 0;
146         struct vx_info *vxi = current->vx_info;
147         struct _vx_syslog *log;
148
149         if (!vxi)
150                 return -EINVAL;
151         log = &vxi->cvirt.syslog;
152
153         switch (type) {
154         case 0:         /* Close log */
155         case 1:         /* Open log */
156                 break;
157         case 2:         /* Read from log */
158                 error = wait_event_interruptible(log->log_wait,
159                         (log->log_start - log->log_end));
160                 if (error)
161                         break;
162                 spin_lock_irq(&log->logbuf_lock);
163                 spin_unlock_irq(&log->logbuf_lock);
164                 break;
165         case 4:         /* Read/clear last kernel messages */
166                 do_clear = 1;
167                 /* fall through */
168         case 3:         /* Read last kernel messages */
169                 return 0;
170
171         case 5:         /* Clear ring buffer */
172                 return 0;
173
174         case 6:         /* Disable logging to console */
175         case 7:         /* Enable logging to console */
176         case 8:         /* Set level of messages printed to console */
177                 break;
178
179         case 9:         /* Number of chars in the log buffer */
180                 return 0;
181         case 10:        /* Size of the log buffer */
182                 return 0;
183         default:
184                 error = -EINVAL;
185                 break;
186         }
187         return error;
188 }
189
190
191 /* virtual host info names */
192
193 static char * vx_vhi_name(struct vx_info *vxi, int id)
194 {
195         switch (id) {
196         case VHIN_CONTEXT:
197                 return vxi->vx_name;
198         case VHIN_SYSNAME:
199                 return vxi->cvirt.utsname.sysname;
200         case VHIN_NODENAME:
201                 return vxi->cvirt.utsname.nodename;
202         case VHIN_RELEASE:
203                 return vxi->cvirt.utsname.release;
204         case VHIN_VERSION:
205                 return vxi->cvirt.utsname.version;
206         case VHIN_MACHINE:
207                 return vxi->cvirt.utsname.machine;
208         case VHIN_DOMAINNAME:
209                 return vxi->cvirt.utsname.domainname;
210         default:
211                 return NULL;
212         }
213         return NULL;
214 }
215
216 int vc_set_vhi_name(uint32_t id, void __user *data)
217 {
218         struct vx_info *vxi;
219         struct vcmd_vhi_name_v0 vc_data;
220         char *name;
221
222         if (!capable(CAP_SYS_ADMIN))
223                 return -EPERM;
224         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
225                 return -EFAULT;
226
227         vxi = lookup_vx_info(id);
228         if (!vxi)
229                 return -ESRCH;
230
231         name = vx_vhi_name(vxi, vc_data.field);
232         if (name)
233                 memcpy(name, vc_data.name, 65);
234         put_vx_info(vxi);
235         return (name ? 0 : -EFAULT);
236 }
237
238 int vc_get_vhi_name(uint32_t id, void __user *data)
239 {
240         struct vx_info *vxi;
241         struct vcmd_vhi_name_v0 vc_data;
242         char *name;
243
244         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
245                 return -EFAULT;
246
247         vxi = lookup_vx_info(id);
248         if (!vxi)
249                 return -ESRCH;
250
251         name = vx_vhi_name(vxi, vc_data.field);
252         if (!name)
253                 goto out_put;
254
255         memcpy(vc_data.name, name, 65);
256         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
257                 return -EFAULT;
258 out_put:
259         put_vx_info(vxi);
260         return (name ? 0 : -EFAULT);
261 }