ia64/xen-unstable

view xen/common/dom0_ops.c @ 6068:0229efe8ffe4

Simple fix to getdomaininfo cpu_time calculation for
multi-vcpu guests. From Josh Triplett.
author kaf24@firebug.cl.cam.ac.uk
date Mon Aug 08 18:43:57 2005 +0000 (2005-08-08)
parents 217fb2d1f364
children 57b3fdca5dae d481d2776e89 dc61689b4781 c589ca6d292b
line source
1 /******************************************************************************
2 * dom0_ops.c
3 *
4 * Process command requests from domain-0 guest OS.
5 *
6 * Copyright (c) 2002, K A Fraser
7 */
9 #include <xen/config.h>
10 #include <xen/types.h>
11 #include <xen/lib.h>
12 #include <xen/mm.h>
13 #include <xen/sched.h>
14 #include <xen/domain.h>
15 #include <xen/event.h>
16 #include <xen/domain_page.h>
17 #include <xen/trace.h>
18 #include <xen/console.h>
19 #include <asm/current.h>
20 #include <public/dom0_ops.h>
21 #include <public/sched_ctl.h>
22 #include <acm/acm_hooks.h>
24 extern long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op);
25 extern void arch_getdomaininfo_ctxt(
26 struct vcpu *, struct vcpu_guest_context *);
28 static inline int is_free_domid(domid_t dom)
29 {
30 struct domain *d;
32 if ( dom >= DOMID_FIRST_RESERVED )
33 return 0;
35 if ( (d = find_domain_by_id(dom)) == NULL )
36 return 1;
38 put_domain(d);
39 return 0;
40 }
42 static void getdomaininfo(struct domain *d, dom0_getdomaininfo_t *info)
43 {
44 struct vcpu *v;
45 u64 cpu_time = 0;
46 int vcpu_count = 0;
47 int flags = DOMFLAGS_PAUSED | DOMFLAGS_BLOCKED;
49 info->domain = d->domain_id;
51 memset(&info->vcpu_to_cpu, -1, sizeof(info->vcpu_to_cpu));
52 memset(&info->cpumap, 0, sizeof(info->cpumap));
54 /*
55 * - domain is marked as paused or blocked only if all its vcpus
56 * are paused or blocked
57 * - domain is marked as running if any of its vcpus is running
58 * - only map vcpus that aren't down. Note, at some point we may
59 * wish to demux the -1 value to indicate down vs. not-ever-booted
60 *
61 */
62 for_each_vcpu ( d, v ) {
63 /* only map vcpus that are up */
64 if ( !(test_bit(_VCPUF_down, &v->vcpu_flags)) )
65 info->vcpu_to_cpu[v->vcpu_id] = v->processor;
66 info->cpumap[v->vcpu_id] = v->cpumap;
67 if ( !(v->vcpu_flags & VCPUF_ctrl_pause) )
68 flags &= ~DOMFLAGS_PAUSED;
69 if ( !(v->vcpu_flags & VCPUF_blocked) )
70 flags &= ~DOMFLAGS_BLOCKED;
71 if ( v->vcpu_flags & VCPUF_running )
72 flags |= DOMFLAGS_RUNNING;
73 cpu_time += v->cpu_time;
74 vcpu_count++;
75 }
77 info->cpu_time = cpu_time;
78 info->n_vcpu = vcpu_count;
80 info->flags = flags |
81 ((d->domain_flags & DOMF_dying) ? DOMFLAGS_DYING : 0) |
82 ((d->domain_flags & DOMF_shutdown) ? DOMFLAGS_SHUTDOWN : 0) |
83 d->shutdown_code << DOMFLAGS_SHUTDOWNSHIFT;
85 if (d->ssid != NULL)
86 info->ssidref = ((struct acm_ssid_domain *)d->ssid)->ssidref;
87 else
88 info->ssidref = ACM_DEFAULT_SSID;
90 info->tot_pages = d->tot_pages;
91 info->max_pages = d->max_pages;
92 info->shared_info_frame = __pa(d->shared_info) >> PAGE_SHIFT;
93 }
95 long do_dom0_op(dom0_op_t *u_dom0_op)
96 {
97 long ret = 0;
98 dom0_op_t curop, *op = &curop;
99 void *ssid = NULL; /* save security ptr between pre and post/fail hooks */
101 if ( !IS_PRIV(current->domain) )
102 return -EPERM;
104 if ( copy_from_user(op, u_dom0_op, sizeof(*op)) )
105 return -EFAULT;
107 if ( op->interface_version != DOM0_INTERFACE_VERSION )
108 return -EACCES;
110 if ( acm_pre_dom0_op(op, &ssid) )
111 return -EACCES;
113 switch ( op->cmd )
114 {
116 case DOM0_SETDOMAININFO:
117 {
118 struct domain *d = find_domain_by_id(op->u.setdomaininfo.domain);
119 ret = -ESRCH;
120 if ( d != NULL )
121 {
122 ret = set_info_guest(d, &op->u.setdomaininfo);
123 put_domain(d);
124 }
125 }
126 break;
128 case DOM0_PAUSEDOMAIN:
129 {
130 struct domain *d = find_domain_by_id(op->u.pausedomain.domain);
131 ret = -ESRCH;
132 if ( d != NULL )
133 {
134 ret = -EINVAL;
135 if ( d != current->domain )
136 {
137 domain_pause_by_systemcontroller(d);
138 ret = 0;
139 }
140 put_domain(d);
141 }
142 }
143 break;
145 case DOM0_UNPAUSEDOMAIN:
146 {
147 struct domain *d = find_domain_by_id(op->u.unpausedomain.domain);
148 ret = -ESRCH;
149 if ( d != NULL )
150 {
151 ret = -EINVAL;
152 if ( (d != current->domain) &&
153 test_bit(_DOMF_constructed, &d->domain_flags) )
154 {
155 domain_unpause_by_systemcontroller(d);
156 ret = 0;
157 }
158 put_domain(d);
159 }
160 }
161 break;
163 case DOM0_CREATEDOMAIN:
164 {
165 struct domain *d;
166 unsigned int pro;
167 domid_t dom;
168 struct vcpu *v;
169 unsigned int i, cnt[NR_CPUS] = { 0 };
170 static spinlock_t alloc_lock = SPIN_LOCK_UNLOCKED;
171 static domid_t rover = 0;
173 spin_lock(&alloc_lock);
175 dom = op->u.createdomain.domain;
176 if ( (dom > 0) && (dom < DOMID_FIRST_RESERVED) )
177 {
178 ret = -EINVAL;
179 if ( !is_free_domid(dom) )
180 goto alloc_out;
181 }
182 else
183 {
184 for ( dom = rover + 1; dom != rover; dom++ )
185 {
186 if ( dom == DOMID_FIRST_RESERVED )
187 dom = 0;
188 if ( is_free_domid(dom) )
189 break;
190 }
192 ret = -ENOMEM;
193 if ( dom == rover )
194 goto alloc_out;
196 rover = dom;
197 }
199 /* Do an initial CPU placement. Pick the least-populated CPU. */
200 read_lock(&domlist_lock);
201 for_each_domain ( d )
202 for_each_vcpu ( d, v )
203 cnt[v->processor]++;
204 read_unlock(&domlist_lock);
206 /*
207 * If we're on a HT system, we only use the first HT for dom0, other
208 * domains will all share the second HT of each CPU. Since dom0 is on
209 * CPU 0, we favour high numbered CPUs in the event of a tie.
210 */
211 pro = smp_num_siblings - 1;
212 for ( i = pro; i < num_online_cpus(); i += smp_num_siblings )
213 if ( cnt[i] <= cnt[pro] )
214 pro = i;
216 ret = -ENOMEM;
217 if ( (d = do_createdomain(dom, pro)) == NULL )
218 goto alloc_out;
220 ret = 0;
222 op->u.createdomain.domain = d->domain_id;
223 copy_to_user(u_dom0_op, op, sizeof(*op));
225 alloc_out:
226 spin_unlock(&alloc_lock);
227 }
228 break;
230 case DOM0_DESTROYDOMAIN:
231 {
232 struct domain *d = find_domain_by_id(op->u.destroydomain.domain);
233 ret = -ESRCH;
234 if ( d != NULL )
235 {
236 ret = -EINVAL;
237 if ( d != current->domain )
238 {
239 domain_kill(d);
240 ret = 0;
241 }
242 put_domain(d);
243 }
244 }
245 break;
247 case DOM0_PINCPUDOMAIN:
248 {
249 domid_t dom = op->u.pincpudomain.domain;
250 struct domain *d = find_domain_by_id(dom);
251 struct vcpu *v;
252 cpumap_t cpumap;
255 if ( d == NULL )
256 {
257 ret = -ESRCH;
258 break;
259 }
261 if ( (op->u.pincpudomain.vcpu >= MAX_VIRT_CPUS) ||
262 !d->vcpu[op->u.pincpudomain.vcpu] )
263 {
264 ret = -EINVAL;
265 put_domain(d);
266 break;
267 }
269 v = d->vcpu[op->u.pincpudomain.vcpu];
270 if ( v == NULL )
271 {
272 ret = -ESRCH;
273 put_domain(d);
274 break;
275 }
277 if ( v == current )
278 {
279 ret = -EINVAL;
280 put_domain(d);
281 break;
282 }
284 if ( copy_from_user(&cpumap, op->u.pincpudomain.cpumap,
285 sizeof(cpumap)) )
286 {
287 ret = -EFAULT;
288 put_domain(d);
289 break;
290 }
292 /* update cpumap for this vcpu */
293 v->cpumap = cpumap;
295 if ( cpumap == CPUMAP_RUNANYWHERE )
296 clear_bit(_VCPUF_cpu_pinned, &v->vcpu_flags);
297 else
298 {
299 /* pick a new cpu from the usable map */
300 int new_cpu = (int)find_first_set_bit(cpumap) % num_online_cpus();
302 vcpu_pause(v);
303 if ( v->processor != new_cpu )
304 set_bit(_VCPUF_cpu_migrated, &v->vcpu_flags);
305 set_bit(_VCPUF_cpu_pinned, &v->vcpu_flags);
306 v->processor = new_cpu;
307 vcpu_unpause(v);
308 }
310 put_domain(d);
311 }
312 break;
314 case DOM0_SCHEDCTL:
315 {
316 ret = sched_ctl(&op->u.schedctl);
317 copy_to_user(u_dom0_op, op, sizeof(*op));
318 }
319 break;
321 case DOM0_ADJUSTDOM:
322 {
323 ret = sched_adjdom(&op->u.adjustdom);
324 copy_to_user(u_dom0_op, op, sizeof(*op));
325 }
326 break;
328 case DOM0_GETDOMAININFO:
329 {
330 struct domain *d;
332 read_lock(&domlist_lock);
334 for_each_domain ( d )
335 {
336 if ( d->domain_id >= op->u.getdomaininfo.domain )
337 break;
338 }
340 if ( (d == NULL) || !get_domain(d) )
341 {
342 read_unlock(&domlist_lock);
343 ret = -ESRCH;
344 break;
345 }
347 read_unlock(&domlist_lock);
349 getdomaininfo(d, &op->u.getdomaininfo);
351 if ( copy_to_user(u_dom0_op, op, sizeof(*op)) )
352 ret = -EINVAL;
354 put_domain(d);
355 }
356 break;
358 case DOM0_GETDOMAININFOLIST:
359 {
360 struct domain *d;
361 dom0_getdomaininfo_t info;
362 dom0_getdomaininfo_t *buffer = op->u.getdomaininfolist.buffer;
363 u32 num_domains = 0;
365 read_lock(&domlist_lock);
367 for_each_domain ( d )
368 {
369 if ( d->domain_id < op->u.getdomaininfolist.first_domain )
370 continue;
371 if ( num_domains == op->u.getdomaininfolist.max_domains )
372 break;
373 if ( (d == NULL) || !get_domain(d) )
374 {
375 ret = -ESRCH;
376 break;
377 }
379 getdomaininfo(d, &info);
381 put_domain(d);
383 if ( copy_to_user(buffer, &info, sizeof(dom0_getdomaininfo_t)) )
384 {
385 ret = -EINVAL;
386 break;
387 }
389 buffer++;
390 num_domains++;
391 }
393 read_unlock(&domlist_lock);
395 if ( ret != 0 )
396 break;
398 op->u.getdomaininfolist.num_domains = num_domains;
400 if ( copy_to_user(u_dom0_op, op, sizeof(*op)) )
401 ret = -EINVAL;
402 }
403 break;
405 case DOM0_GETVCPUCONTEXT:
406 {
407 struct vcpu_guest_context *c;
408 struct domain *d;
409 struct vcpu *v;
410 int i;
412 d = find_domain_by_id(op->u.getvcpucontext.domain);
413 if ( d == NULL )
414 {
415 ret = -ESRCH;
416 break;
417 }
419 if ( op->u.getvcpucontext.vcpu >= MAX_VIRT_CPUS )
420 {
421 ret = -EINVAL;
422 put_domain(d);
423 break;
424 }
426 /* find first valid vcpu starting from request. */
427 v = NULL;
428 for ( i = op->u.getvcpucontext.vcpu; i < MAX_VIRT_CPUS; i++ )
429 {
430 v = d->vcpu[i];
431 if ( v != NULL && !(test_bit(_VCPUF_down, &v->vcpu_flags)) )
432 break;
433 }
435 if ( v == NULL )
436 {
437 ret = -ESRCH;
438 put_domain(d);
439 break;
440 }
442 op->u.getvcpucontext.cpu_time = v->cpu_time;
444 if ( op->u.getvcpucontext.ctxt != NULL )
445 {
446 if ( (c = xmalloc(struct vcpu_guest_context)) == NULL )
447 {
448 ret = -ENOMEM;
449 put_domain(d);
450 break;
451 }
453 if ( v != current )
454 vcpu_pause(v);
456 arch_getdomaininfo_ctxt(v,c);
458 if ( v != current )
459 vcpu_unpause(v);
461 if ( copy_to_user(op->u.getvcpucontext.ctxt, c, sizeof(*c)) )
462 ret = -EINVAL;
464 xfree(c);
465 }
467 if ( copy_to_user(u_dom0_op, op, sizeof(*op)) )
468 ret = -EINVAL;
470 put_domain(d);
471 }
472 break;
474 case DOM0_SETTIME:
475 {
476 do_settime(op->u.settime.secs,
477 op->u.settime.nsecs,
478 op->u.settime.system_time);
479 ret = 0;
480 }
481 break;
483 #ifdef TRACE_BUFFER
484 case DOM0_TBUFCONTROL:
485 {
486 ret = tb_control(&op->u.tbufcontrol);
487 copy_to_user(u_dom0_op, op, sizeof(*op));
488 }
489 break;
490 #endif
492 case DOM0_READCONSOLE:
493 {
494 ret = read_console_ring(
495 &op->u.readconsole.buffer,
496 &op->u.readconsole.count,
497 op->u.readconsole.clear);
498 copy_to_user(u_dom0_op, op, sizeof(*op));
499 }
500 break;
502 case DOM0_SCHED_ID:
503 {
504 op->u.sched_id.sched_id = sched_id();
505 copy_to_user(u_dom0_op, op, sizeof(*op));
506 ret = 0;
507 }
508 break;
510 case DOM0_SETDOMAINMAXMEM:
511 {
512 struct domain *d;
513 ret = -ESRCH;
514 d = find_domain_by_id(op->u.setdomainmaxmem.domain);
515 if ( d != NULL )
516 {
517 d->max_pages = op->u.setdomainmaxmem.max_memkb >> (PAGE_SHIFT-10);
518 put_domain(d);
519 ret = 0;
520 }
521 }
522 break;
524 #ifdef PERF_COUNTERS
525 case DOM0_PERFCCONTROL:
526 {
527 extern int perfc_control(dom0_perfccontrol_t *);
528 ret = perfc_control(&op->u.perfccontrol);
529 copy_to_user(u_dom0_op, op, sizeof(*op));
530 }
531 break;
532 #endif
534 default:
535 ret = arch_do_dom0_op(op,u_dom0_op);
537 }
538 if (!ret)
539 acm_post_dom0_op(op, ssid);
540 else
541 acm_fail_dom0_op(op, ssid);
542 return ret;
543 }
545 /*
546 * Local variables:
547 * mode: C
548 * c-set-style: "BSD"
549 * c-basic-offset: 4
550 * tab-width: 4
551 * indent-tabs-mode: nil
552 * End:
553 */