951fe6c66cff1b25701dc6b0f275bf454571c18d
[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-2007  Herbert Pƶtzl
7  *
8  *  V0.01  broken out from limit.c
9  *  V0.02  added utsname stuff
10  *  V0.03  changed vcmds to vxi arg
11  *
12  */
13
14 #include <linux/sched.h>
15 #include <linux/sysctl.h>
16 #include <linux/types.h>
17 #include <linux/vs_base.h>
18 #include <linux/vs_context.h>
19 #include <linux/vs_cvirt.h>
20 #include <linux/vserver/switch.h>
21 #include <linux/vserver/cvirt_cmd.h>
22
23 #include <asm/errno.h>
24 #include <asm/uaccess.h>
25
26
27 void vx_vsi_uptime(struct timespec *uptime, struct timespec *idle)
28 {
29         struct vx_info *vxi = current->vx_info;
30
31         set_normalized_timespec(uptime,
32                 uptime->tv_sec - vxi->cvirt.bias_uptime.tv_sec,
33                 uptime->tv_nsec - vxi->cvirt.bias_uptime.tv_nsec);
34         if (!idle)
35                 return;
36         set_normalized_timespec(idle,
37                 idle->tv_sec - vxi->cvirt.bias_idle.tv_sec,
38                 idle->tv_nsec - vxi->cvirt.bias_idle.tv_nsec);
39         return;
40 }
41
42 uint64_t vx_idle_jiffies(void)
43 {
44         return init_task.utime + init_task.stime;
45 }
46
47
48
49 static inline uint32_t __update_loadavg(uint32_t load,
50         int wsize, int delta, int n)
51 {
52         unsigned long long calc, prev;
53
54         /* just set it to n */
55         if (unlikely(delta >= wsize))
56                 return (n << FSHIFT);
57
58         calc = delta * n;
59         calc <<= FSHIFT;
60         prev = (wsize - delta);
61         prev *= load;
62         calc += prev;
63         do_div(calc, wsize);
64         return calc;
65 }
66
67
68 void vx_update_load(struct vx_info *vxi)
69 {
70         uint32_t now, last, delta;
71         unsigned int nr_running, nr_uninterruptible;
72         unsigned int total;
73         unsigned long flags;
74
75         spin_lock_irqsave(&vxi->cvirt.load_lock, flags);
76
77         now = jiffies;
78         last = vxi->cvirt.load_last;
79         delta = now - last;
80
81         if (delta < 5*HZ)
82                 goto out;
83
84         nr_running = atomic_read(&vxi->cvirt.nr_running);
85         nr_uninterruptible = atomic_read(&vxi->cvirt.nr_uninterruptible);
86         total = nr_running + nr_uninterruptible;
87
88         vxi->cvirt.load[0] = __update_loadavg(vxi->cvirt.load[0],
89                 60*HZ, delta, total);
90         vxi->cvirt.load[1] = __update_loadavg(vxi->cvirt.load[1],
91                 5*60*HZ, delta, total);
92         vxi->cvirt.load[2] = __update_loadavg(vxi->cvirt.load[2],
93                 15*60*HZ, delta, total);
94
95         vxi->cvirt.load_last = now;
96 out:
97         atomic_inc(&vxi->cvirt.load_updates);
98         spin_unlock_irqrestore(&vxi->cvirt.load_lock, flags);
99 }
100
101
102 /*
103  * Commands to do_syslog:
104  *
105  *      0 -- Close the log.  Currently a NOP.
106  *      1 -- Open the log. Currently a NOP.
107  *      2 -- Read from the log.
108  *      3 -- Read all messages remaining in the ring buffer.
109  *      4 -- Read and clear all messages remaining in the ring buffer
110  *      5 -- Clear ring buffer.
111  *      6 -- Disable printk's to console
112  *      7 -- Enable printk's to console
113  *      8 -- Set level of messages printed to console
114  *      9 -- Return number of unread characters in the log buffer
115  *     10 -- Return size of the log buffer
116  */
117 int vx_do_syslog(int type, char __user *buf, int len)
118 {
119         int error = 0;
120         int do_clear = 0;
121         struct vx_info *vxi = current->vx_info;
122         struct _vx_syslog *log;
123
124         if (!vxi)
125                 return -EINVAL;
126         log = &vxi->cvirt.syslog;
127
128         switch (type) {
129         case 0:         /* Close log */
130         case 1:         /* Open log */
131                 break;
132         case 2:         /* Read from log */
133                 error = wait_event_interruptible(log->log_wait,
134                         (log->log_start - log->log_end));
135                 if (error)
136                         break;
137                 spin_lock_irq(&log->logbuf_lock);
138                 spin_unlock_irq(&log->logbuf_lock);
139                 break;
140         case 4:         /* Read/clear last kernel messages */
141                 do_clear = 1;
142                 /* fall through */
143         case 3:         /* Read last kernel messages */
144                 return 0;
145
146         case 5:         /* Clear ring buffer */
147                 return 0;
148
149         case 6:         /* Disable logging to console */
150         case 7:         /* Enable logging to console */
151         case 8:         /* Set level of messages printed to console */
152                 break;
153
154         case 9:         /* Number of chars in the log buffer */
155                 return 0;
156         case 10:        /* Size of the log buffer */
157                 return 0;
158         default:
159                 error = -EINVAL;
160                 break;
161         }
162         return error;
163 }
164
165
166 /* virtual host info names */
167
168 static char * vx_vhi_name(struct vx_info *vxi, int id)
169 {
170         struct nsproxy *nsproxy;
171         struct uts_namespace *uts;
172
173
174         if (id == VHIN_CONTEXT)
175                 return vxi->vx_name;
176
177         nsproxy = vxi->vx_nsproxy;
178         if (!nsproxy)
179                 return NULL;
180
181         uts = nsproxy->uts_ns;
182         if (!uts)
183                 return NULL;
184
185         switch (id) {
186         case VHIN_SYSNAME:
187                 return uts->name.sysname;
188         case VHIN_NODENAME:
189                 return uts->name.nodename;
190         case VHIN_RELEASE:
191                 return uts->name.release;
192         case VHIN_VERSION:
193                 return uts->name.version;
194         case VHIN_MACHINE:
195                 return uts->name.machine;
196         case VHIN_DOMAINNAME:
197                 return uts->name.domainname;
198         default:
199                 return NULL;
200         }
201         return NULL;
202 }
203
204 int vc_set_vhi_name(struct vx_info *vxi, void __user *data)
205 {
206         struct vcmd_vhi_name_v0 vc_data;
207         char *name;
208
209         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
210                 return -EFAULT;
211
212         name = vx_vhi_name(vxi, vc_data.field);
213         if (!name)
214                 return -EINVAL;
215
216         memcpy(name, vc_data.name, 65);
217         return 0;
218 }
219
220 int vc_get_vhi_name(struct vx_info *vxi, void __user *data)
221 {
222         struct vcmd_vhi_name_v0 vc_data;
223         char *name;
224
225         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
226                 return -EFAULT;
227
228         name = vx_vhi_name(vxi, vc_data.field);
229         if (!name)
230                 return -EINVAL;
231
232         memcpy(vc_data.name, name, 65);
233         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
234                 return -EFAULT;
235         return 0;
236 }
237
238
239 int vc_virt_stat(struct vx_info *vxi, void __user *data)
240 {
241         struct vcmd_virt_stat_v0 vc_data;
242         struct _vx_cvirt *cvirt = &vxi->cvirt;
243         struct timespec uptime;
244
245         do_posix_clock_monotonic_gettime(&uptime);
246         set_normalized_timespec(&uptime,
247                 uptime.tv_sec - cvirt->bias_uptime.tv_sec,
248                 uptime.tv_nsec - cvirt->bias_uptime.tv_nsec);
249
250         vc_data.offset = timeval_to_ns(&cvirt->bias_tv);
251         vc_data.uptime = timespec_to_ns(&uptime);
252         vc_data.nr_threads = atomic_read(&cvirt->nr_threads);
253         vc_data.nr_running = atomic_read(&cvirt->nr_running);
254         vc_data.nr_uninterruptible = atomic_read(&cvirt->nr_uninterruptible);
255         vc_data.nr_onhold = atomic_read(&cvirt->nr_onhold);
256         vc_data.nr_forks = atomic_read(&cvirt->total_forks);
257         vc_data.load[0] = cvirt->load[0];
258         vc_data.load[1] = cvirt->load[1];
259         vc_data.load[2] = cvirt->load[2];
260
261         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
262                 return -EFAULT;
263         return 0;
264 }
265
266
267 #ifdef CONFIG_VSERVER_VTIME
268
269 /* virtualized time base */
270
271 void vx_gettimeofday(struct timeval *tv)
272 {
273         do_gettimeofday(tv);
274         if (!vx_flags(VXF_VIRT_TIME, 0))
275                 return;
276
277         tv->tv_sec += current->vx_info->cvirt.bias_tv.tv_sec;
278         tv->tv_usec += current->vx_info->cvirt.bias_tv.tv_usec;
279
280         if (tv->tv_usec >= USEC_PER_SEC) {
281                 tv->tv_sec++;
282                 tv->tv_usec -= USEC_PER_SEC;
283         } else if (tv->tv_usec < 0) {
284                 tv->tv_sec--;
285                 tv->tv_usec += USEC_PER_SEC;
286         }
287 }
288
289 int vx_settimeofday(struct timespec *ts)
290 {
291         struct timeval tv;
292
293         if (!vx_flags(VXF_VIRT_TIME, 0))
294                 return do_settimeofday(ts);
295
296         do_gettimeofday(&tv);
297         current->vx_info->cvirt.bias_tv.tv_sec =
298                 ts->tv_sec - tv.tv_sec;
299         current->vx_info->cvirt.bias_tv.tv_usec =
300                 (ts->tv_nsec/NSEC_PER_USEC) - tv.tv_usec;
301         return 0;
302 }
303
304 #endif
305