debuggers.hg

view tools/libxl/libxl.c @ 22319:063927551e9c

tools: cpupools: xl: commands and library changes

Support of cpu pools in libxl and xl:
library functions
xl cpupool-create
xl cpupool-list
xl cpupool-destroy
xl cpupool-cpu-add
xl cpupool-cpu-remove
xl cpupool-migrate
Renamed all cpu pool related names to *cpupool*

Signed-off-by: juergen.gross@ts.fujitsu.com
Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
author Juergen Gross <juergen.gross@ts.fujitsu.com>
date Thu Oct 21 18:36:22 2010 +0100 (2010-10-21)
parents ee0e2acc0d99
children da9b1aa3c366
line source
1 /*
2 * Copyright (C) 2009 Citrix Ltd.
3 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
4 * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published
8 * by the Free Software Foundation; version 2.1 only. with the special
9 * exception on linking described in file LICENSE.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 */
17 #include "libxl_osdeps.h"
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <sys/select.h>
26 #include <sys/wait.h>
27 #include <sys/time.h>
28 #include <signal.h>
29 #include <unistd.h> /* for write, unlink and close */
30 #include <stdint.h>
31 #include <inttypes.h>
32 #include <assert.h>
34 #include "libxl.h"
35 #include "libxl_utils.h"
36 #include "libxl_internal.h"
37 #include "flexarray.h"
39 #define PAGE_TO_MEMKB(pages) ((pages) * 4)
41 int libxl_ctx_init(libxl_ctx *ctx, int version, xentoollog_logger *lg)
42 {
43 if (version != LIBXL_VERSION)
44 return ERROR_VERSION;
45 memset(ctx, 0, sizeof(libxl_ctx));
46 ctx->lg = lg;
47 memset(&ctx->version_info, 0, sizeof(libxl_version_info));
49 ctx->xch = xc_interface_open(lg,lg,0);
50 if (!ctx->xch) {
51 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, errno,
52 "cannot open libxc handle");
53 return ERROR_FAIL;
54 }
56 ctx->xsh = xs_daemon_open();
57 if (!ctx->xsh)
58 ctx->xsh = xs_domain_open();
59 if (!ctx->xsh) {
60 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, errno,
61 "cannot connect to xenstore");
62 xc_interface_close(ctx->xch);
63 return ERROR_FAIL;
64 }
65 return 0;
66 }
68 int libxl_ctx_free(libxl_ctx *ctx)
69 {
70 if (ctx->xch) xc_interface_close(ctx->xch);
71 libxl_version_info_destroy(&ctx->version_info);
72 if (ctx->xsh) xs_daemon_close(ctx->xsh);
73 return 0;
74 }
76 void libxl_string_list_destroy(libxl_string_list *psl)
77 {
78 int i;
79 libxl_string_list sl = *psl;
81 if (!sl)
82 return;
84 for (i = 0; sl[i] != NULL; i++)
85 free(sl[i]);
86 free(sl);
87 }
89 void libxl_key_value_list_destroy(libxl_key_value_list *pkvl)
90 {
91 int i;
92 libxl_key_value_list kvl = *pkvl;
94 if (!kvl)
95 return;
97 for (i = 0; kvl[i] != NULL; i += 2) {
98 free(kvl[i]);
99 if (kvl[i + 1])
100 free(kvl[i + 1]);
101 }
102 free(kvl);
103 }
105 void libxl_cpuid_destroy(libxl_cpuid_policy_list *p_cpuid_list)
106 {
107 int i, j;
108 libxl_cpuid_policy_list cpuid_list = *p_cpuid_list;
110 if (cpuid_list == NULL)
111 return;
112 for (i = 0; cpuid_list[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++) {
113 for (j = 0; j < 4; j++)
114 if (cpuid_list[i].policy[j] != NULL)
115 free(cpuid_list[i].policy[j]);
116 }
117 return;
118 }
120 /******************************************************************************/
122 int libxl_domain_make(libxl_ctx *ctx, libxl_domain_create_info *info,
123 uint32_t *domid)
124 {
125 libxl__gc gc = LIBXL_INIT_GC(ctx);
126 int flags, ret, i, rc;
127 char *uuid_string;
128 char *rw_paths[] = { "device", "device/suspend/event-channel" , "data"};
129 char *ro_paths[] = { "cpu", "memory", "device", "error", "drivers",
130 "control", "attr", "messages" };
131 char *dom_path, *vm_path;
132 struct xs_permissions roperm[2];
133 struct xs_permissions rwperm[1];
134 xs_transaction_t t;
135 xen_domain_handle_t handle;
137 uuid_string = libxl__uuid2string(&gc, info->uuid);
138 if (!uuid_string) {
139 libxl__free_all(&gc);
140 return ERROR_NOMEM;
141 }
143 flags = info->hvm ? XEN_DOMCTL_CDF_hvm_guest : 0;
144 flags |= info->hap ? XEN_DOMCTL_CDF_hap : 0;
145 flags |= info->oos ? 0 : XEN_DOMCTL_CDF_oos_off;
146 *domid = -1;
148 /* Ultimately, handle is an array of 16 uint8_t, same as uuid */
149 libxl_uuid_copy((libxl_uuid *)handle, &info->uuid);
151 ret = xc_domain_create(ctx->xch, info->ssidref, handle, flags, domid);
152 if (ret < 0) {
153 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain creation fail");
154 libxl__free_all(&gc);
155 return ERROR_FAIL;
156 }
158 ret = xc_cpupool_movedomain(ctx->xch, info->poolid, *domid);
159 if (ret < 0) {
160 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain move fail");
161 libxl__free_all(&gc);
162 return ERROR_FAIL;
163 }
165 dom_path = libxl__xs_get_dompath(&gc, *domid);
166 if (!dom_path) {
167 libxl__free_all(&gc);
168 return ERROR_FAIL;
169 }
171 vm_path = libxl__sprintf(&gc, "/vm/%s", uuid_string);
172 if (!vm_path) {
173 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot allocate create paths");
174 libxl__free_all(&gc);
175 return ERROR_FAIL;
176 }
178 roperm[0].id = 0;
179 roperm[0].perms = XS_PERM_NONE;
180 roperm[1].id = *domid;
181 roperm[1].perms = XS_PERM_READ;
182 rwperm[0].id = *domid;
183 rwperm[0].perms = XS_PERM_NONE;
185 retry_transaction:
186 t = xs_transaction_start(ctx->xsh);
187 xs_rm(ctx->xsh, t, dom_path);
188 xs_mkdir(ctx->xsh, t, dom_path);
189 xs_set_permissions(ctx->xsh, t, dom_path, roperm, ARRAY_SIZE(roperm));
191 xs_rm(ctx->xsh, t, vm_path);
192 xs_mkdir(ctx->xsh, t, vm_path);
193 xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));
195 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/vm", dom_path), vm_path, strlen(vm_path));
196 rc = libxl_domain_rename(ctx, *domid, 0, info->name, t);
197 if (rc) {
198 libxl__free_all(&gc);
199 return rc;
200 }
202 for (i = 0; i < ARRAY_SIZE(rw_paths); i++) {
203 char *path = libxl__sprintf(&gc, "%s/%s", dom_path, rw_paths[i]);
204 xs_mkdir(ctx->xsh, t, path);
205 xs_set_permissions(ctx->xsh, t, path, rwperm, ARRAY_SIZE(rwperm));
206 }
207 for (i = 0; i < ARRAY_SIZE(ro_paths); i++) {
208 char *path = libxl__sprintf(&gc, "%s/%s", dom_path, ro_paths[i]);
209 xs_mkdir(ctx->xsh, t, path);
210 xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm));
211 }
213 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
214 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/name", vm_path), info->name, strlen(info->name));
215 if (info->poolname)
216 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/pool_name", vm_path), info->poolname, strlen(info->poolname));
218 libxl__xs_writev(&gc, t, dom_path, info->xsdata);
219 libxl__xs_writev(&gc, t, libxl__sprintf(&gc, "%s/platform", dom_path), info->platformdata);
221 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1);
223 if (!xs_transaction_end(ctx->xsh, t, 0))
224 if (errno == EAGAIN)
225 goto retry_transaction;
227 libxl__free_all(&gc);
228 return 0;
229 }
231 int libxl_domain_rename(libxl_ctx *ctx, uint32_t domid,
232 const char *old_name, const char *new_name,
233 xs_transaction_t trans)
234 {
235 libxl__gc gc = LIBXL_INIT_GC(ctx);
236 char *dom_path = 0;
237 const char *name_path;
238 char *got_old_name;
239 unsigned int got_old_len;
240 xs_transaction_t our_trans = 0;
241 int rc;
243 dom_path = libxl__xs_get_dompath(&gc, domid);
244 if (!dom_path) goto x_nomem;
246 name_path= libxl__sprintf(&gc, "%s/name", dom_path);
247 if (!name_path) goto x_nomem;
249 retry_transaction:
250 if (!trans) {
251 trans = our_trans = xs_transaction_start(ctx->xsh);
252 if (!our_trans) {
253 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, errno,
254 "create xs transaction for domain (re)name");
255 goto x_fail;
256 }
257 }
259 if (old_name) {
260 got_old_name = xs_read(ctx->xsh, trans, name_path, &got_old_len);
261 if (!got_old_name) {
262 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, errno, "check old name"
263 " for domain %"PRIu32" allegedly named `%s'",
264 domid, old_name);
265 goto x_fail;
266 }
267 if (strcmp(old_name, got_old_name)) {
268 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "domain %"PRIu32" allegedly named "
269 "`%s' is actually named `%s' - racing ?",
270 domid, old_name, got_old_name);
271 free(got_old_name);
272 goto x_fail;
273 }
274 free(got_old_name);
275 }
276 if (!xs_write(ctx->xsh, trans, name_path,
277 new_name, strlen(new_name))) {
278 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "failed to write new name `%s'"
279 " for domain %"PRIu32" previously named `%s'",
280 new_name, domid, old_name);
281 goto x_fail;
282 }
284 if (our_trans) {
285 if (!xs_transaction_end(ctx->xsh, our_trans, 0)) {
286 trans = our_trans = 0;
287 if (errno != EAGAIN) {
288 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "failed to commit new name `%s'"
289 " for domain %"PRIu32" previously named `%s'",
290 new_name, domid, old_name);
291 goto x_fail;
292 }
293 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "need to retry rename transaction"
294 " for domain %"PRIu32" (name_path=\"%s\", new_name=\"%s\")",
295 domid, name_path, new_name);
296 goto retry_transaction;
297 }
298 our_trans = 0;
299 }
301 rc = 0;
302 x_rc:
303 if (our_trans) xs_transaction_end(ctx->xsh, our_trans, 1);
304 libxl__free_all(&gc);
305 return rc;
307 x_fail: rc = ERROR_FAIL; goto x_rc;
308 x_nomem: rc = ERROR_NOMEM; goto x_rc;
309 }
311 int libxl_domain_build(libxl_ctx *ctx, libxl_domain_build_info *info, uint32_t domid, libxl_domain_build_state *state)
312 {
313 libxl__gc gc = LIBXL_INIT_GC(ctx);
314 char **vments = NULL, **localents = NULL;
315 struct timeval start_time;
316 int i, ret;
318 ret = libxl__build_pre(ctx, domid, info, state);
319 if (ret)
320 goto out;
322 gettimeofday(&start_time, NULL);
324 if (info->hvm) {
325 ret = libxl__build_hvm(ctx, domid, info, state);
326 if (ret)
327 goto out;
329 vments = libxl__calloc(&gc, 7, sizeof(char *));
330 vments[0] = "rtc/timeoffset";
331 vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
332 vments[2] = "image/ostype";
333 vments[3] = "hvm";
334 vments[4] = "start_time";
335 vments[5] = libxl__sprintf(&gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
336 } else {
337 ret = libxl__build_pv(ctx, domid, info, state);
338 if (ret)
339 goto out;
341 vments = libxl__calloc(&gc, 11, sizeof(char *));
342 i = 0;
343 vments[i++] = "image/ostype";
344 vments[i++] = "linux";
345 vments[i++] = "image/kernel";
346 vments[i++] = (char*) info->kernel.path;
347 vments[i++] = "start_time";
348 vments[i++] = libxl__sprintf(&gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
349 if (info->u.pv.ramdisk.path) {
350 vments[i++] = "image/ramdisk";
351 vments[i++] = (char*) info->u.pv.ramdisk.path;
352 }
353 if (info->u.pv.cmdline) {
354 vments[i++] = "image/cmdline";
355 vments[i++] = (char*) info->u.pv.cmdline;
356 }
357 }
358 ret = libxl__build_post(ctx, domid, info, state, vments, localents);
359 out:
360 libxl__file_reference_unmap(&info->kernel);
361 if (!info->hvm)
362 libxl__file_reference_unmap(&info->u.pv.ramdisk);
364 libxl__free_all(&gc);
365 return ret;
366 }
368 int libxl_domain_restore(libxl_ctx *ctx, libxl_domain_build_info *info,
369 uint32_t domid, int fd, libxl_domain_build_state *state,
370 libxl_device_model_info *dm_info)
371 {
372 libxl__gc gc = LIBXL_INIT_GC(ctx);
373 char **vments = NULL, **localents = NULL;
374 struct timeval start_time;
375 int i, ret, esave, flags;
377 ret = libxl__build_pre(ctx, domid, info, state);
378 if (ret)
379 goto out;
381 ret = libxl__domain_restore_common(ctx, domid, info, state, fd);
382 if (ret)
383 goto out;
385 gettimeofday(&start_time, NULL);
387 if (info->hvm) {
388 vments = libxl__calloc(&gc, 7, sizeof(char *));
389 vments[0] = "rtc/timeoffset";
390 vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
391 vments[2] = "image/ostype";
392 vments[3] = "hvm";
393 vments[4] = "start_time";
394 vments[5] = libxl__sprintf(&gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
395 } else {
396 vments = libxl__calloc(&gc, 11, sizeof(char *));
397 i = 0;
398 vments[i++] = "image/ostype";
399 vments[i++] = "linux";
400 vments[i++] = "image/kernel";
401 vments[i++] = (char*) info->kernel.path;
402 vments[i++] = "start_time";
403 vments[i++] = libxl__sprintf(&gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
404 if (info->u.pv.ramdisk.path) {
405 vments[i++] = "image/ramdisk";
406 vments[i++] = (char*) info->u.pv.ramdisk.path;
407 }
408 if (info->u.pv.cmdline) {
409 vments[i++] = "image/cmdline";
410 vments[i++] = (char*) info->u.pv.cmdline;
411 }
412 }
413 ret = libxl__build_post(ctx, domid, info, state, vments, localents);
414 if (ret)
415 goto out;
417 dm_info->saved_state = NULL;
418 if (info->hvm) {
419 ret = asprintf(&dm_info->saved_state,
420 "/var/lib/xen/qemu-save.%d", domid);
421 ret = (ret < 0) ? ERROR_FAIL : 0;
422 }
424 out:
425 libxl__file_reference_unmap(&info->kernel);
426 if (!info->hvm)
427 libxl__file_reference_unmap(&info->u.pv.ramdisk);
429 esave = errno;
431 flags = fcntl(fd, F_GETFL);
432 if (flags == -1) {
433 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to get flags on restore fd");
434 } else {
435 flags &= ~O_NONBLOCK;
436 if (fcntl(fd, F_SETFL, flags) == -1)
437 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to put restore fd"
438 " back to blocking mode");
439 }
441 errno = esave;
442 libxl__free_all(&gc);
443 return ret;
444 }
446 int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid)
447 {
448 libxl__gc gc = LIBXL_INIT_GC(ctx);
449 int rc = 0;
451 if (libxl__domain_is_hvm(ctx, domid)) {
452 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Called domain_resume on "
453 "non-cooperative hvm domain %u", domid);
454 rc = ERROR_NI;
455 goto out;
456 }
457 if (xc_domain_resume(ctx->xch, domid, 1)) {
458 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
459 "xc_domain_resume failed for domain %u",
460 domid);
461 rc = ERROR_FAIL;
462 goto out;
463 }
464 if (!xs_resume_domain(ctx->xsh, domid)) {
465 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
466 "xs_resume_domain failed for domain %u",
467 domid);
468 rc = ERROR_FAIL;
469 }
470 out:
471 libxl__free_all(&gc);
472 return 0;
473 }
475 /*
476 * Preserves a domain but rewrites xenstore etc to make it unique so
477 * that the domain can be restarted.
478 *
479 * Does not modify info so that it may be reused.
480 */
481 int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid,
482 libxl_domain_create_info *info, const char *name_suffix, libxl_uuid new_uuid)
483 {
484 libxl__gc gc = LIBXL_INIT_GC(ctx);
485 struct xs_permissions roperm[2];
486 xs_transaction_t t;
487 char *preserved_name;
488 char *uuid_string;
489 char *vm_path;
490 char *dom_path;
492 int rc;
494 preserved_name = libxl__sprintf(&gc, "%s%s", info->name, name_suffix);
495 if (!preserved_name) {
496 libxl__free_all(&gc);
497 return ERROR_NOMEM;
498 }
500 uuid_string = libxl__uuid2string(&gc, new_uuid);
501 if (!uuid_string) {
502 libxl__free_all(&gc);
503 return ERROR_NOMEM;
504 }
506 dom_path = libxl__xs_get_dompath(&gc, domid);
507 if (!dom_path) {
508 libxl__free_all(&gc);
509 return ERROR_FAIL;
510 }
512 vm_path = libxl__sprintf(&gc, "/vm/%s", uuid_string);
513 if (!vm_path) {
514 libxl__free_all(&gc);
515 return ERROR_FAIL;
516 }
518 roperm[0].id = 0;
519 roperm[0].perms = XS_PERM_NONE;
520 roperm[1].id = domid;
521 roperm[1].perms = XS_PERM_READ;
523 retry_transaction:
524 t = xs_transaction_start(ctx->xsh);
526 xs_rm(ctx->xsh, t, vm_path);
527 xs_mkdir(ctx->xsh, t, vm_path);
528 xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));
530 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/vm", dom_path), vm_path, strlen(vm_path));
531 rc = libxl_domain_rename(ctx, domid, info->name, preserved_name, t);
532 if (rc) return rc;
534 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
536 if (!xs_transaction_end(ctx->xsh, t, 0))
537 if (errno == EAGAIN)
538 goto retry_transaction;
540 libxl__free_all(&gc);
541 return 0;
542 }
544 static void xcinfo2xlinfo(const xc_domaininfo_t *xcinfo,
545 libxl_dominfo *xlinfo)
546 {
547 memcpy(&(xlinfo->uuid), xcinfo->handle, sizeof(xen_domain_handle_t));
548 xlinfo->domid = xcinfo->domain;
550 xlinfo->dying = !!(xcinfo->flags&XEN_DOMINF_dying);
551 xlinfo->shutdown = !!(xcinfo->flags&XEN_DOMINF_shutdown);
552 xlinfo->paused = !!(xcinfo->flags&XEN_DOMINF_paused);
553 xlinfo->blocked = !!(xcinfo->flags&XEN_DOMINF_blocked);
554 xlinfo->running = !!(xcinfo->flags&XEN_DOMINF_running);
556 if (xlinfo->shutdown || xlinfo->dying)
557 xlinfo->shutdown_reason = (xcinfo->flags>>XEN_DOMINF_shutdownshift) & XEN_DOMINF_shutdownmask;
558 else
559 xlinfo->shutdown_reason = ~0;
561 xlinfo->current_memkb = PAGE_TO_MEMKB(xcinfo->tot_pages);
562 xlinfo->max_memkb = PAGE_TO_MEMKB(xcinfo->max_pages);
563 xlinfo->cpu_time = xcinfo->cpu_time;
564 xlinfo->vcpu_max_id = xcinfo->max_vcpu_id;
565 xlinfo->vcpu_online = xcinfo->nr_online_vcpus;
566 }
568 libxl_dominfo * libxl_list_domain(libxl_ctx *ctx, int *nb_domain)
569 {
570 libxl_dominfo *ptr;
571 int i, ret;
572 xc_domaininfo_t info[1024];
573 int size = 1024;
575 ptr = calloc(size, sizeof(libxl_dominfo));
576 if (!ptr) {
577 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "allocating domain info");
578 return NULL;
579 }
581 ret = xc_domain_getinfolist(ctx->xch, 0, 1024, info);
582 if (ret<0) {
583 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "geting domain info list");
584 return NULL;
585 }
587 for (i = 0; i < ret; i++) {
588 xcinfo2xlinfo(&info[i], &ptr[i]);
589 }
590 *nb_domain = ret;
591 return ptr;
592 }
594 int libxl_domain_info(libxl_ctx *ctx, libxl_dominfo *info_r,
595 uint32_t domid) {
596 xc_domaininfo_t xcinfo;
597 int ret;
599 ret = xc_domain_getinfolist(ctx->xch, domid, 1, &xcinfo);
600 if (ret<0) {
601 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "geting domain info list");
602 return ERROR_FAIL;
603 }
604 if (ret==0 || xcinfo.domain != domid) return ERROR_INVAL;
606 xcinfo2xlinfo(&xcinfo, info_r);
607 return 0;
608 }
610 libxl_cpupoolinfo * libxl_list_cpupool(libxl_ctx *ctx, int *nb_pool)
611 {
612 libxl_cpupoolinfo *ptr, *tmp;
613 int i, m, ncpu;
614 xc_cpupoolinfo_t *info;
615 uint32_t poolid;
617 ptr = NULL;
618 ncpu = xc_get_max_cpus(ctx->xch);
619 if (!ncpu) {
620 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting max cpu number");
621 return NULL;
622 }
624 poolid = 0;
625 for (i = 0;; i++) {
626 info = xc_cpupool_getinfo(ctx->xch, poolid);
627 if (info == NULL)
628 break;
629 tmp = realloc(ptr, (i + 1) * sizeof(libxl_cpupoolinfo));
630 if (!tmp) {
631 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "allocating cpupool info");
632 free(ptr);
633 return NULL;
634 }
635 ptr = tmp;
636 ptr[i].poolid = info->cpupool_id;
637 ptr[i].sched_id = info->sched_id;
638 ptr[i].n_dom = info->n_dom;
639 if (libxl_cpumap_alloc(&ptr[i].cpumap, ncpu))
640 break;
641 for (m = 0; m < ptr[i].cpumap.size / sizeof(*ptr[i].cpumap.map); m++)
642 ptr[i].cpumap.map[m] = (info->cpumap_size > (m * sizeof(*ptr[i].cpumap.map))) ?
643 info->cpumap[m] : 0;
644 poolid = info->cpupool_id + 1;
645 free(info);
646 }
648 *nb_pool = i;
649 return ptr;
650 }
652 /* this API call only list VM running on this host. a VM can be an aggregate of multiple domains. */
653 libxl_vminfo * libxl_list_vm(libxl_ctx *ctx, int *nb_vm)
654 {
655 libxl_vminfo *ptr;
656 int index, i, ret;
657 xc_domaininfo_t info[1024];
658 int size = 1024;
660 ptr = calloc(size, sizeof(libxl_dominfo));
661 if (!ptr)
662 return NULL;
664 ret = xc_domain_getinfolist(ctx->xch, 1, 1024, info);
665 if (ret<0) {
666 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "geting domain info list");
667 return NULL;
668 }
669 for (index = i = 0; i < ret; i++) {
670 if (libxl_is_stubdom(ctx, info[i].domain, NULL))
671 continue;
672 memcpy(&(ptr[index].uuid), info[i].handle, sizeof(xen_domain_handle_t));
673 ptr[index].domid = info[i].domain;
675 index++;
676 }
677 *nb_vm = index;
678 return ptr;
679 }
681 int libxl_domain_suspend(libxl_ctx *ctx, libxl_domain_suspend_info *info,
682 uint32_t domid, int fd)
683 {
684 int hvm = libxl__domain_is_hvm(ctx, domid);
685 int live = info != NULL && info->flags & XL_SUSPEND_LIVE;
686 int debug = info != NULL && info->flags & XL_SUSPEND_DEBUG;
687 int rc = 0;
689 libxl__domain_suspend_common(ctx, domid, fd, hvm, live, debug);
690 if (hvm)
691 rc = libxl__domain_save_device_model(ctx, domid, fd);
692 return rc;
693 }
695 int libxl_domain_pause(libxl_ctx *ctx, uint32_t domid)
696 {
697 int ret;
698 ret = xc_domain_pause(ctx->xch, domid);
699 if (ret<0) {
700 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "pausing domain %d", domid);
701 return ERROR_FAIL;
702 }
703 return 0;
704 }
706 int libxl_domain_core_dump(libxl_ctx *ctx, uint32_t domid,
707 const char *filename)
708 {
709 int ret;
710 ret = xc_domain_dumpcore(ctx->xch, domid, filename);
711 if (ret<0) {
712 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "core dumping domain %d to %s",
713 domid, filename);
714 return ERROR_FAIL;
715 }
716 return 0;
717 }
719 int libxl_domain_unpause(libxl_ctx *ctx, uint32_t domid)
720 {
721 libxl__gc gc = LIBXL_INIT_GC(ctx);
722 char *path;
723 char *state;
724 int ret, rc = 0;
726 if (libxl__domain_is_hvm(ctx, domid)) {
727 path = libxl__sprintf(&gc, "/local/domain/0/device-model/%d/state", domid);
728 state = libxl__xs_read(&gc, XBT_NULL, path);
729 if (state != NULL && !strcmp(state, "paused")) {
730 libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/0/device-model/%d/command", domid), "continue");
731 libxl__wait_for_device_model(ctx, domid, "running", NULL, NULL);
732 }
733 }
734 ret = xc_domain_unpause(ctx->xch, domid);
735 if (ret<0) {
736 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unpausing domain %d", domid);
737 rc = ERROR_FAIL;
738 }
739 libxl__free_all(&gc);
740 return rc;
741 }
743 static char *req_table[] = {
744 [0] = "poweroff",
745 [1] = "reboot",
746 [2] = "suspend",
747 [3] = "crash",
748 [4] = "halt",
749 };
751 int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid, int req)
752 {
753 libxl__gc gc = LIBXL_INIT_GC(ctx);
754 char *shutdown_path;
755 char *dom_path;
757 if (req > ARRAY_SIZE(req_table)) {
758 libxl__free_all(&gc);
759 return ERROR_INVAL;
760 }
762 dom_path = libxl__xs_get_dompath(&gc, domid);
763 if (!dom_path) {
764 libxl__free_all(&gc);
765 return ERROR_FAIL;
766 }
768 shutdown_path = libxl__sprintf(&gc, "%s/control/shutdown", dom_path);
770 xs_write(ctx->xsh, XBT_NULL, shutdown_path, req_table[req], strlen(req_table[req]));
771 if (libxl__domain_is_hvm(ctx,domid)) {
772 unsigned long acpi_s_state = 0;
773 unsigned long pvdriver = 0;
774 int ret;
775 ret = xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_ACPI_S_STATE, &acpi_s_state);
776 if (ret<0) {
777 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting ACPI S-state");
778 return ERROR_FAIL;
779 }
780 ret = xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver);
781 if (ret<0) {
782 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting HVM callback IRQ");
783 return ERROR_FAIL;
784 }
785 if (!pvdriver || acpi_s_state != 0) {
786 ret = xc_domain_shutdown(ctx->xch, domid, req);
787 if (ret<0) {
788 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unpausing domain");
789 return ERROR_FAIL;
790 }
791 }
792 }
793 libxl__free_all(&gc);
794 return 0;
795 }
797 int libxl_get_wait_fd(libxl_ctx *ctx, int *fd)
798 {
799 *fd = xs_fileno(ctx->xsh);
800 return 0;
801 }
803 int libxl_wait_for_domain_death(libxl_ctx *ctx, uint32_t domid, libxl_waiter *waiter)
804 {
805 waiter->path = strdup("@releaseDomain");
806 if (asprintf(&(waiter->token), "%d", LIBXL_EVENT_DOMAIN_DEATH) < 0)
807 return -1;
808 if (!xs_watch(ctx->xsh, waiter->path, waiter->token))
809 return -1;
810 return 0;
811 }
813 int libxl_wait_for_disk_ejects(libxl_ctx *ctx, uint32_t guest_domid, libxl_device_disk *disks, int num_disks, libxl_waiter *waiter)
814 {
815 libxl__gc gc = LIBXL_INIT_GC(ctx);
816 int i, rc = -1;
817 uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid);
819 if (!domid)
820 domid = guest_domid;
822 for (i = 0; i < num_disks; i++) {
823 if (asprintf(&(waiter[i].path), "%s/device/vbd/%d/eject",
824 libxl__xs_get_dompath(&gc, domid),
825 libxl__device_disk_dev_number(disks[i].virtpath)) < 0)
826 goto out;
827 if (asprintf(&(waiter[i].token), "%d", LIBXL_EVENT_DISK_EJECT) < 0)
828 goto out;
829 xs_watch(ctx->xsh, waiter->path, waiter->token);
830 }
831 rc = 0;
832 out:
833 libxl__free_all(&gc);
834 return rc;
835 }
837 int libxl_get_event(libxl_ctx *ctx, libxl_event *event)
838 {
839 unsigned int num;
840 char **events = xs_read_watch(ctx->xsh, &num);
841 if (num != 2) {
842 free(events);
843 return ERROR_FAIL;
844 }
845 event->path = strdup(events[XS_WATCH_PATH]);
846 event->token = strdup(events[XS_WATCH_TOKEN]);
847 event->type = atoi(event->token);
848 free(events);
849 return 0;
850 }
852 int libxl_stop_waiting(libxl_ctx *ctx, libxl_waiter *waiter)
853 {
854 if (!xs_unwatch(ctx->xsh, waiter->path, waiter->token))
855 return ERROR_FAIL;
856 else
857 return 0;
858 }
860 int libxl_free_event(libxl_event *event)
861 {
862 free(event->path);
863 free(event->token);
864 return 0;
865 }
867 int libxl_free_waiter(libxl_waiter *waiter)
868 {
869 free(waiter->path);
870 free(waiter->token);
871 return 0;
872 }
874 int libxl_event_get_domain_death_info(libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_dominfo *info)
875 {
876 if (libxl_domain_info(ctx, info, domid) < 0)
877 return 0;
879 if (info->running || (!info->shutdown && !info->dying))
880 return ERROR_INVAL;
882 return 1;
883 }
885 int libxl_event_get_disk_eject_info(libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_device_disk *disk)
886 {
887 libxl__gc gc = LIBXL_INIT_GC(ctx);
888 char *path;
889 char *backend;
890 char *value;
892 value = libxl__xs_read(&gc, XBT_NULL, event->path);
894 if (!value || strcmp(value, "eject")) {
895 libxl__free_all(&gc);
896 return 0;
897 }
899 path = strdup(event->path);
900 path[strlen(path) - 6] = '\0';
901 backend = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend", path));
903 disk->backend_domid = 0;
904 disk->domid = domid;
905 disk->physpath = NULL;
906 disk->phystype = 0;
907 /* this value is returned to the user: do not free right away */
908 disk->virtpath = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/dev", backend));
909 disk->unpluggable = 1;
910 disk->readwrite = 0;
911 disk->is_cdrom = 1;
913 free(path);
914 libxl__free_all(&gc);
915 return 1;
916 }
918 static int libxl_destroy_device_model(libxl_ctx *ctx, uint32_t domid)
919 {
920 libxl__gc gc = LIBXL_INIT_GC(ctx);
921 char *pid;
922 int ret;
924 pid = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/%d/image/device-model-pid", domid));
925 if (!pid) {
926 int stubdomid = libxl_get_stubdom_id(ctx, domid);
927 if (!stubdomid) {
928 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "Couldn't find device model's pid");
929 ret = ERROR_INVAL;
930 goto out;
931 }
932 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Device model is a stubdom, domid=%d\n", stubdomid);
933 ret = libxl_domain_destroy(ctx, stubdomid, 0);
934 if (ret)
935 goto out;
936 } else {
937 ret = kill(atoi(pid), SIGHUP);
938 if (ret < 0 && errno == ESRCH) {
939 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device Model already exited");
940 ret = 0;
941 } else if (ret == 0) {
942 LIBXL__LOG(ctx, LIBXL__LOG_DEBUG, "Device Model signaled");
943 ret = 0;
944 } else {
945 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "failed to kill Device Model [%d]",
946 atoi(pid));
947 ret = ERROR_FAIL;
948 goto out;
949 }
950 }
951 xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "/local/domain/0/device-model/%d", domid));
953 out:
954 libxl__free_all(&gc);
955 return ret;
956 }
958 int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid, int force)
959 {
960 libxl__gc gc = LIBXL_INIT_GC(ctx);
961 char *dom_path;
962 char *vm_path;
963 int rc, dm_present;
965 if (libxl__domain_is_hvm(ctx, domid)) {
966 dm_present = 1;
967 } else {
968 char *pid;
969 pid = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/%d/image/device-model-pid", domid));
970 dm_present = (pid != NULL);
971 }
973 dom_path = libxl__xs_get_dompath(&gc, domid);
974 if (!dom_path) {
975 rc = ERROR_FAIL;
976 goto out;
977 }
979 if (libxl_device_pci_shutdown(ctx, domid) < 0)
980 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "pci shutdown failed for domid %d", domid);
981 if (dm_present) {
982 xs_write(ctx->xsh, XBT_NULL,
983 libxl__sprintf(&gc, "/local/domain/0/device-model/%d/command", domid),
984 "shutdown", strlen("shutdown"));
985 }
986 rc = xc_domain_pause(ctx->xch, domid);
987 if (rc < 0) {
988 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_pause failed for %d", domid);
989 }
990 if (dm_present) {
991 if (libxl_destroy_device_model(ctx, domid) < 0)
992 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "libxl_destroy_device_model failed for %d", domid);
993 }
994 if (libxl__devices_destroy(ctx, domid, force) < 0)
995 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "libxl_destroy_devices failed for %d", domid);
997 vm_path = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dom_path));
998 if (vm_path)
999 if (!xs_rm(ctx->xsh, XBT_NULL, vm_path))
1000 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xs_rm failed for %s", vm_path);
1002 if (!xs_rm(ctx->xsh, XBT_NULL, dom_path))
1003 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xs_rm failed for %s", dom_path);
1005 libxl__userdata_destroyall(ctx, domid);
1007 rc = xc_domain_destroy(ctx->xch, domid);
1008 if (rc < 0) {
1009 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "xc_domain_destroy failed for %d", domid);
1010 rc = ERROR_FAIL;
1011 goto out;
1013 rc = 0;
1014 out:
1015 libxl__free_all(&gc);
1016 return 0;
1019 int libxl_console_exec(libxl_ctx *ctx, uint32_t domid, int cons_num, libxl_console_constype type)
1021 libxl__gc gc = LIBXL_INIT_GC(ctx);
1022 char *p = libxl__sprintf(&gc, "%s/xenconsole", libxl_private_bindir_path());
1023 char *domid_s = libxl__sprintf(&gc, "%d", domid);
1024 char *cons_num_s = libxl__sprintf(&gc, "%d", cons_num);
1025 char *cons_type_s;
1027 switch (type) {
1028 case LIBXL_CONSTYPE_PV:
1029 cons_type_s = "pv";
1030 break;
1031 case LIBXL_CONSTYPE_SERIAL:
1032 cons_type_s = "serial";
1033 break;
1034 default:
1035 goto out;
1038 execl(p, p, domid_s, "--num", cons_num_s, "--type", cons_type_s, (void *)NULL);
1040 out:
1041 libxl__free_all(&gc);
1042 return ERROR_FAIL;
1045 int libxl_primary_console_exec(libxl_ctx *ctx, uint32_t domid_vm)
1047 uint32_t stubdomid = libxl_get_stubdom_id(ctx, domid_vm);
1048 if (stubdomid)
1049 return libxl_console_exec(ctx, stubdomid, 1, LIBXL_CONSTYPE_PV);
1050 else {
1051 if (libxl__domain_is_hvm(ctx, domid_vm))
1052 return libxl_console_exec(ctx, domid_vm, 0, LIBXL_CONSTYPE_SERIAL);
1053 else
1054 return libxl_console_exec(ctx, domid_vm, 0, LIBXL_CONSTYPE_PV);
1058 int libxl_vncviewer_exec(libxl_ctx *ctx, uint32_t domid, int autopass)
1060 libxl__gc gc = LIBXL_INIT_GC(ctx);
1061 const char *vnc_port, *vfb_back;
1062 const char *vnc_listen = NULL, *vnc_pass = NULL;
1063 int port = 0, autopass_fd = -1;
1064 char *vnc_bin, *args[] = {
1065 "vncviewer",
1066 NULL, /* hostname:display */
1067 NULL, /* -autopass */
1068 NULL,
1069 };
1071 vnc_port = libxl__xs_read(&gc, XBT_NULL,
1072 libxl__sprintf(&gc,
1073 "/local/domain/%d/console/vnc-port", domid));
1074 if ( vnc_port )
1075 port = atoi(vnc_port) - 5900;
1077 vfb_back = libxl__xs_read(&gc, XBT_NULL,
1078 libxl__sprintf(&gc,
1079 "/local/domain/%d/device/vfb/0/backend", domid));
1080 if ( vfb_back ) {
1081 vnc_listen = libxl__xs_read(&gc, XBT_NULL,
1082 libxl__sprintf(&gc,
1083 "/local/domain/%d/console/vnc-listen", domid));
1084 if ( autopass )
1085 vnc_pass = libxl__xs_read(&gc, XBT_NULL,
1086 libxl__sprintf(&gc,
1087 "/local/domain/%d/console/vnc-pass", domid));
1090 if ( NULL == vnc_listen )
1091 vnc_listen = "localhost";
1093 if ( (vnc_bin = getenv("VNCVIEWER")) )
1094 args[0] = vnc_bin;
1096 args[1] = libxl__sprintf(&gc, "%s:%d", vnc_listen, port);
1098 if ( vnc_pass ) {
1099 char tmpname[] = "/tmp/vncautopass.XXXXXX";
1100 autopass_fd = mkstemp(tmpname);
1101 if ( autopass_fd < 0 )
1102 goto skip_autopass;
1104 if ( unlink(tmpname) )
1105 /* should never happen */
1106 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unlink %s failed", tmpname);
1108 if ( libxl_write_exactly(ctx, autopass_fd, vnc_pass, strlen(vnc_pass),
1109 tmpname, "vnc password") ) {
1110 do { close(autopass_fd); } while(errno == EINTR);
1111 goto skip_autopass;
1114 args[2] = "-autopass";
1117 skip_autopass:
1118 libxl__free_all(&gc);
1119 libxl__exec(autopass_fd, -1, -1, args[0], args);
1120 return 0;
1123 static char ** libxl_build_device_model_args_old(libxl__gc *gc,
1124 libxl_device_model_info *info,
1125 libxl_device_nic *vifs,
1126 int num_vifs)
1128 int num = 0, i;
1129 flexarray_t *dm_args;
1130 dm_args = flexarray_make(16, 1);
1132 if (!dm_args)
1133 return NULL;
1135 flexarray_set(dm_args, num++, "qemu-dm");
1136 flexarray_set(dm_args, num++, "-d");
1138 flexarray_set(dm_args, num++, libxl__sprintf(gc, "%d", info->domid));
1140 if (info->dom_name) {
1141 flexarray_set(dm_args, num++, "-domain-name");
1142 flexarray_set(dm_args, num++, info->dom_name);
1144 if (info->vnc || info->vncdisplay || info->vnclisten || info->vncunused) {
1145 flexarray_set(dm_args, num++, "-vnc");
1146 if (info->vncdisplay) {
1147 if (info->vnclisten && strchr(info->vnclisten, ':') == NULL) {
1148 flexarray_set(
1149 dm_args, num++,
1150 libxl__sprintf(gc, "%s:%d%s",
1151 info->vnclisten,
1152 info->vncdisplay,
1153 info->vncpasswd ? ",password" : ""));
1154 } else {
1155 flexarray_set(dm_args, num++, libxl__sprintf(gc, "127.0.0.1:%d", info->vncdisplay));
1157 } else if (info->vnclisten) {
1158 if (strchr(info->vnclisten, ':') != NULL) {
1159 flexarray_set(dm_args, num++, info->vnclisten);
1160 } else {
1161 flexarray_set(dm_args, num++, libxl__sprintf(gc, "%s:0", info->vnclisten));
1163 } else {
1164 flexarray_set(dm_args, num++, "127.0.0.1:0");
1166 if (info->vncunused) {
1167 flexarray_set(dm_args, num++, "-vncunused");
1170 if (info->sdl) {
1171 flexarray_set(dm_args, num++, "-sdl");
1172 if (!info->opengl) {
1173 flexarray_set(dm_args, num++, "-disable-opengl");
1176 if (info->keymap) {
1177 flexarray_set(dm_args, num++, "-k");
1178 flexarray_set(dm_args, num++, info->keymap);
1180 if (info->nographic && (!info->sdl && !info->vnc)) {
1181 flexarray_set(dm_args, num++, "-nographic");
1183 if (info->serial) {
1184 flexarray_set(dm_args, num++, "-serial");
1185 flexarray_set(dm_args, num++, info->serial);
1187 if (info->type == XENFV) {
1188 int ioemu_vifs = 0;
1190 if (info->videoram) {
1191 flexarray_set(dm_args, num++, "-videoram");
1192 flexarray_set(dm_args, num++, libxl__sprintf(gc, "%d", info->videoram));
1194 if (info->stdvga) {
1195 flexarray_set(dm_args, num++, "-std-vga");
1198 if (info->boot) {
1199 flexarray_set(dm_args, num++, "-boot");
1200 flexarray_set(dm_args, num++, info->boot);
1202 if (info->usb || info->usbdevice) {
1203 flexarray_set(dm_args, num++, "-usb");
1204 if (info->usbdevice) {
1205 flexarray_set(dm_args, num++, "-usbdevice");
1206 flexarray_set(dm_args, num++, info->usbdevice);
1209 if (info->soundhw) {
1210 flexarray_set(dm_args, num++, "-soundhw");
1211 flexarray_set(dm_args, num++, info->soundhw);
1213 if (info->apic) {
1214 flexarray_set(dm_args, num++, "-acpi");
1216 if (info->vcpus > 1) {
1217 flexarray_set(dm_args, num++, "-vcpus");
1218 flexarray_set(dm_args, num++, libxl__sprintf(gc, "%d", info->vcpus));
1220 if (info->vcpu_avail) {
1221 flexarray_set(dm_args, num++, "-vcpu_avail");
1222 flexarray_set(dm_args, num++, libxl__sprintf(gc, "0x%x", info->vcpu_avail));
1224 for (i = 0; i < num_vifs; i++) {
1225 if (vifs[i].nictype == NICTYPE_IOEMU) {
1226 char *smac = libxl__sprintf(gc, "%02x:%02x:%02x:%02x:%02x:%02x",
1227 vifs[i].mac[0], vifs[i].mac[1], vifs[i].mac[2],
1228 vifs[i].mac[3], vifs[i].mac[4], vifs[i].mac[5]);
1229 char *ifname;
1230 if (!vifs[i].ifname)
1231 ifname = libxl__sprintf(gc, "tap%d.%d", info->domid, vifs[i].devid);
1232 else
1233 ifname = vifs[i].ifname;
1234 flexarray_set(dm_args, num++, "-net");
1235 flexarray_set(dm_args, num++, libxl__sprintf(gc, "nic,vlan=%d,macaddr=%s,model=%s",
1236 vifs[i].devid, smac, vifs[i].model));
1237 flexarray_set(dm_args, num++, "-net");
1238 flexarray_set(dm_args, num++, libxl__sprintf(gc, "tap,vlan=%d,ifname=%s,bridge=%s,script=no",
1239 vifs[i].devid, ifname, vifs[i].bridge));
1240 ioemu_vifs++;
1243 /* If we have no emulated nics, tell qemu not to create any */
1244 if ( ioemu_vifs == 0 ) {
1245 flexarray_set(dm_args, num++, "-net");
1246 flexarray_set(dm_args, num++, "none");
1249 if (info->saved_state) {
1250 flexarray_set(dm_args, num++, "-loadvm");
1251 flexarray_set(dm_args, num++, info->saved_state);
1253 for (i = 0; info->extra && info->extra[i] != NULL; i++)
1254 flexarray_set(dm_args, num++, info->extra[i]);
1255 flexarray_set(dm_args, num++, "-M");
1256 if (info->type == XENPV)
1257 flexarray_set(dm_args, num++, "xenpv");
1258 else
1259 flexarray_set(dm_args, num++, "xenfv");
1260 flexarray_set(dm_args, num++, NULL);
1261 return (char **) flexarray_contents(dm_args);
1264 static char ** libxl_build_device_model_args_new(libxl__gc *gc,
1265 libxl_device_model_info *info,
1266 libxl_device_nic *vifs,
1267 int num_vifs)
1269 int num = 0, i;
1270 flexarray_t *dm_args;
1271 int nb;
1272 libxl_device_disk *disks;
1274 dm_args = flexarray_make(16, 1);
1275 if (!dm_args)
1276 return NULL;
1278 flexarray_set(dm_args, num++, "qemu-system-xen");
1279 flexarray_set(dm_args, num++, "-xen-domid");
1281 flexarray_set(dm_args, num++, libxl__sprintf(gc, "%d", info->domid));
1283 if (info->dom_name) {
1284 flexarray_set(dm_args, num++, "-name");
1285 flexarray_set(dm_args, num++, info->dom_name);
1287 if (info->vnc || info->vncdisplay || info->vnclisten || info->vncunused) {
1288 int display = 0;
1289 const char *listen = "127.0.0.1";
1291 flexarray_set(dm_args, num++, "-vnc");
1293 if (info->vncdisplay) {
1294 display = info->vncdisplay;
1295 if (info->vnclisten && strchr(info->vnclisten, ':') == NULL) {
1296 listen = info->vnclisten;
1298 } else if (info->vnclisten) {
1299 listen = info->vnclisten;
1302 if (strchr(listen, ':') != NULL)
1303 flexarray_set(dm_args, num++,
1304 libxl__sprintf(gc, "%s%s", listen,
1305 info->vncunused ? ",to=99" : ""));
1306 else
1307 flexarray_set(dm_args, num++,
1308 libxl__sprintf(gc, "%s:%d%s", listen, display,
1309 info->vncunused ? ",to=99" : ""));
1311 if (info->sdl) {
1312 flexarray_set(dm_args, num++, "-sdl");
1314 if (info->keymap) {
1315 flexarray_set(dm_args, num++, "-k");
1316 flexarray_set(dm_args, num++, info->keymap);
1318 if (info->nographic && (!info->sdl && !info->vnc)) {
1319 flexarray_set(dm_args, num++, "-nographic");
1321 if (info->serial) {
1322 flexarray_set(dm_args, num++, "-serial");
1323 flexarray_set(dm_args, num++, info->serial);
1325 if (info->type == XENFV) {
1326 int ioemu_vifs = 0;
1328 if (info->stdvga) {
1329 flexarray_set(dm_args, num++, "-vga");
1330 flexarray_set(dm_args, num++, "std");
1333 if (info->boot) {
1334 flexarray_set(dm_args, num++, "-boot");
1335 flexarray_set(dm_args, num++, libxl__sprintf(gc, "order=%s", info->boot));
1337 if (info->usb || info->usbdevice) {
1338 flexarray_set(dm_args, num++, "-usb");
1339 if (info->usbdevice) {
1340 flexarray_set(dm_args, num++, "-usbdevice");
1341 flexarray_set(dm_args, num++, info->usbdevice);
1344 if (info->soundhw) {
1345 flexarray_set(dm_args, num++, "-soundhw");
1346 flexarray_set(dm_args, num++, info->soundhw);
1348 if (!info->apic) {
1349 flexarray_set(dm_args, num++, "-no-acpi");
1351 if (info->vcpus > 1) {
1352 flexarray_set(dm_args, num++, "-smp");
1353 if (info->vcpu_avail)
1354 flexarray_set(dm_args, num++, libxl__sprintf(gc, "%d,maxcpus=%d", info->vcpus, info->vcpu_avail));
1355 else
1356 flexarray_set(dm_args, num++, libxl__sprintf(gc, "%d", info->vcpus));
1358 for (i = 0; i < num_vifs; i++) {
1359 if (vifs[i].nictype == NICTYPE_IOEMU) {
1360 char *smac = libxl__sprintf(gc, "%02x:%02x:%02x:%02x:%02x:%02x",
1361 vifs[i].mac[0], vifs[i].mac[1], vifs[i].mac[2],
1362 vifs[i].mac[3], vifs[i].mac[4], vifs[i].mac[5]);
1363 if (!vifs[i].ifname)
1364 vifs[i].ifname = libxl__sprintf(gc, "tap%d.%d", info->domid, vifs[i].devid);
1365 flexarray_set(dm_args, num++, "-net");
1366 flexarray_set(dm_args, num++, libxl__sprintf(gc, "nic,vlan=%d,macaddr=%s,model=%s",
1367 vifs[i].devid, smac, vifs[i].model));
1368 flexarray_set(dm_args, num++, "-net");
1369 flexarray_set(dm_args, num++, libxl__sprintf(gc, "tap,vlan=%d,ifname=%s,script=no",
1370 vifs[i].devid, vifs[i].ifname));
1371 ioemu_vifs++;
1374 /* If we have no emulated nics, tell qemu not to create any */
1375 if ( ioemu_vifs == 0 ) {
1376 flexarray_set(dm_args, num++, "-net");
1377 flexarray_set(dm_args, num++, "none");
1380 if (info->saved_state) {
1381 flexarray_set(dm_args, num++, "-loadvm");
1382 flexarray_set(dm_args, num++, info->saved_state);
1384 for (i = 0; info->extra && info->extra[i] != NULL; i++)
1385 flexarray_set(dm_args, num++, info->extra[i]);
1386 flexarray_set(dm_args, num++, "-M");
1387 if (info->type == XENPV)
1388 flexarray_set(dm_args, num++, "xenpv");
1389 else
1390 flexarray_set(dm_args, num++, "xenfv");
1392 disks = libxl_device_disk_list(libxl__gc_owner(gc), info->domid, &nb);
1393 for (i; i < nb; i++) {
1394 if ( disks[i].is_cdrom ) {
1395 flexarray_set(dm_args, num++, "-cdrom");
1396 flexarray_set(dm_args, num++, disks[i].physpath);
1397 }else{
1398 flexarray_set(dm_args, num++, libxl__sprintf(gc, "-%s", disks[i].virtpath));
1399 flexarray_set(dm_args, num++, disks[i].physpath);
1401 libxl_device_disk_destroy(&disks[i]);
1403 free(disks);
1404 flexarray_set(dm_args, num++, NULL);
1405 return (char **) flexarray_contents(dm_args);
1408 static char ** libxl_build_device_model_args(libxl__gc *gc,
1409 libxl_device_model_info *info,
1410 libxl_device_nic *vifs,
1411 int num_vifs)
1413 libxl_ctx *ctx = libxl__gc_owner(gc);
1414 int new_qemu;
1416 new_qemu = libxl_check_device_model_version(ctx, info->device_model);
1418 if (new_qemu == 1) {
1419 return libxl_build_device_model_args_new(gc, info, vifs, num_vifs);
1420 } else {
1421 return libxl_build_device_model_args_old(gc, info, vifs, num_vifs);
1425 static void dm_xenstore_record_pid(void *for_spawn, pid_t innerchild)
1427 libxl_device_model_starting *starting = for_spawn;
1428 struct xs_handle *xsh;
1429 char *path = NULL, *pid = NULL;
1430 int len;
1432 if (asprintf(&path, "%s/%s", starting->dom_path, "image/device-model-pid") < 0)
1433 goto out;
1435 len = asprintf(&pid, "%d", innerchild);
1436 if (len < 0)
1437 goto out;
1439 /* we mustn't use the parent's handle in the child */
1440 xsh = xs_daemon_open();
1442 xs_write(xsh, XBT_NULL, path, pid, len);
1444 xs_daemon_close(xsh);
1445 out:
1446 free(path);
1447 free(pid);
1450 static int libxl_vfb_and_vkb_from_device_model_info(libxl_ctx *ctx,
1451 libxl_device_model_info *info,
1452 libxl_device_vfb *vfb,
1453 libxl_device_vkb *vkb)
1455 memset(vfb, 0x00, sizeof(libxl_device_vfb));
1456 memset(vkb, 0x00, sizeof(libxl_device_vkb));
1458 vfb->backend_domid = 0;
1459 vfb->devid = 0;
1460 vfb->vnc = info->vnc;
1461 vfb->vnclisten = info->vnclisten;
1462 vfb->vncdisplay = info->vncdisplay;
1463 vfb->vncunused = info->vncunused;
1464 vfb->vncpasswd = info->vncpasswd;
1465 vfb->keymap = info->keymap;
1466 vfb->sdl = info->sdl;
1467 vfb->opengl = info->opengl;
1469 vkb->backend_domid = 0;
1470 vkb->devid = 0;
1471 return 0;
1474 static int libxl_write_dmargs(libxl_ctx *ctx, int domid, int guest_domid, char **args)
1476 libxl__gc gc = LIBXL_INIT_GC(ctx);
1477 int i;
1478 char *vm_path;
1479 char *dmargs, *path;
1480 int dmargs_size;
1481 struct xs_permissions roperm[2];
1482 xs_transaction_t t;
1484 roperm[0].id = 0;
1485 roperm[0].perms = XS_PERM_NONE;
1486 roperm[1].id = domid;
1487 roperm[1].perms = XS_PERM_READ;
1489 vm_path = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "/local/domain/%d/vm", guest_domid));
1491 i = 0;
1492 dmargs_size = 0;
1493 while (args[i] != NULL) {
1494 dmargs_size = dmargs_size + strlen(args[i]) + 1;
1495 i++;
1497 dmargs_size++;
1498 dmargs = (char *) malloc(dmargs_size);
1499 i = 1;
1500 dmargs[0] = '\0';
1501 while (args[i] != NULL) {
1502 if (strcmp(args[i], "-sdl") && strcmp(args[i], "-M") && strcmp(args[i], "xenfv")) {
1503 strcat(dmargs, " ");
1504 strcat(dmargs, args[i]);
1506 i++;
1508 path = libxl__sprintf(&gc, "%s/image/dmargs", vm_path);
1510 retry_transaction:
1511 t = xs_transaction_start(ctx->xsh);
1512 xs_write(ctx->xsh, t, path, dmargs, strlen(dmargs));
1513 xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm));
1514 xs_set_permissions(ctx->xsh, t, libxl__sprintf(&gc, "%s/rtc/timeoffset", vm_path), roperm, ARRAY_SIZE(roperm));
1515 if (!xs_transaction_end(ctx->xsh, t, 0))
1516 if (errno == EAGAIN)
1517 goto retry_transaction;
1518 free(dmargs);
1519 libxl__free_all(&gc);
1520 return 0;
1523 static int libxl_create_stubdom(libxl_ctx *ctx,
1524 libxl_device_model_info *info,
1525 libxl_device_disk *disks, int num_disks,
1526 libxl_device_nic *vifs, int num_vifs,
1527 libxl_device_vfb *vfb,
1528 libxl_device_vkb *vkb,
1529 libxl_device_model_starting **starting_r)
1531 libxl__gc gc = LIBXL_INIT_GC(ctx);
1532 int i, num_console = 1, ret;
1533 libxl_device_console *console;
1534 libxl_domain_create_info c_info;
1535 libxl_domain_build_info b_info;
1536 libxl_domain_build_state state;
1537 uint32_t domid;
1538 char **args;
1539 struct xs_permissions perm[2];
1540 xs_transaction_t t;
1541 libxl_device_model_starting *dm_starting = 0;
1543 args = libxl_build_device_model_args(&gc, info, vifs, num_vifs);
1544 if (!args) {
1545 ret = ERROR_FAIL;
1546 goto out;
1549 memset(&c_info, 0x00, sizeof(libxl_domain_create_info));
1550 c_info.hvm = 0;
1551 c_info.name = libxl__sprintf(&gc, "%s-dm", libxl__domid_to_name(&gc, info->domid));
1553 libxl_uuid_copy(&c_info.uuid, &info->uuid);
1555 memset(&b_info, 0x00, sizeof(libxl_domain_build_info));
1556 b_info.max_vcpus = 1;
1557 b_info.max_memkb = 32 * 1024;
1558 b_info.target_memkb = b_info.max_memkb;
1559 b_info.kernel.path = libxl__abs_path(&gc, "ioemu-stubdom.gz", libxl_xenfirmwaredir_path());
1560 b_info.u.pv.cmdline = libxl__sprintf(&gc, " -d %d", info->domid);
1561 b_info.u.pv.ramdisk.path = "";
1562 b_info.u.pv.features = "";
1563 b_info.hvm = 0;
1565 ret = libxl_domain_make(ctx, &c_info, &domid);
1566 if (ret)
1567 goto out_free;
1568 ret = libxl_domain_build(ctx, &b_info, domid, &state);
1569 if (ret)
1570 goto out_free;
1572 libxl_write_dmargs(ctx, domid, info->domid, args);
1573 libxl__xs_write(&gc, XBT_NULL,
1574 libxl__sprintf(&gc, "%s/image/device-model-domid", libxl__xs_get_dompath(&gc, info->domid)),
1575 "%d", domid);
1576 libxl__xs_write(&gc, XBT_NULL,
1577 libxl__sprintf(&gc, "%s/target", libxl__xs_get_dompath(&gc, domid)),
1578 "%d", info->domid);
1579 ret = xc_domain_set_target(ctx->xch, domid, info->domid);
1580 if (ret<0) {
1581 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "setting target domain %d -> %d", domid, info->domid);
1582 ret = ERROR_FAIL;
1583 goto out_free;
1585 xs_set_target(ctx->xsh, domid, info->domid);
1587 perm[0].id = domid;
1588 perm[0].perms = XS_PERM_NONE;
1589 perm[1].id = info->domid;
1590 perm[1].perms = XS_PERM_READ;
1591 retry_transaction:
1592 t = xs_transaction_start(ctx->xsh);
1593 xs_mkdir(ctx->xsh, t, libxl__sprintf(&gc, "/local/domain/0/device-model/%d", info->domid));
1594 xs_set_permissions(ctx->xsh, t, libxl__sprintf(&gc, "/local/domain/0/device-model/%d", info->domid), perm, ARRAY_SIZE(perm));
1595 xs_mkdir(ctx->xsh, t, libxl__sprintf(&gc, "/local/domain/%d/device/vfs", domid));
1596 xs_set_permissions(ctx->xsh, t, libxl__sprintf(&gc, "/local/domain/%d/device/vfs",domid), perm, ARRAY_SIZE(perm));
1597 if (!xs_transaction_end(ctx->xsh, t, 0))
1598 if (errno == EAGAIN)
1599 goto retry_transaction;
1601 for (i = 0; i < num_disks; i++) {
1602 disks[i].domid = domid;
1603 ret = libxl_device_disk_add(ctx, domid, &disks[i]);
1604 if (ret)
1605 goto out_free;
1607 for (i = 0; i < num_vifs; i++) {
1608 vifs[i].domid = domid;
1609 ret = libxl_device_nic_add(ctx, domid, &vifs[i]);
1610 if (ret)
1611 goto out_free;
1613 vfb->domid = domid;
1614 ret = libxl_device_vfb_add(ctx, domid, vfb);
1615 if (ret)
1616 goto out_free;
1617 vkb->domid = domid;
1618 ret = libxl_device_vkb_add(ctx, domid, vkb);
1619 if (ret)
1620 goto out_free;
1622 if (info->serial)
1623 num_console++;
1625 console = libxl__calloc(&gc, num_console, sizeof(libxl_device_console));
1626 if (!console) {
1627 ret = ERROR_NOMEM;
1628 goto out_free;
1631 for (i = 0; i < num_console; i++) {
1632 console[i].devid = i;
1633 console[i].consback = LIBXL_CONSBACK_IOEMU;
1634 console[i].domid = domid;
1635 if (!i) {
1636 char *filename;
1637 char *name = libxl__sprintf(&gc, "qemu-dm-%s", libxl_domid_to_name(ctx, info->domid));
1638 libxl_create_logfile(ctx, name, &filename);
1639 console[i].output = libxl__sprintf(&gc, "file:%s", filename);
1640 console[i].build_state = &state;
1641 free(filename);
1642 } else
1643 console[i].output = "pty";
1644 ret = libxl_device_console_add(ctx, domid, &console[i]);
1645 if (ret)
1646 goto out_free;
1648 if (libxl_create_xenpv_qemu(ctx, domid, vfb, &dm_starting) < 0) {
1649 ret = ERROR_FAIL;
1650 goto out_free;
1652 if (libxl_confirm_device_model_startup(ctx, dm_starting) < 0) {
1653 ret = ERROR_FAIL;
1654 goto out_free;
1657 libxl_domain_unpause(ctx, domid);
1659 if (starting_r) {
1660 *starting_r = calloc(sizeof(libxl_device_model_starting), 1);
1661 (*starting_r)->domid = info->domid;
1662 (*starting_r)->dom_path = libxl__xs_get_dompath(&gc, info->domid);
1663 (*starting_r)->for_spawn = NULL;
1666 ret = 0;
1668 out_free:
1669 free(args);
1670 out:
1671 libxl__free_all(&gc);
1672 return ret;
1675 int libxl_create_device_model(libxl_ctx *ctx,
1676 libxl_device_model_info *info,
1677 libxl_device_disk *disks, int num_disks,
1678 libxl_device_nic *vifs, int num_vifs,
1679 libxl_device_model_starting **starting_r)
1681 libxl__gc gc = LIBXL_INIT_GC(ctx);
1682 char *path, *logfile;
1683 int logfile_w, null;
1684 int rc;
1685 char **args;
1686 libxl_device_model_starting buf_starting, *p;
1687 xs_transaction_t t;
1688 char *vm_path;
1689 char **pass_stuff;
1691 if (strstr(info->device_model, "stubdom-dm")) {
1692 libxl_device_vfb vfb;
1693 libxl_device_vkb vkb;
1695 libxl_vfb_and_vkb_from_device_model_info(ctx, info, &vfb, &vkb);
1696 rc = libxl_create_stubdom(ctx, info, disks, num_disks, vifs, num_vifs, &vfb, &vkb, starting_r);
1697 goto out;
1700 args = libxl_build_device_model_args(&gc, info, vifs, num_vifs);
1701 if (!args) {
1702 rc = ERROR_FAIL;
1703 goto out;
1706 path = libxl__sprintf(&gc, "/local/domain/0/device-model/%d", info->domid);
1707 xs_mkdir(ctx->xsh, XBT_NULL, path);
1708 libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/disable_pf", path), "%d", !info->xen_platform_pci);
1710 libxl_create_logfile(ctx, libxl__sprintf(&gc, "qemu-dm-%s", info->dom_name), &logfile);
1711 logfile_w = open(logfile, O_WRONLY|O_CREAT, 0644);
1712 free(logfile);
1713 null = open("/dev/null", O_RDONLY);
1715 if (starting_r) {
1716 rc = ERROR_NOMEM;
1717 *starting_r = calloc(sizeof(libxl_device_model_starting), 1);
1718 if (!*starting_r)
1719 goto out_close;
1720 p = *starting_r;
1721 p->for_spawn = calloc(sizeof(libxl__spawn_starting), 1);
1722 } else {
1723 p = &buf_starting;
1724 p->for_spawn = NULL;
1727 p->domid = info->domid;
1728 p->dom_path = libxl__xs_get_dompath(&gc, info->domid);
1729 if (!p->dom_path) {
1730 rc = ERROR_FAIL;
1731 goto out_close;
1734 if (info->vncpasswd) {
1735 retry_transaction:
1736 /* Find uuid and the write the vnc password to xenstore for qemu. */
1737 t = xs_transaction_start(ctx->xsh);
1738 vm_path = libxl__xs_read(&gc,t,libxl__sprintf(&gc, "%s/vm", p->dom_path));
1739 if (vm_path) {
1740 /* Now write the vncpassword into it. */
1741 pass_stuff = libxl__calloc(&gc, 3, sizeof(char *));
1742 pass_stuff[0] = "vncpasswd";
1743 pass_stuff[1] = info->vncpasswd;
1744 libxl__xs_writev(&gc,t,vm_path,pass_stuff);
1745 if (!xs_transaction_end(ctx->xsh, t, 0))
1746 if (errno == EAGAIN)
1747 goto retry_transaction;
1751 rc = libxl__spawn_spawn(ctx, p, "device model", dm_xenstore_record_pid);
1752 if (rc < 0)
1753 goto out_close;
1754 if (!rc) { /* inner child */
1755 libxl__exec(null, logfile_w, logfile_w,
1756 libxl__abs_path(&gc, info->device_model, libxl_libexec_path()),
1757 args);
1760 rc = 0;
1762 out_close:
1763 close(null);
1764 close(logfile_w);
1765 free(args);
1766 out:
1767 libxl__free_all(&gc);
1768 return rc;
1771 int libxl_detach_device_model(libxl_ctx *ctx,
1772 libxl_device_model_starting *starting)
1774 int rc;
1775 rc = libxl__spawn_detach(ctx, starting->for_spawn);
1776 if (starting->for_spawn)
1777 free(starting->for_spawn);
1778 free(starting);
1779 return rc;
1783 int libxl_confirm_device_model_startup(libxl_ctx *ctx,
1784 libxl_device_model_starting *starting)
1786 int problem = libxl__wait_for_device_model(ctx, starting->domid, "running", NULL, NULL);
1787 int detach;
1788 if ( !problem )
1789 problem = libxl__spawn_check(ctx, starting->for_spawn);
1790 detach = libxl_detach_device_model(ctx, starting);
1791 return problem ? problem : detach;
1795 /******************************************************************************/
1797 int libxl_device_disk_add(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
1799 libxl__gc gc = LIBXL_INIT_GC(ctx);
1800 flexarray_t *front;
1801 flexarray_t *back;
1802 char *backend_type;
1803 unsigned int boffset = 0;
1804 unsigned int foffset = 0;
1805 int devid;
1806 libxl__device device;
1807 int major, minor, rc;
1809 front = flexarray_make(16, 1);
1810 if (!front) {
1811 rc = ERROR_NOMEM;
1812 goto out;
1814 back = flexarray_make(16, 1);
1815 if (!back) {
1816 rc = ERROR_NOMEM;
1817 goto out_free;
1820 backend_type = libxl__device_disk_backend_type_of_phystype(disk->phystype);
1821 devid = libxl__device_disk_dev_number(disk->virtpath);
1822 if (devid==-1) {
1823 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Invalid or unsupported"
1824 " virtual disk identifier %s", disk->virtpath);
1825 rc = ERROR_INVAL;
1826 goto out_free;
1829 device.backend_devid = devid;
1830 device.backend_domid = disk->backend_domid;
1831 device.devid = devid;
1832 device.domid = disk->domid;
1833 device.kind = DEVICE_VBD;
1835 switch (disk->phystype) {
1836 case PHYSTYPE_PHY: {
1838 libxl__device_physdisk_major_minor(disk->physpath, &major, &minor);
1839 flexarray_set(back, boffset++, "physical-device");
1840 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%x:%x", major, minor));
1842 flexarray_set(back, boffset++, "params");
1843 flexarray_set(back, boffset++, disk->physpath);
1845 device.backend_kind = DEVICE_VBD;
1846 break;
1848 case PHYSTYPE_FILE:
1849 /* let's pretend is tap:aio for the moment */
1850 disk->phystype = PHYSTYPE_AIO;
1851 case PHYSTYPE_AIO:
1852 case PHYSTYPE_QCOW:
1853 case PHYSTYPE_QCOW2:
1854 case PHYSTYPE_VHD:
1855 if (libxl__blktap_enabled(&gc)) {
1856 const char *dev = libxl__blktap_devpath(&gc,
1857 disk->physpath, disk->phystype);
1858 if (!dev) {
1859 rc = ERROR_FAIL;
1860 goto out_free;
1862 flexarray_set(back, boffset++, "tapdisk-params");
1863 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%s:%s", libxl__device_disk_string_of_phystype(disk->phystype), disk->physpath));
1864 flexarray_set(back, boffset++, "params");
1865 flexarray_set(back, boffset++, libxl__strdup(&gc, dev));
1866 backend_type = "phy";
1867 libxl__device_physdisk_major_minor(dev, &major, &minor);
1868 flexarray_set(back, boffset++, "physical-device");
1869 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%x:%x", major, minor));
1870 device.backend_kind = DEVICE_VBD;
1872 break;
1874 flexarray_set(back, boffset++, "params");
1875 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%s:%s",
1876 libxl__device_disk_string_of_phystype(disk->phystype), disk->physpath));
1878 device.backend_kind = DEVICE_TAP;
1879 break;
1881 default:
1882 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unrecognized disk physical type: %d\n", disk->phystype);
1883 rc = ERROR_INVAL;
1884 goto out_free;
1887 flexarray_set(back, boffset++, "frontend-id");
1888 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", disk->domid));
1889 flexarray_set(back, boffset++, "online");
1890 flexarray_set(back, boffset++, "1");
1891 flexarray_set(back, boffset++, "removable");
1892 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", (disk->unpluggable) ? 1 : 0));
1893 flexarray_set(back, boffset++, "bootable");
1894 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", 1));
1895 flexarray_set(back, boffset++, "state");
1896 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", 1));
1897 flexarray_set(back, boffset++, "dev");
1898 flexarray_set(back, boffset++, disk->virtpath);
1899 flexarray_set(back, boffset++, "type");
1900 flexarray_set(back, boffset++, backend_type);
1901 flexarray_set(back, boffset++, "mode");
1902 flexarray_set(back, boffset++, disk->readwrite ? "w" : "r");
1904 flexarray_set(front, foffset++, "backend-id");
1905 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", disk->backend_domid));
1906 flexarray_set(front, foffset++, "state");
1907 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", 1));
1908 flexarray_set(front, foffset++, "virtual-device");
1909 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", devid));
1910 flexarray_set(front, foffset++, "device-type");
1911 flexarray_set(front, foffset++, disk->is_cdrom ? "cdrom" : "disk");
1913 if (0 /* protocol != native*/) {
1914 flexarray_set(front, foffset++, "protocol");
1915 flexarray_set(front, foffset++, "x86_32-abi"); /* hardcoded ! */
1918 libxl__device_generic_add(ctx, &device,
1919 libxl__xs_kvs_of_flexarray(&gc, back, boffset),
1920 libxl__xs_kvs_of_flexarray(&gc, front, foffset));
1922 rc = 0;
1924 out_free:
1925 flexarray_free(back);
1926 flexarray_free(front);
1927 out:
1928 libxl__free_all(&gc);
1929 return rc;
1932 int libxl_device_disk_del(libxl_ctx *ctx,
1933 libxl_device_disk *disk, int wait)
1935 libxl__device device;
1936 int devid;
1938 devid = libxl__device_disk_dev_number(disk->virtpath);
1939 device.backend_domid = disk->backend_domid;
1940 device.backend_devid = devid;
1941 device.backend_kind =
1942 (disk->phystype == PHYSTYPE_PHY) ? DEVICE_VBD : DEVICE_TAP;
1943 device.domid = disk->domid;
1944 device.devid = devid;
1945 device.kind = DEVICE_VBD;
1946 return libxl__device_del(ctx, &device, wait);
1949 char * libxl_device_disk_local_attach(libxl_ctx *ctx, libxl_device_disk *disk)
1951 libxl__gc gc = LIBXL_INIT_GC(ctx);
1952 const char *dev = NULL;
1953 char *ret;
1954 int phystype = disk->phystype;
1955 switch (phystype) {
1956 case PHYSTYPE_PHY: {
1957 fprintf(stderr, "attaching PHY disk %s to domain 0\n", disk->physpath);
1958 dev = disk->physpath;
1959 break;
1961 case PHYSTYPE_FILE:
1962 /* let's pretend is tap:aio for the moment */
1963 phystype = PHYSTYPE_AIO;
1964 case PHYSTYPE_AIO:
1965 case PHYSTYPE_QCOW:
1966 case PHYSTYPE_QCOW2:
1967 case PHYSTYPE_VHD:
1968 if (libxl__blktap_enabled(&gc))
1969 dev = libxl__blktap_devpath(&gc, disk->physpath, phystype);
1970 break;
1972 default:
1973 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "unrecognized disk physical type: %d\n", phystype);
1974 break;
1976 ret = strdup(dev);
1977 libxl__free_all(&gc);
1978 return ret;
1981 int libxl_device_disk_local_detach(libxl_ctx *ctx, libxl_device_disk *disk)
1983 /* Nothing to do for PHYSTYPE_PHY. */
1985 /*
1986 * For other device types assume that the blktap2 process is
1987 * needed by the soon to be started domain and do nothing.
1988 */
1990 return 0;
1993 /******************************************************************************/
1994 int libxl_device_nic_add(libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
1996 libxl__gc gc = LIBXL_INIT_GC(ctx);
1997 flexarray_t *front;
1998 flexarray_t *back;
1999 unsigned int boffset = 0;
2000 unsigned int foffset = 0;
2001 libxl__device device;
2002 char *dompath, **l;
2003 unsigned int nb, rc;
2005 front = flexarray_make(16, 1);
2006 if (!front) {
2007 rc = ERROR_NOMEM;
2008 goto out;
2010 back = flexarray_make(16, 1);
2011 if (!back) {
2012 rc = ERROR_NOMEM;
2013 goto out_free;
2016 if (nic->devid == -1) {
2017 if (!(dompath = libxl__xs_get_dompath(&gc, domid))) {
2018 rc = ERROR_FAIL;
2019 goto out_free;
2021 if (!(l = libxl__xs_directory(&gc, XBT_NULL,
2022 libxl__sprintf(&gc, "%s/device/vif", dompath), &nb))) {
2023 nic->devid = 0;
2024 } else {
2025 nic->devid = strtoul(l[nb - 1], NULL, 10) + 1;
2029 device.backend_devid = nic->devid;
2030 device.backend_domid = nic->backend_domid;
2031 device.backend_kind = DEVICE_VIF;
2032 device.devid = nic->devid;
2033 device.domid = nic->domid;
2034 device.kind = DEVICE_VIF;
2036 flexarray_set(back, boffset++, "frontend-id");
2037 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", nic->domid));
2038 flexarray_set(back, boffset++, "online");
2039 flexarray_set(back, boffset++, "1");
2040 flexarray_set(back, boffset++, "state");
2041 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", 1));
2042 flexarray_set(back, boffset++, "script");
2043 flexarray_set(back, boffset++, nic->script);
2044 flexarray_set(back, boffset++, "mac");
2045 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%02x:%02x:%02x:%02x:%02x:%02x",
2046 nic->mac[0], nic->mac[1], nic->mac[2],
2047 nic->mac[3], nic->mac[4], nic->mac[5]));
2048 flexarray_set(back, boffset++, "bridge");
2049 flexarray_set(back, boffset++, libxl__strdup(&gc, nic->bridge));
2050 flexarray_set(back, boffset++, "handle");
2051 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", nic->devid));
2053 flexarray_set(front, foffset++, "backend-id");
2054 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", nic->backend_domid));
2055 flexarray_set(front, foffset++, "state");
2056 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", 1));
2057 flexarray_set(front, foffset++, "handle");
2058 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", nic->devid));
2059 flexarray_set(front, foffset++, "mac");
2060 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%02x:%02x:%02x:%02x:%02x:%02x",
2061 nic->mac[0], nic->mac[1], nic->mac[2],
2062 nic->mac[3], nic->mac[4], nic->mac[5]));
2063 if (0 /* protocol != native*/) {
2064 flexarray_set(front, foffset++, "protocol");
2065 flexarray_set(front, foffset++, "x86_32-abi"); /* hardcoded ! */
2068 libxl__device_generic_add(ctx, &device,
2069 libxl__xs_kvs_of_flexarray(&gc, back, boffset),
2070 libxl__xs_kvs_of_flexarray(&gc, front, foffset));
2072 /* FIXME: wait for plug */
2073 rc = 0;
2074 out_free:
2075 flexarray_free(back);
2076 flexarray_free(front);
2077 out:
2078 libxl__free_all(&gc);
2079 return rc;
2082 int libxl_device_nic_del(libxl_ctx *ctx,
2083 libxl_device_nic *nic, int wait)
2085 libxl__device device;
2087 device.backend_devid = nic->devid;
2088 device.backend_domid = nic->backend_domid;
2089 device.backend_kind = DEVICE_VIF;
2090 device.devid = nic->devid;
2091 device.domid = nic->domid;
2092 device.kind = DEVICE_VIF;
2094 return libxl__device_del(ctx, &device, wait);
2097 libxl_nicinfo *libxl_list_nics(libxl_ctx *ctx, uint32_t domid, unsigned int *nb)
2099 libxl__gc gc = LIBXL_INIT_GC(ctx);
2100 char *dompath, *nic_path_fe;
2101 char **l, **list;
2102 char *val, *tok;
2103 unsigned int nb_nics, i;
2104 libxl_nicinfo *res, *nics;
2106 dompath = libxl__xs_get_dompath(&gc, domid);
2107 if (!dompath)
2108 goto err;
2109 list = l = libxl__xs_directory(&gc, XBT_NULL,
2110 libxl__sprintf(&gc, "%s/device/vif", dompath), &nb_nics);
2111 if (!l)
2112 goto err;
2113 nics = res = calloc(nb_nics, sizeof (libxl_device_nic));
2114 if (!res)
2115 goto err;
2116 for (*nb = nb_nics; nb_nics > 0; --nb_nics, ++l, ++nics) {
2117 nic_path_fe = libxl__sprintf(&gc, "%s/device/vif/%s", dompath, *l);
2119 nics->backend = xs_read(ctx->xsh, XBT_NULL,
2120 libxl__sprintf(&gc, "%s/backend", nic_path_fe), NULL);
2121 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend-id", nic_path_fe));
2122 nics->backend_id = val ? strtoul(val, NULL, 10) : -1;
2124 nics->devid = strtoul(*l, NULL, 10);
2125 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/state", nic_path_fe));
2126 nics->state = val ? strtoul(val, NULL, 10) : -1;
2127 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/mac", nic_path_fe));
2128 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
2129 ++i, tok = strtok(NULL, ":")) {
2130 nics->mac[i] = strtoul(tok, NULL, 16);
2132 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/event-channel", nic_path_fe));
2133 nics->evtch = val ? strtol(val, NULL, 10) : -1;
2134 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/tx-ring-ref", nic_path_fe));
2135 nics->rref_tx = val ? strtol(val, NULL, 10) : -1;
2136 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/rx-ring-ref", nic_path_fe));
2137 nics->rref_rx = val ? strtol(val, NULL, 10) : -1;
2138 nics->frontend = xs_read(ctx->xsh, XBT_NULL,
2139 libxl__sprintf(&gc, "%s/frontend", nics->backend), NULL);
2140 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/frontend-id", nics->backend));
2141 nics->frontend_id = val ? strtoul(val, NULL, 10) : -1;
2142 nics->script = xs_read(ctx->xsh, XBT_NULL,
2143 libxl__sprintf(&gc, "%s/script", nics->backend), NULL);
2146 libxl__free_all(&gc);
2147 return res;
2148 err:
2149 libxl__free_all(&gc);
2150 return NULL;
2153 /******************************************************************************/
2154 int libxl_device_net2_add(libxl_ctx *ctx, uint32_t domid, libxl_device_net2 *net2)
2156 libxl__gc gc = LIBXL_INIT_GC(ctx);
2157 flexarray_t *front, *back;
2158 unsigned int boffset = 0, foffset = 0;
2159 libxl__device device;
2160 char *dompath, *dom, **l;
2161 unsigned int nb;
2162 int rc;
2164 front = flexarray_make(16, 1);
2165 if (!front) {
2166 rc = ERROR_NOMEM;
2167 goto err;
2169 back = flexarray_make(16, 1);
2170 if (!back) {
2171 rc = ERROR_NOMEM;
2172 goto err_free;
2175 if (!(dompath = libxl__xs_get_dompath(&gc, domid))) {
2176 rc = ERROR_FAIL;
2177 goto err_free;
2179 dom = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/name", dompath));
2181 if (net2->devid == -1) {
2182 if (!(l = libxl__xs_directory(&gc, XBT_NULL,
2183 libxl__sprintf(&gc, "%s/device/vif2", dompath), &nb))) {
2184 net2->devid = 0;
2185 } else {
2186 net2->devid = strtoul(l[nb - 1], NULL, 10) + 1;
2190 device.backend_devid = net2->devid;
2191 device.backend_domid = net2->backend_domid;
2192 device.backend_kind = DEVICE_VIF2;
2193 device.devid = net2->devid;
2194 device.domid = net2->domid;
2195 device.kind = DEVICE_VIF2;
2197 flexarray_set(back, boffset++, "domain");
2198 flexarray_set(back, boffset++, dom);
2199 flexarray_set(back, boffset++, "frontend-id");
2200 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", net2->domid));
2202 flexarray_set(back, boffset++, "local-trusted");
2203 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", net2->back_trusted));
2204 flexarray_set(back, boffset++, "mac");
2205 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%02x:%02x:%02x:%02x:%02x:%02x",
2206 net2->back_mac[0], net2->back_mac[1],
2207 net2->back_mac[2], net2->back_mac[3],
2208 net2->back_mac[4], net2->back_mac[5]));
2210 flexarray_set(back, boffset++, "remote-trusted");
2211 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", net2->trusted));
2212 flexarray_set(back, boffset++, "remote-mac");
2213 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%02x:%02x:%02x:%02x:%02x:%02x",
2214 net2->front_mac[0], net2->front_mac[1],
2215 net2->front_mac[2], net2->front_mac[3],
2216 net2->front_mac[4], net2->front_mac[5]));
2218 flexarray_set(back, boffset++, "max-bypasses");
2219 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", net2->max_bypasses));
2220 flexarray_set(back, boffset++, "filter-mac");
2221 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", !!(net2->filter_mac)));
2222 flexarray_set(back, boffset++, "handle");
2223 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", net2->devid));
2224 flexarray_set(back, boffset++, "online");
2225 flexarray_set(back, boffset++, "1");
2226 flexarray_set(back, boffset++, "state");
2227 flexarray_set(back, boffset++, "1");
2229 flexarray_set(front, foffset++, "backend-id");
2230 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", net2->backend_domid));
2232 flexarray_set(front, foffset++, "local-trusted");
2233 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", net2->trusted));
2234 flexarray_set(front, foffset++, "mac");
2235 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%02x:%02x:%02x:%02x:%02x:%02x",
2236 net2->front_mac[0], net2->front_mac[1],
2237 net2->front_mac[2], net2->front_mac[3],
2238 net2->front_mac[4], net2->front_mac[5]));
2240 flexarray_set(front, foffset++, "remote-trusted");
2241 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", net2->back_trusted));
2242 flexarray_set(front, foffset++, "remote-mac");
2243 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%02x:%02x:%02x:%02x:%02x:%02x",
2244 net2->back_mac[0], net2->back_mac[1],
2245 net2->back_mac[2], net2->back_mac[3],
2246 net2->back_mac[4], net2->back_mac[5]));
2248 flexarray_set(front, foffset++, "filter-mac");
2249 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", !!(net2->filter_mac)));
2250 flexarray_set(front, foffset++, "state");
2251 flexarray_set(front, foffset++, "1");
2253 libxl__device_generic_add(ctx, &device,
2254 libxl__xs_kvs_of_flexarray(&gc, back, boffset),
2255 libxl__xs_kvs_of_flexarray(&gc, front, foffset));
2257 /* FIXME: wait for plug */
2258 rc = 0;
2259 err_free:
2260 flexarray_free(back);
2261 flexarray_free(front);
2262 err:
2263 libxl__free_all(&gc);
2264 return rc;
2267 libxl_net2info *libxl_device_net2_list(libxl_ctx *ctx, uint32_t domid, unsigned int *nb)
2269 libxl__gc gc = LIBXL_INIT_GC(ctx);
2270 char *dompath, *net2_path_fe;
2271 char **l;
2272 char *val, *tok;
2273 unsigned int nb_net2s, i;
2274 libxl_net2info *res, *net2s;
2276 dompath = libxl__xs_get_dompath(&gc, domid);
2277 if (!dompath)
2278 goto err;
2279 l = libxl__xs_directory(&gc, XBT_NULL,
2280 libxl__sprintf(&gc, "%s/device/vif2", dompath), &nb_net2s);
2281 if (!l)
2282 goto err;
2283 res = calloc(nb_net2s, sizeof (libxl_net2info));
2284 if (!res)
2285 goto err;
2286 net2s = res;
2287 for (*nb = nb_net2s; nb_net2s > 0; --nb_net2s, ++l, ++net2s) {
2288 net2_path_fe = libxl__sprintf(&gc, "%s/device/vif2/%s", dompath, *l);
2290 net2s->backend = libxl__xs_read(&gc, XBT_NULL,
2291 libxl__sprintf(&gc, "%s/backend", net2_path_fe));
2292 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend-id", net2_path_fe));
2293 net2s->backend_id = val ? strtoul(val, NULL, 10) : -1;
2295 net2s->devid = strtoul(*l, NULL, 10);
2296 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/state", net2_path_fe));
2297 net2s->state = val ? strtoul(val, NULL, 10) : -1;
2299 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/mac", net2_path_fe));
2300 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
2301 ++i, tok = strtok(NULL, ":")) {
2302 net2s->mac[i] = strtoul(tok, NULL, 16);
2304 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/remote-trusted", net2_path_fe));
2305 net2s->trusted = val ? strtoul(val, NULL, 10) : -1;
2307 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/remote-mac", net2_path_fe));
2308 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
2309 ++i, tok = strtok(NULL, ":")) {
2310 net2s->back_mac[i] = strtoul(tok, NULL, 16);
2312 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/filter-mac", net2_path_fe));
2313 net2s->filter_mac = val ? strtoul(val, NULL, 10) : -1;
2315 net2s->frontend = libxl__xs_read(&gc, XBT_NULL,
2316 libxl__sprintf(&gc, "%s/frontend", net2s->backend));
2317 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/frontend-id", net2s->backend));
2318 net2s->frontend_id = val ? strtoul(val, NULL, 10) : -1;
2321 libxl__free_all(&gc);
2322 return res;
2323 err:
2324 libxl__free_all(&gc);
2325 return NULL;
2328 int libxl_device_net2_del(libxl_ctx *ctx, libxl_device_net2 *net2, int wait)
2330 libxl__device device;
2332 device.backend_devid = net2->devid;
2333 device.backend_domid = net2->backend_domid;
2334 device.backend_kind = DEVICE_VIF2;
2335 device.devid = net2->devid;
2336 device.domid = net2->domid;
2337 device.kind = DEVICE_VIF2;
2339 return libxl__device_del(ctx, &device, wait);
2343 /******************************************************************************/
2344 int libxl_device_console_add(libxl_ctx *ctx, uint32_t domid, libxl_device_console *console)
2346 libxl__gc gc = LIBXL_INIT_GC(ctx);
2347 flexarray_t *front;
2348 flexarray_t *back;
2349 unsigned int boffset = 0;
2350 unsigned int foffset = 0;
2351 libxl__device device;
2352 int rc;
2354 front = flexarray_make(16, 1);
2355 if (!front) {
2356 rc = ERROR_NOMEM;
2357 goto out;
2359 back = flexarray_make(16, 1);
2360 if (!back) {
2361 rc = ERROR_NOMEM;
2362 goto out_free;
2365 device.backend_devid = console->devid;
2366 device.backend_domid = console->backend_domid;
2367 device.backend_kind = DEVICE_CONSOLE;
2368 device.devid = console->devid;
2369 device.domid = console->domid;
2370 device.kind = DEVICE_CONSOLE;
2372 flexarray_set(back, boffset++, "frontend-id");
2373 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", console->domid));
2374 flexarray_set(back, boffset++, "online");
2375 flexarray_set(back, boffset++, "1");
2376 flexarray_set(back, boffset++, "state");
2377 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", 1));
2378 flexarray_set(back, boffset++, "domain");
2379 flexarray_set(back, boffset++, libxl__domid_to_name(&gc, domid));
2380 flexarray_set(back, boffset++, "protocol");
2381 flexarray_set(back, boffset++, LIBXL_XENCONSOLE_PROTOCOL);
2383 flexarray_set(front, foffset++, "backend-id");
2384 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", console->backend_domid));
2385 flexarray_set(front, foffset++, "limit");
2386 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", LIBXL_XENCONSOLE_LIMIT));
2387 flexarray_set(front, foffset++, "type");
2388 if (console->consback == LIBXL_CONSBACK_XENCONSOLED)
2389 flexarray_set(front, foffset++, "xenconsoled");
2390 else
2391 flexarray_set(front, foffset++, "ioemu");
2392 flexarray_set(front, foffset++, "output");
2393 flexarray_set(front, foffset++, console->output);
2395 if (device.devid == 0) {
2396 if (console->build_state == NULL) {
2397 rc = ERROR_INVAL;
2398 goto out_free;
2400 flexarray_set(front, foffset++, "port");
2401 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%"PRIu32, console->build_state->console_port));
2402 flexarray_set(front, foffset++, "ring-ref");
2403 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%lu", console->build_state->console_mfn));
2404 } else {
2405 flexarray_set(front, foffset++, "state");
2406 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", 1));
2407 flexarray_set(front, foffset++, "protocol");
2408 flexarray_set(front, foffset++, LIBXL_XENCONSOLE_PROTOCOL);
2411 libxl__device_generic_add(ctx, &device,
2412 libxl__xs_kvs_of_flexarray(&gc, back, boffset),
2413 libxl__xs_kvs_of_flexarray(&gc, front, foffset));
2414 rc = 0;
2415 out_free:
2416 flexarray_free(back);
2417 flexarray_free(front);
2418 out:
2419 libxl__free_all(&gc);
2420 return rc;
2423 /******************************************************************************/
2424 int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb)
2426 libxl__gc gc = LIBXL_INIT_GC(ctx);
2427 flexarray_t *front;
2428 flexarray_t *back;
2429 unsigned int boffset = 0;
2430 unsigned int foffset = 0;
2431 libxl__device device;
2432 int rc;
2434 front = flexarray_make(16, 1);
2435 if (!front) {
2436 rc = ERROR_NOMEM;
2437 goto out;
2439 back = flexarray_make(16, 1);
2440 if (!back) {
2441 rc = ERROR_NOMEM;
2442 goto out_free;
2445 device.backend_devid = vkb->devid;
2446 device.backend_domid = vkb->backend_domid;
2447 device.backend_kind = DEVICE_VKBD;
2448 device.devid = vkb->devid;
2449 device.domid = vkb->domid;
2450 device.kind = DEVICE_VKBD;
2452 flexarray_set(back, boffset++, "frontend-id");
2453 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", vkb->domid));
2454 flexarray_set(back, boffset++, "online");
2455 flexarray_set(back, boffset++, "1");
2456 flexarray_set(back, boffset++, "state");
2457 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", 1));
2458 flexarray_set(back, boffset++, "domain");
2459 flexarray_set(back, boffset++, libxl__domid_to_name(&gc, domid));
2461 flexarray_set(front, foffset++, "backend-id");
2462 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", vkb->backend_domid));
2463 flexarray_set(front, foffset++, "state");
2464 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", 1));
2466 libxl__device_generic_add(ctx, &device,
2467 libxl__xs_kvs_of_flexarray(&gc, back, boffset),
2468 libxl__xs_kvs_of_flexarray(&gc, front, foffset));
2469 rc = 0;
2470 out_free:
2471 flexarray_free(back);
2472 flexarray_free(front);
2473 out:
2474 libxl__free_all(&gc);
2475 return rc;
2478 int libxl_device_vkb_clean_shutdown(libxl_ctx *ctx, uint32_t domid)
2480 return ERROR_NI;
2483 int libxl_device_vkb_hard_shutdown(libxl_ctx *ctx, uint32_t domid)
2485 return ERROR_NI;
2488 libxl_device_disk *libxl_device_disk_list(libxl_ctx *ctx, uint32_t domid, int *num)
2490 libxl__gc gc = LIBXL_INIT_GC(ctx);
2491 char *be_path_tap, *be_path_vbd;
2492 libxl_device_disk *dend, *disks, *ret = NULL;
2493 char **b, **l = NULL;
2494 unsigned int numl, len;
2495 char *type;
2497 be_path_vbd = libxl__sprintf(&gc, "%s/backend/vbd/%d", libxl__xs_get_dompath(&gc, 0), domid);
2498 be_path_tap = libxl__sprintf(&gc, "%s/backend/tap/%d", libxl__xs_get_dompath(&gc, 0), domid);
2500 b = l = libxl__xs_directory(&gc, XBT_NULL, be_path_vbd, &numl);
2501 if (l) {
2502 ret = realloc(ret, sizeof(libxl_device_disk) * numl);
2503 disks = ret;
2504 *num = numl;
2505 dend = ret + *num;
2506 for (; disks < dend; ++disks, ++l) {
2507 disks->backend_domid = 0;
2508 disks->domid = domid;
2509 disks->physpath = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "%s/%s/params", be_path_vbd, *l), &len);
2510 libxl_string_to_phystype(ctx, libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/%s/type", be_path_vbd, *l)), &(disks->phystype));
2511 disks->virtpath = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "%s/%s/dev", be_path_vbd, *l), &len);
2512 disks->unpluggable = atoi(libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/%s/removable", be_path_vbd, *l)));
2513 if (!strcmp(libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/%s/mode", be_path_vbd, *l)), "w"))
2514 disks->readwrite = 1;
2515 else
2516 disks->readwrite = 0;
2517 type = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/device-type", libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/%s/frontend", be_path_vbd, *l))));
2518 disks->is_cdrom = !strcmp(type, "cdrom");
2521 b = l = libxl__xs_directory(&gc, XBT_NULL, be_path_tap, &numl);
2522 if (l) {
2523 ret = realloc(ret, sizeof(libxl_device_disk) * (*num + numl));
2524 disks = ret + *num;
2525 *num += numl;
2526 for (dend = ret + *num; disks < dend; ++disks, ++l) {
2527 disks->backend_domid = 0;
2528 disks->domid = domid;
2529 disks->physpath = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "%s/%s/params", be_path_tap, *l), &len);
2530 libxl_string_to_phystype(ctx, libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/%s/type", be_path_tap, *l)), &(disks->phystype));
2531 disks->virtpath = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "%s/%s/dev", be_path_tap, *l), &len);
2532 disks->unpluggable = atoi(libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/%s/removable", be_path_tap, *l)));
2533 if (!strcmp(libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/%s/mode", be_path_tap, *l)), "w"))
2534 disks->readwrite = 1;
2535 else
2536 disks->readwrite = 0;
2537 type = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/device-type", libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/%s/frontend", be_path_tap, *l))));
2538 disks->is_cdrom = !strcmp(type, "cdrom");
2541 libxl__free_all(&gc);
2542 return ret;
2545 int libxl_device_disk_getinfo(libxl_ctx *ctx, uint32_t domid,
2546 libxl_device_disk *disk, libxl_diskinfo *diskinfo)
2548 libxl__gc gc = LIBXL_INIT_GC(ctx);
2549 char *dompath, *diskpath;
2550 char *val;
2552 dompath = libxl__xs_get_dompath(&gc, domid);
2553 diskinfo->devid = libxl__device_disk_dev_number(disk->virtpath);
2555 /* tap devices entries in xenstore are written as vbd devices. */
2556 diskpath = libxl__sprintf(&gc, "%s/device/vbd/%d", dompath, diskinfo->devid);
2557 diskinfo->backend = xs_read(ctx->xsh, XBT_NULL,
2558 libxl__sprintf(&gc, "%s/backend", diskpath), NULL);
2559 if (!diskinfo->backend) {
2560 libxl__free_all(&gc);
2561 return ERROR_FAIL;
2563 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend-id", diskpath));
2564 diskinfo->backend_id = val ? strtoul(val, NULL, 10) : -1;
2565 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/state", diskpath));
2566 diskinfo->state = val ? strtoul(val, NULL, 10) : -1;
2567 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/event-channel", diskpath));
2568 diskinfo->evtch = val ? strtoul(val, NULL, 10) : -1;
2569 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/ring-ref", diskpath));
2570 diskinfo->rref = val ? strtoul(val, NULL, 10) : -1;
2571 diskinfo->frontend = xs_read(ctx->xsh, XBT_NULL,
2572 libxl__sprintf(&gc, "%s/frontend", diskinfo->backend), NULL);
2573 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/frontend-id", diskinfo->backend));
2574 diskinfo->frontend_id = val ? strtoul(val, NULL, 10) : -1;
2576 libxl__free_all(&gc);
2577 return 0;
2580 int libxl_cdrom_insert(libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
2582 int num, i;
2583 uint32_t stubdomid;
2584 libxl_device_disk *disks;
2585 int ret = ERROR_FAIL;
2587 if (!disk->physpath) {
2588 disk->physpath = "";
2589 disk->phystype = PHYSTYPE_PHY;
2591 disks = libxl_device_disk_list(ctx, domid, &num);
2592 for (i = 0; i < num; i++) {
2593 if (disks[i].is_cdrom && !strcmp(disk->virtpath, disks[i].virtpath))
2594 /* found */
2595 break;
2597 if (i == num) {
2598 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Virtual device not found");
2599 goto out;
2602 ret = 0;
2604 libxl_device_disk_del(ctx, disks + i, 1);
2605 libxl_device_disk_add(ctx, domid, disk);
2606 stubdomid = libxl_get_stubdom_id(ctx, domid);
2607 if (stubdomid) {
2608 disks[i].domid = stubdomid;
2609 libxl_device_disk_del(ctx, disks + i, 1);
2610 disk->domid = stubdomid;
2611 libxl_device_disk_add(ctx, stubdomid, disk);
2612 disk->domid = domid;
2614 out:
2615 for (i = 0; i < num; i++)
2616 libxl_device_disk_destroy(&disks[i]);
2617 free(disks);
2618 return ret;
2621 /******************************************************************************/
2622 static int libxl_build_xenpv_qemu_args(libxl__gc *gc,
2623 uint32_t domid,
2624 libxl_device_vfb *vfb,
2625 libxl_device_model_info *info)
2627 libxl_ctx *ctx = libxl__gc_owner(gc);
2628 memset(info, 0x00, sizeof(libxl_device_model_info));
2630 if (vfb != NULL) {
2631 info->vnc = vfb->vnc;
2632 if (vfb->vnclisten)
2633 info->vnclisten = libxl__strdup(gc, vfb->vnclisten);
2634 info->vncdisplay = vfb->vncdisplay;
2635 info->vncunused = vfb->vncunused;
2636 if (vfb->vncpasswd)
2637 info->vncpasswd = vfb->vncpasswd;
2638 if (vfb->keymap)
2639 info->keymap = libxl__strdup(gc, vfb->keymap);
2640 info->sdl = vfb->sdl;
2641 info->opengl = vfb->opengl;
2642 } else
2643 info->nographic = 1;
2644 info->domid = domid;
2645 info->dom_name = libxl_domid_to_name(ctx, domid);
2646 info->device_model = libxl__abs_path(gc, "qemu-dm", libxl_libexec_path());
2647 info->type = XENPV;
2648 return 0;
2651 int libxl_create_xenpv_qemu(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb,
2652 libxl_device_model_starting **starting_r)
2654 libxl__gc gc = LIBXL_INIT_GC(ctx);
2655 libxl_device_model_info info;
2657 libxl_build_xenpv_qemu_args(&gc, domid, vfb, &info);
2658 libxl_create_device_model(ctx, &info, NULL, 0, NULL, 0, starting_r);
2659 libxl__free_all(&gc);
2660 return 0;
2663 int libxl_device_vfb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb)
2665 libxl__gc gc = LIBXL_INIT_GC(ctx);
2666 flexarray_t *front;
2667 flexarray_t *back;
2668 unsigned int boffset = 0;
2669 unsigned int foffset = 0;
2670 libxl__device device;
2671 int rc;
2673 front = flexarray_make(16, 1);
2674 if (!front) {
2675 rc = ERROR_NOMEM;
2676 goto out;
2678 back = flexarray_make(16, 1);
2679 if (!back) {
2680 rc = ERROR_NOMEM;
2681 goto out_free;
2684 device.backend_devid = vfb->devid;
2685 device.backend_domid = vfb->backend_domid;
2686 device.backend_kind = DEVICE_VFB;
2687 device.devid = vfb->devid;
2688 device.domid = vfb->domid;
2689 device.kind = DEVICE_VFB;
2691 flexarray_set(back, boffset++, "frontend-id");
2692 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", vfb->domid));
2693 flexarray_set(back, boffset++, "online");
2694 flexarray_set(back, boffset++, "1");
2695 flexarray_set(back, boffset++, "state");
2696 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", 1));
2697 flexarray_set(back, boffset++, "domain");
2698 flexarray_set(back, boffset++, libxl__domid_to_name(&gc, domid));
2699 flexarray_set(back, boffset++, "vnc");
2700 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", vfb->vnc));
2701 flexarray_set(back, boffset++, "vnclisten");
2702 flexarray_set(back, boffset++, vfb->vnclisten);
2703 flexarray_set(back, boffset++, "vncpasswd");
2704 flexarray_set(back, boffset++, vfb->vncpasswd);
2705 flexarray_set(back, boffset++, "vncdisplay");
2706 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", vfb->vncdisplay));
2707 flexarray_set(back, boffset++, "vncunused");
2708 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", vfb->vncunused));
2709 flexarray_set(back, boffset++, "sdl");
2710 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", vfb->sdl));
2711 flexarray_set(back, boffset++, "opengl");
2712 flexarray_set(back, boffset++, libxl__sprintf(&gc, "%d", vfb->opengl));
2713 if (vfb->xauthority) {
2714 flexarray_set(back, boffset++, "xauthority");
2715 flexarray_set(back, boffset++, vfb->xauthority);
2717 if (vfb->display) {
2718 flexarray_set(back, boffset++, "display");
2719 flexarray_set(back, boffset++, vfb->display);
2722 flexarray_set(front, foffset++, "backend-id");
2723 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", vfb->backend_domid));
2724 flexarray_set(front, foffset++, "state");
2725 flexarray_set(front, foffset++, libxl__sprintf(&gc, "%d", 1));
2727 libxl__device_generic_add(ctx, &device,
2728 libxl__xs_kvs_of_flexarray(&gc, back, boffset),
2729 libxl__xs_kvs_of_flexarray(&gc, front, foffset));
2730 rc = 0;
2731 out_free:
2732 flexarray_free(front);
2733 flexarray_free(back);
2734 out:
2735 libxl__free_all(&gc);
2736 return rc;
2739 int libxl_device_vfb_clean_shutdown(libxl_ctx *ctx, uint32_t domid)
2741 return ERROR_NI;
2744 int libxl_device_vfb_hard_shutdown(libxl_ctx *ctx, uint32_t domid)
2746 return ERROR_NI;
2749 /******************************************************************************/
2751 int libxl_domain_setmaxmem(libxl_ctx *ctx, uint32_t domid, uint32_t max_memkb)
2753 libxl__gc gc = LIBXL_INIT_GC(ctx);
2754 char *mem, *endptr;
2755 uint32_t memorykb;
2756 char *dompath = libxl__xs_get_dompath(&gc, domid);
2757 int rc = 1;
2759 mem = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/memory/target", dompath));
2760 if (!mem) {
2761 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "cannot get memory info from %s/memory/target\n", dompath);
2762 goto out;
2764 memorykb = strtoul(mem, &endptr, 10);
2765 if (*endptr != '\0') {
2766 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "invalid memory %s from %s/memory/target\n", mem, dompath);
2767 goto out;
2770 if (max_memkb < memorykb) {
2771 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "memory_static_max must be greater than or or equal to memory_dynamic_max\n");
2772 goto out;
2775 rc = 0;
2776 out:
2777 libxl__free_all(&gc);
2778 return rc;
2781 static int libxl__fill_dom0_memory_info(libxl__gc *gc, uint32_t *target_memkb)
2783 int rc;
2784 libxl_dominfo info;
2785 libxl_physinfo physinfo;
2786 char *target = NULL, *endptr = NULL;
2787 char *target_path = "/local/domain/0/memory/target";
2788 char *max_path = "/local/domain/0/memory/static-max";
2789 char *free_mem_slack_path = "/local/domain/0/memory/freemem-slack";
2790 xs_transaction_t t;
2791 libxl_ctx *ctx = libxl__gc_owner(gc);
2792 uint32_t free_mem_slack = 0;
2794 retry_transaction:
2795 t = xs_transaction_start(ctx->xsh);
2797 target = libxl__xs_read(gc, t, target_path);
2798 if (target) {
2799 *target_memkb = strtoul(target, &endptr, 10);
2800 if (*endptr != '\0') {
2801 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
2802 "invalid memory target %s from %s\n", target, target_path);
2803 rc = ERROR_FAIL;
2804 goto out;
2806 rc = 0;
2807 goto out;
2810 rc = libxl_domain_info(ctx, &info, 0);
2811 if (rc < 0)
2812 return rc;
2814 rc = libxl_get_physinfo(ctx, &physinfo);
2815 if (rc < 0)
2816 return rc;
2818 libxl__xs_write(gc, t, target_path, "%"PRIu32,
2819 (uint32_t) info.current_memkb);
2820 libxl__xs_write(gc, t, max_path, "%"PRIu32,
2821 (uint32_t) info.max_memkb);
2823 free_mem_slack = (uint32_t) (PAGE_TO_MEMKB(physinfo.total_pages) -
2824 info.current_memkb);
2825 /* From empirical measurements the free_mem_slack shouldn't be more
2826 * than 15% of the total memory present on the system. */
2827 if (free_mem_slack > PAGE_TO_MEMKB(physinfo.total_pages) * 0.15)
2828 free_mem_slack = PAGE_TO_MEMKB(physinfo.total_pages) * 0.15;
2829 libxl__xs_write(gc, t, free_mem_slack_path, "%"PRIu32, free_mem_slack);
2831 *target_memkb = (uint32_t) info.current_memkb;
2832 rc = 0;
2834 out:
2835 if (!xs_transaction_end(ctx->xsh, t, 0))
2836 if (errno == EAGAIN)
2837 goto retry_transaction;
2840 return rc;
2843 /* returns how much memory should be left free in the system */
2844 static int libxl__get_free_memory_slack(libxl__gc *gc, uint32_t *free_mem_slack)
2846 int rc;
2847 char *free_mem_slack_path = "/local/domain/0/memory/freemem-slack";
2848 char *free_mem_slack_s, *endptr;
2849 uint32_t target_memkb;
2851 retry:
2852 free_mem_slack_s = libxl__xs_read(gc, XBT_NULL, free_mem_slack_path);
2853 if (!free_mem_slack_s) {
2854 rc = libxl__fill_dom0_memory_info(gc, &target_memkb);
2855 if (rc < 0)
2856 return rc;
2857 goto retry;
2858 } else {
2859 *free_mem_slack = strtoul(free_mem_slack_s, &endptr, 10);
2860 if (*endptr != '\0') {
2861 LIBXL__LOG_ERRNO(gc->owner, LIBXL__LOG_ERROR,
2862 "invalid free_mem_slack %s from %s\n",
2863 free_mem_slack_s, free_mem_slack_path);
2864 return ERROR_FAIL;
2867 return 0;
2870 int libxl_set_memory_target(libxl_ctx *ctx, uint32_t domid,
2871 int32_t target_memkb, int relative, int enforce)
2873 libxl__gc gc = LIBXL_INIT_GC(ctx);
2874 int rc = 1, abort = 0;
2875 uint32_t memorykb = 0, videoram = 0;
2876 uint32_t current_target_memkb = 0, new_target_memkb = 0;
2877 char *memmax, *endptr, *videoram_s = NULL, *target = NULL;
2878 char *dompath = libxl__xs_get_dompath(&gc, domid);
2879 xc_domaininfo_t info;
2880 libxl_dominfo ptr;
2881 char *uuid;
2882 xs_transaction_t t;
2884 retry_transaction:
2885 t = xs_transaction_start(ctx->xsh);
2887 target = libxl__xs_read(&gc, t, libxl__sprintf(&gc,
2888 "%s/memory/target", dompath));
2889 if (!target && !domid) {
2890 xs_transaction_end(ctx->xsh, t, 1);
2891 rc = libxl__fill_dom0_memory_info(&gc, &current_target_memkb);
2892 if (rc < 0) {
2893 abort = 1;
2894 goto out;
2896 goto retry_transaction;
2897 } else if (!target) {
2898 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
2899 "cannot get target memory info from %s/memory/target\n",
2900 dompath);
2901 abort = 1;
2902 goto out;
2903 } else {
2904 current_target_memkb = strtoul(target, &endptr, 10);
2905 if (*endptr != '\0') {
2906 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
2907 "invalid memory target %s from %s/memory/target\n",
2908 target, dompath);
2909 abort = 1;
2910 goto out;
2913 memmax = libxl__xs_read(&gc, t, libxl__sprintf(&gc,
2914 "%s/memory/static-max", dompath));
2915 if (!memmax) {
2916 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
2917 "cannot get memory info from %s/memory/static-max\n",
2918 dompath);
2919 abort = 1;
2920 goto out;
2922 memorykb = strtoul(memmax, &endptr, 10);
2923 if (*endptr != '\0') {
2924 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
2925 "invalid max memory %s from %s/memory/static-max\n",
2926 memmax, dompath);
2927 abort = 1;
2928 goto out;
2930 if (!domid && new_target_memkb < LIBXL_MIN_DOM0_MEM) {
2931 LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
2932 "new target for dom0 is below the minimum threshold\n");
2933 abort = 1;
2934 goto out;
2937 if (relative)
2938 new_target_memkb = current_target_memkb + target_memkb;
2939 else
2940 new_target_memkb = target_memkb;
2941 if (new_target_memkb > memorykb) {
2942 LIBXL__LOG(ctx, LIBXL__LOG_ERROR,
2943 "memory_dynamic_max must be less than or equal to"
2944 " memory_static_max\n");
2945 abort = 1;
2946 goto out;
2949 videoram_s = libxl__xs_read(&gc, t, libxl__sprintf(&gc,
2950 "%s/memory/videoram", dompath));
2951 videoram = videoram_s ? atoi(videoram_s) : 0;
2953 if (enforce) {
2954 memorykb = new_target_memkb;
2955 rc = xc_domain_setmaxmem(ctx->xch, domid, memorykb +
2956 LIBXL_MAXMEM_CONSTANT);
2957 if (rc != 0) {
2958 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
2959 "xc_domain_setmaxmem domid=%d memkb=%d failed "
2960 "rc=%d\n", domid, memorykb + LIBXL_MAXMEM_CONSTANT, rc);
2961 abort = 1;
2962 goto out;
2966 new_target_memkb -= videoram;
2967 rc = xc_domain_set_pod_target(ctx->xch, domid,
2968 new_target_memkb / 4, NULL, NULL, NULL);
2969 if (rc != 0) {
2970 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
2971 "xc_domain_set_pod_target domid=%d, memkb=%d "
2972 "failed rc=%d\n", domid, new_target_memkb / 4,
2973 rc);
2974 abort = 1;
2975 goto out;
2978 libxl__xs_write(&gc, t, libxl__sprintf(&gc, "%s/memory/target",
2979 dompath), "%"PRIu32, new_target_memkb);
2980 rc = xc_domain_getinfolist(ctx->xch, domid, 1, &info);
2981 if (rc != 1 || info.domain != domid) {
2982 abort = 1;
2983 goto out;
2985 xcinfo2xlinfo(&info, &ptr);
2986 uuid = libxl__uuid2string(&gc, ptr.uuid);
2987 libxl__xs_write(&gc, t, libxl__sprintf(&gc, "/vm/%s/memory", uuid),
2988 "%"PRIu32, new_target_memkb / 1024);
2990 out:
2991 if (!xs_transaction_end(ctx->xsh, t, abort) && !abort)
2992 if (errno == EAGAIN)
2993 goto retry_transaction;
2995 libxl__free_all(&gc);
2996 return rc;
2999 int libxl_get_memory_target(libxl_ctx *ctx, uint32_t domid, uint32_t *out_target)
3001 libxl__gc gc = LIBXL_INIT_GC(ctx);
3002 int rc = 1;
3003 char *target = NULL, *endptr = NULL;
3004 char *dompath = libxl__xs_get_dompath(&gc, domid);
3005 uint32_t target_memkb;
3007 target = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc,
3008 "%s/memory/target", dompath));
3009 if (!target && !domid) {
3010 rc = libxl__fill_dom0_memory_info(&gc, &target_memkb);
3011 if (rc < 0)
3012 goto out;
3013 } else if (!target) {
3014 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
3015 "cannot get target memory info from %s/memory/target\n",
3016 dompath);
3017 goto out;
3018 } else {
3019 target_memkb = strtoul(target, &endptr, 10);
3020 if (*endptr != '\0') {
3021 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR,
3022 "invalid memory target %s from %s/memory/target\n",
3023 target, dompath);
3024 goto out;
3027 *out_target = target_memkb;
3028 rc = 0;
3030 out:
3031 libxl__free_all(&gc);
3032 return rc;
3035 int libxl_domain_need_memory(libxl_ctx *ctx, libxl_domain_build_info *b_info,
3036 libxl_device_model_info *dm_info, uint32_t *need_memkb)
3038 *need_memkb = b_info->target_memkb;
3039 if (b_info->hvm) {
3040 *need_memkb += b_info->shadow_memkb + LIBXL_HVM_EXTRA_MEMORY;
3041 if (strstr(dm_info->device_model, "stubdom-dm"))
3042 *need_memkb += 32 * 1024;
3043 } else
3044 *need_memkb += LIBXL_PV_EXTRA_MEMORY;
3045 if (*need_memkb % (2 * 1024))
3046 *need_memkb += (2 * 1024) - (*need_memkb % (2 * 1024));
3047 return 0;
3050 int libxl_get_free_memory(libxl_ctx *ctx, uint32_t *memkb)
3052 int rc = 0;
3053 libxl_physinfo info;
3054 uint32_t freemem_slack;
3055 libxl__gc gc = LIBXL_INIT_GC(ctx);
3057 rc = libxl_get_physinfo(ctx, &info);
3058 if (rc < 0)
3059 goto out;
3060 rc = libxl__get_free_memory_slack(&gc, &freemem_slack);
3061 if (rc < 0)
3062 goto out;
3064 if ((info.free_pages + info.scrub_pages) * 4 > freemem_slack)
3065 *memkb = (info.free_pages + info.scrub_pages) * 4 - freemem_slack;
3066 else
3067 *memkb = 0;
3069 out:
3070 libxl__free_all(&gc);
3071 return rc;
3074 int libxl_wait_for_free_memory(libxl_ctx *ctx, uint32_t domid, uint32_t
3075 memory_kb, int wait_secs)
3077 int rc = 0;
3078 libxl_physinfo info;
3079 uint32_t freemem_slack;
3080 libxl__gc gc = LIBXL_INIT_GC(ctx);
3082 rc = libxl__get_free_memory_slack(&gc, &freemem_slack);
3083 if (rc < 0)
3084 goto out;
3085 while (wait_secs > 0) {
3086 rc = libxl_get_physinfo(ctx, &info);
3087 if (rc < 0)
3088 goto out;
3089 if (info.free_pages * 4 - freemem_slack >= memory_kb) {
3090 rc = 0;
3091 goto out;
3093 wait_secs--;
3094 sleep(1);
3096 rc = ERROR_NOMEM;
3098 out:
3099 libxl__free_all(&gc);
3100 return rc;
3103 int libxl_wait_for_memory_target(libxl_ctx *ctx, uint32_t domid, int wait_secs)
3105 int rc = 0;
3106 uint32_t target_memkb = 0;
3107 libxl_dominfo info;
3109 do {
3110 wait_secs--;
3111 sleep(1);
3113 rc = libxl_get_memory_target(ctx, domid, &target_memkb);
3114 if (rc < 0)
3115 goto out;
3117 rc = libxl_domain_info(ctx, &info, domid);
3118 if (rc < 0)
3119 return rc;
3120 } while (wait_secs > 0 && info.current_memkb > target_memkb);
3122 if (info.current_memkb <= target_memkb)
3123 rc = 0;
3124 else
3125 rc = ERROR_FAIL;
3127 out:
3128 return 0;
3131 int libxl_button_press(libxl_ctx *ctx, uint32_t domid, libxl_button button)
3133 int rc = -1;
3135 switch (button) {
3136 case POWER_BUTTON:
3137 rc = xc_domain_send_trigger(ctx->xch, domid, XEN_DOMCTL_SENDTRIGGER_POWER, 0);
3138 break;
3139 case SLEEP_BUTTON:
3140 rc = xc_domain_send_trigger(ctx->xch, domid, XEN_DOMCTL_SENDTRIGGER_SLEEP, 0);
3141 break;
3142 default:
3143 break;
3146 return rc;
3149 int libxl_get_physinfo(libxl_ctx *ctx, libxl_physinfo *physinfo)
3151 xc_physinfo_t xcphysinfo = { 0 };
3152 int rc;
3154 rc = xc_physinfo(ctx->xch, &xcphysinfo);
3155 if (rc != 0) {
3156 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting physinfo");
3157 return ERROR_FAIL;
3159 physinfo->threads_per_core = xcphysinfo.threads_per_core;
3160 physinfo->cores_per_socket = xcphysinfo.cores_per_socket;
3161 physinfo->max_cpu_id = xcphysinfo.max_cpu_id;
3162 physinfo->nr_cpus = xcphysinfo.nr_cpus;
3163 physinfo->cpu_khz = xcphysinfo.cpu_khz;
3164 physinfo->total_pages = xcphysinfo.total_pages;
3165 physinfo->free_pages = xcphysinfo.free_pages;
3166 physinfo->scrub_pages = xcphysinfo.scrub_pages;
3167 physinfo->nr_nodes = xcphysinfo.nr_nodes;
3168 memcpy(physinfo->hw_cap,xcphysinfo.hw_cap, sizeof(physinfo->hw_cap));
3169 physinfo->phys_cap = xcphysinfo.capabilities;
3171 return 0;
3174 const libxl_version_info* libxl_get_version_info(libxl_ctx *ctx)
3176 union {
3177 xen_extraversion_t xen_extra;
3178 xen_compile_info_t xen_cc;
3179 xen_changeset_info_t xen_chgset;
3180 xen_capabilities_info_t xen_caps;
3181 xen_platform_parameters_t p_parms;
3182 xen_commandline_t xen_commandline;
3183 } u;
3184 long xen_version;
3185 libxl_version_info *info = &ctx->version_info;
3187 if (info->xen_version_extra != NULL)
3188 return info;
3190 xen_version = xc_version(ctx->xch, XENVER_version, NULL);
3191 info->xen_version_major = xen_version >> 16;
3192 info->xen_version_minor = xen_version & 0xFF;
3194 xc_version(ctx->xch, XENVER_extraversion, &u.xen_extra);
3195 info->xen_version_extra = strdup(u.xen_extra);
3197 xc_version(ctx->xch, XENVER_compile_info, &u.xen_cc);
3198 info->compiler = strdup(u.xen_cc.compiler);
3199 info->compile_by = strdup(u.xen_cc.compile_by);
3200 info->compile_domain = strdup(u.xen_cc.compile_domain);
3201 info->compile_date = strdup(u.xen_cc.compile_date);
3203 xc_version(ctx->xch, XENVER_capabilities, &u.xen_caps);
3204 info->capabilities = strdup(u.xen_caps);
3206 xc_version(ctx->xch, XENVER_changeset, &u.xen_chgset);
3207 info->changeset = strdup(u.xen_chgset);
3209 xc_version(ctx->xch, XENVER_platform_parameters, &u.p_parms);
3210 info->virt_start = u.p_parms.virt_start;
3212 info->pagesize = xc_version(ctx->xch, XENVER_pagesize, NULL);
3214 xc_version(ctx->xch, XENVER_commandline, &u.xen_commandline);
3215 info->commandline = strdup(u.xen_commandline);
3217 return info;
3220 libxl_vcpuinfo *libxl_list_vcpu(libxl_ctx *ctx, uint32_t domid,
3221 int *nb_vcpu, int *nrcpus)
3223 libxl_vcpuinfo *ptr, *ret;
3224 xc_domaininfo_t domaininfo;
3225 xc_vcpuinfo_t vcpuinfo;
3227 if (xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo) != 1) {
3228 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting infolist");
3229 return NULL;
3231 *nrcpus = xc_get_max_cpus(ctx->xch);
3232 ret = ptr = calloc(domaininfo.max_vcpu_id + 1, sizeof (libxl_vcpuinfo));
3233 if (!ptr) {
3234 return NULL;
3237 for (*nb_vcpu = 0; *nb_vcpu <= domaininfo.max_vcpu_id; ++*nb_vcpu, ++ptr) {
3238 if (libxl_cpumap_alloc(&ptr->cpumap, *nrcpus)) {
3239 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "allocating cpumap");
3240 return NULL;
3242 if (xc_vcpu_getinfo(ctx->xch, domid, *nb_vcpu, &vcpuinfo) == -1) {
3243 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting vcpu info");
3244 return NULL;
3246 if (xc_vcpu_getaffinity(ctx->xch, domid, *nb_vcpu,
3247 ptr->cpumap.map, ((*nrcpus) + 7) / 8) == -1) {
3248 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting vcpu affinity");
3249 return NULL;
3251 ptr->vcpuid = *nb_vcpu;
3252 ptr->cpu = vcpuinfo.cpu;
3253 ptr->online = !!vcpuinfo.online;
3254 ptr->blocked = !!vcpuinfo.blocked;
3255 ptr->running = !!vcpuinfo.running;
3256 ptr->vcpu_time = vcpuinfo.cpu_time;
3258 return ret;
3261 int libxl_set_vcpuaffinity(libxl_ctx *ctx, uint32_t domid, uint32_t vcpuid,
3262 uint64_t *cpumap, int nrcpus)
3264 if (xc_vcpu_setaffinity(ctx->xch, domid, vcpuid, cpumap, (nrcpus + 7) / 8)) {
3265 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "setting vcpu affinity");
3266 return ERROR_FAIL;
3268 return 0;
3271 int libxl_set_vcpuonline(libxl_ctx *ctx, uint32_t domid, uint32_t bitmask)
3273 libxl__gc gc = LIBXL_INIT_GC(ctx);
3274 libxl_dominfo info;
3275 char *dompath;
3276 xs_transaction_t t;
3277 int i, rc = ERROR_FAIL;
3279 if (libxl_domain_info(ctx, &info, domid) < 0) {
3280 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting domain info list");
3281 goto out;
3283 if (!(dompath = libxl__xs_get_dompath(&gc, domid)))
3284 goto out;
3286 retry_transaction:
3287 t = xs_transaction_start(ctx->xsh);
3288 for (i = 0; i <= info.vcpu_max_id; i++)
3289 libxl__xs_write(&gc, t,
3290 libxl__sprintf(&gc, "%s/cpu/%u/availability", dompath, i),
3291 "%s", ((1 << i) & bitmask) ? "online" : "offline");
3292 if (!xs_transaction_end(ctx->xsh, t, 0)) {
3293 if (errno == EAGAIN)
3294 goto retry_transaction;
3295 } else
3296 rc = 0;
3297 out:
3298 libxl__free_all(&gc);
3299 return rc;
3302 /*
3303 * returns one of the XEN_SCHEDULER_* constants from public/domctl.h
3304 */
3305 int libxl_get_sched_id(libxl_ctx *ctx)
3307 int sched, ret;
3309 if ((ret = xc_sched_id(ctx->xch, &sched)) != 0) {
3310 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting domain info list");
3311 return ERROR_FAIL;
3313 return sched;
3316 int libxl_sched_credit_domain_get(libxl_ctx *ctx, uint32_t domid, libxl_sched_credit *scinfo)
3318 struct xen_domctl_sched_credit sdom;
3319 int rc;
3321 rc = xc_sched_credit_domain_get(ctx->xch, domid, &sdom);
3322 if (rc != 0) {
3323 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "setting domain sched credit");
3324 return ERROR_FAIL;
3327 scinfo->weight = sdom.weight;
3328 scinfo->cap = sdom.cap;
3330 return 0;
3333 int libxl_sched_credit_domain_set(libxl_ctx *ctx, uint32_t domid, libxl_sched_credit *scinfo)
3335 struct xen_domctl_sched_credit sdom;
3336 xc_domaininfo_t domaininfo;
3337 int rc;
3339 rc = xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo);
3340 if (rc < 0) {
3341 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "getting domain info list");
3342 return ERROR_FAIL;
3344 if (rc != 1 || domaininfo.domain != domid)
3345 return ERROR_INVAL;
3348 if (scinfo->weight < 1 || scinfo->weight > 65535) {
3349 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
3350 "Cpu weight out of range, valid values are within range from 1 to 65535");
3351 return ERROR_INVAL;
3354 if (scinfo->cap < 0 || scinfo->cap > (domaininfo.max_vcpu_id + 1) * 100) {
3355 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
3356 "Cpu cap out of range, valid range is from 0 to %d for specified number of vcpus",
3357 ((domaininfo.max_vcpu_id + 1) * 100));
3358 return ERROR_INVAL;
3361 sdom.weight = scinfo->weight;
3362 sdom.cap = scinfo->cap;
3364 rc = xc_sched_credit_domain_set(ctx->xch, domid, &sdom);
3365 if ( rc < 0 ) {
3366 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "setting domain sched credit");
3367 return ERROR_FAIL;
3370 return 0;
3373 static int trigger_type_from_string(char *trigger_name)
3375 if (!strcmp(trigger_name, "nmi"))
3376 return XEN_DOMCTL_SENDTRIGGER_NMI;
3377 else if (!strcmp(trigger_name, "reset"))
3378 return XEN_DOMCTL_SENDTRIGGER_RESET;
3379 else if (!strcmp(trigger_name, "init"))
3380 return XEN_DOMCTL_SENDTRIGGER_INIT;
3381 else if (!strcmp(trigger_name, "power"))
3382 return XEN_DOMCTL_SENDTRIGGER_POWER;
3383 else if (!strcmp(trigger_name, "sleep"))
3384 return XEN_DOMCTL_SENDTRIGGER_SLEEP;
3385 else
3386 return -1;
3389 int libxl_send_trigger(libxl_ctx *ctx, uint32_t domid, char *trigger_name, uint32_t vcpuid)
3391 int rc = -1;
3392 int trigger_type = trigger_type_from_string(trigger_name);
3394 if (trigger_type == -1) {
3395 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, -1,
3396 "Invalid trigger, valid triggers are <nmi|reset|init|power|sleep>");
3397 return ERROR_INVAL;
3400 rc = xc_domain_send_trigger(ctx->xch, domid, trigger_type, vcpuid);
3401 if (rc != 0) {
3402 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
3403 "Send trigger '%s' failed", trigger_name);
3404 return ERROR_FAIL;
3407 return 0;
3410 int libxl_send_sysrq(libxl_ctx *ctx, uint32_t domid, char sysrq)
3412 libxl__gc gc = LIBXL_INIT_GC(ctx);
3413 char *dompath = libxl__xs_get_dompath(&gc, domid);
3415 libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/control/sysrq", dompath), "%c", sysrq);
3417 libxl__free_all(&gc);
3418 return 0;
3421 int libxl_send_debug_keys(libxl_ctx *ctx, char *keys)
3423 int ret;
3424 ret = xc_send_debug_keys(ctx->xch, keys);
3425 if ( ret < 0 ) {
3426 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "sending debug keys");
3427 return ERROR_FAIL;
3429 return 0;
3432 libxl_xen_console_reader *
3433 libxl_xen_console_read_start(libxl_ctx *ctx, int clear)
3435 libxl_xen_console_reader *cr;
3436 unsigned int size = 16384;
3437 char *buf = malloc(size);
3439 if (!buf) {
3440 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "cannot malloc buffer for libxl_xen_console_reader,"
3441 " size is %u", size);
3442 return NULL;
3445 cr = malloc(sizeof(libxl_xen_console_reader));
3446 if (!cr) {
3447 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "cannot malloc libxl_xen_console_reader");
3448 return NULL;
3451 memset(cr, 0, sizeof(libxl_xen_console_reader));
3452 cr->buffer = buf;
3453 cr->size = size;
3454 cr->count = size;
3455 cr->clear = clear;
3456 cr->incremental = 1;
3458 return cr;
3461 /* return values: *line_r
3462 * 1 success, whole line obtained from buffer non-0
3463 * 0 no more lines available right now 0
3464 * negative error code ERROR_* 0
3465 * On success *line_r is updated to point to a nul-terminated
3466 * string which is valid until the next call on the same console
3467 * reader. The libxl caller may overwrite parts of the string
3468 * if it wishes. */
3469 int libxl_xen_console_read_line(libxl_ctx *ctx,
3470 libxl_xen_console_reader *cr,
3471 char **line_r)
3473 int ret;
3475 memset(cr->buffer, 0, cr->size);
3476 ret = xc_readconsolering(ctx->xch, cr->buffer, &cr->count,
3477 cr->clear, cr->incremental, &cr->index);
3478 if (ret < 0) {
3479 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "reading console ring buffer");
3480 return ERROR_FAIL;
3482 if (!ret) {
3483 if (cr->count) {
3484 *line_r = cr->buffer;
3485 ret = 1;
3486 } else {
3487 *line_r = NULL;
3488 ret = 0;
3492 return ret;
3495 void libxl_xen_console_read_finish(libxl_ctx *ctx,
3496 libxl_xen_console_reader *cr)
3498 free(cr->buffer);
3499 free(cr);
3502 uint32_t libxl_vm_get_start_time(libxl_ctx *ctx, uint32_t domid)
3504 libxl__gc gc = LIBXL_INIT_GC(ctx);
3505 char *dompath = libxl__xs_get_dompath(&gc, domid);
3506 char *vm_path, *start_time;
3507 uint32_t ret;
3509 vm_path = libxl__xs_read(
3510 &gc, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dompath));
3511 start_time = libxl__xs_read(
3512 &gc, XBT_NULL, libxl__sprintf(&gc, "%s/start_time", vm_path));
3513 if (start_time == NULL) {
3514 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, -1,
3515 "Can't get start time of domain '%d'", domid);
3516 ret = -1;
3517 }else{
3518 ret = strtoul(start_time, NULL, 10);
3520 libxl__free_all(&gc);
3521 return ret;
3524 #define CPUID_REG_INV 0
3525 #define CPUID_REG_EAX 1
3526 #define CPUID_REG_EBX 2
3527 #define CPUID_REG_ECX 3
3528 #define CPUID_REG_EDX 4
3530 /* mapping CPUID features to names
3531 * holds a "name" for each feature, specified by the "leaf" number (and an
3532 * optional "subleaf" in ECX), the "reg"ister (EAX-EDX) used and a number of
3533 * bits starting with "bit" and being "length" bits long.
3534 * Used for the static structure describing all features.
3535 */
3536 struct cpuid_flags {
3537 char* name;
3538 uint32_t leaf;
3539 uint32_t subleaf;
3540 int reg;
3541 int bit;
3542 int length;
3543 };
3545 /* go through the dynamic array finding the entry for a specified leaf.
3546 * if no entry exists, allocate one and return that.
3547 */
3548 static libxl_cpuid_policy_list cpuid_find_match(libxl_cpuid_policy_list *list,
3549 uint32_t leaf, uint32_t subleaf)
3551 int i = 0;
3553 if (*list != NULL) {
3554 for (i = 0; (*list)[i].input[0] != XEN_CPUID_INPUT_UNUSED; i++) {
3555 if ((*list)[i].input[0] == leaf && (*list)[i].input[1] == subleaf)
3556 return *list + i;
3559 *list = realloc(*list, sizeof((*list)[0]) * (i + 2));
3560 (*list)[i].input[0] = leaf;
3561 (*list)[i].input[1] = subleaf;
3562 memset((*list)[i].policy, 0, 4 * sizeof(char*));
3563 (*list)[i + 1].input[0] = XEN_CPUID_INPUT_UNUSED;
3564 return *list + i;
3567 /* parse a single key=value pair and translate it into the libxc
3568 * used interface using 32-characters strings for each register.
3569 * Will overwrite earlier entries and thus can be called multiple
3570 * times.
3571 */
3572 int libxl_cpuid_parse_config(libxl_cpuid_policy_list *cpuid, const char* str)
3574 #define NA XEN_CPUID_INPUT_UNUSED
3575 struct cpuid_flags cpuid_flags[] = {
3576 {"maxleaf", 0x00000000, NA, CPUID_REG_EAX, 0, 32},
3577 /* the following two entries are subject to tweaking later in the code */
3578 {"family", 0x00000001, NA, CPUID_REG_EAX, 8, 8},
3579 {"model", 0x00000001, NA, CPUID_REG_EAX, 4, 8},
3580 {"stepping", 0x00000001, NA, CPUID_REG_EAX, 0, 4},
3581 {"localapicid", 0x00000001, NA, CPUID_REG_EBX, 24, 8},
3582 {"proccount", 0x00000001, NA, CPUID_REG_EBX, 16, 8},
3583 {"clflush", 0x00000001, NA, CPUID_REG_EBX, 8, 8},
3584 {"brandid", 0x00000001, NA, CPUID_REG_EBX, 0, 8},
3585 {"f16c", 0x00000001, NA, CPUID_REG_ECX, 29, 1},
3586 {"avx", 0x00000001, NA, CPUID_REG_ECX, 28, 1},
3587 {"osxsave", 0x00000001, NA, CPUID_REG_ECX, 27, 1},
3588 {"xsave", 0x00000001, NA, CPUID_REG_ECX, 26, 1},
3589 {"aes", 0x00000001, NA, CPUID_REG_ECX, 25, 1},
3590 {"popcnt", 0x00000001, NA, CPUID_REG_ECX, 23, 1},
3591 {"movbe", 0x00000001, NA, CPUID_REG_ECX, 22, 1},
3592 {"x2apic", 0x00000001, NA, CPUID_REG_ECX, 21, 1},
3593 {"sse4.2", 0x00000001, NA, CPUID_REG_ECX, 20, 1},
3594 {"sse4.1", 0x00000001, NA, CPUID_REG_ECX, 19, 1},
3595 {"dca", 0x00000001, NA, CPUID_REG_ECX, 18, 1},
3596 {"pdcm", 0x00000001, NA, CPUID_REG_ECX, 15, 1},
3597 {"xtpr", 0x00000001, NA, CPUID_REG_ECX, 14, 1},
3598 {"cmpxchg16", 0x00000001, NA, CPUID_REG_ECX, 13, 1},
3599 {"cntxid", 0x00000001, NA, CPUID_REG_ECX, 10, 1},
3600 {"ssse3", 0x00000001, NA, CPUID_REG_ECX, 9, 1},
3601 {"tm2", 0x00000001, NA, CPUID_REG_ECX, 8, 1},
3602 {"est", 0x00000001, NA, CPUID_REG_ECX, 7, 1},
3603 {"smx", 0x00000001, NA, CPUID_REG_ECX, 6, 1},
3604 {"vmx", 0x00000001, NA, CPUID_REG_ECX, 5, 1},
3605 {"dscpl", 0x00000001, NA, CPUID_REG_ECX, 4, 1},
3606 {"monitor", 0x00000001, NA, CPUID_REG_ECX, 3, 1},
3607 {"dtes64", 0x00000001, NA, CPUID_REG_ECX, 2, 1},
3608 {"sse3", 0x00000001, NA, CPUID_REG_ECX, 0, 1},
3609 {"pbe", 0x00000001, NA, CPUID_REG_EDX, 31, 1},
3610 {"ia64", 0x00000001, NA, CPUID_REG_EDX, 30, 1},
3611 {"tm", 0x00000001, NA, CPUID_REG_EDX, 29, 1},
3612 {"htt", 0x00000001, NA, CPUID_REG_EDX, 28, 1},
3613 {"ss", 0x00000001, NA, CPUID_REG_EDX, 27, 1},
3614 {"sse2", 0x00000001, NA, CPUID_REG_EDX, 26, 1},
3615 {"sse", 0x00000001, NA, CPUID_REG_EDX, 25, 1},
3616 {"fxsr", 0x00000001, NA, CPUID_REG_EDX, 24, 1},
3617 {"mmx", 0x00000001, NA, CPUID_REG_EDX, 23, 1},
3618 {"acpi", 0x00000001, NA, CPUID_REG_EDX, 22, 1},
3619 {"ds", 0x00000001, NA, CPUID_REG_EDX, 21, 1},
3620 {"clfsh", 0x00000001, NA, CPUID_REG_EDX, 19, 1},
3621 {"psn", 0x00000001, NA, CPUID_REG_EDX, 18, 1},
3622 {"pse36", 0x00000001, NA, CPUID_REG_EDX, 17, 1},
3623 {"pat", 0x00000001, NA, CPUID_REG_EDX, 16, 1},
3624 {"cmov", 0x00000001, NA, CPUID_REG_EDX, 15, 1},
3625 {"mca", 0x00000001, NA, CPUID_REG_EDX, 14, 1},
3626 {"pge", 0x00000001, NA, CPUID_REG_EDX, 13, 1},
3627 {"mtrr", 0x00000001, NA, CPUID_REG_EDX, 12, 1},
3628 {"sysenter", 0x00000001, NA, CPUID_REG_EDX, 11, 1},
3629 {"apic", 0x00000001, NA, CPUID_REG_EDX, 9, 1},
3630 {"cmpxchg8", 0x00000001, NA, CPUID_REG_EDX, 8, 1},
3631 {"mce", 0x00000001, NA, CPUID_REG_EDX, 7, 1},
3632 {"pae", 0x00000001, NA, CPUID_REG_EDX, 6, 1},
3633 {"msr", 0x00000001, NA, CPUID_REG_EDX, 5, 1},
3634 {"tsc", 0x00000001, NA, CPUID_REG_EDX, 4, 1},
3635 {"pse", 0x00000001, NA, CPUID_REG_EDX, 3, 1},
3636 {"de", 0x00000001, NA, CPUID_REG_EDX, 2, 1},
3637 {"vme", 0x00000001, NA, CPUID_REG_EDX, 1, 1},
3638 {"fpu", 0x00000001, NA, CPUID_REG_EDX, 0, 1},
3639 {"topoext", 0x80000001, NA, CPUID_REG_ECX, 22, 1},
3640 {"tbm", 0x80000001, NA, CPUID_REG_ECX, 21, 1},
3641 {"nodeid", 0x80000001, NA, CPUID_REG_ECX, 19, 1},
3642 {"fma4", 0x80000001, NA, CPUID_REG_ECX, 16, 1},
3643 {"lwp", 0x80000001, NA, CPUID_REG_ECX, 15, 1},
3644 {"wdt", 0x80000001, NA, CPUID_REG_ECX, 13, 1},
3645 {"skinit", 0x80000001, NA, CPUID_REG_ECX, 12, 1},
3646 {"xop", 0x80000001, NA, CPUID_REG_ECX, 11, 1},
3647 {"ibs", 0x80000001, NA, CPUID_REG_ECX, 10, 1},
3648 {"osvw", 0x80000001, NA, CPUID_REG_ECX, 10, 1},
3649 {"3dnowprefetch",0x80000001, NA, CPUID_REG_ECX, 8, 1},
3650 {"misalignsse", 0x80000001, NA, CPUID_REG_ECX, 7, 1},
3651 {"sse4a", 0x80000001, NA, CPUID_REG_ECX, 6, 1},
3652 {"abm", 0x80000001, NA, CPUID_REG_ECX, 5, 1},
3653 {"altmovcr8", 0x80000001, NA, CPUID_REG_ECX, 4, 1},
3654 {"extapic", 0x80000001, NA, CPUID_REG_ECX, 3, 1},
3655 {"svm", 0x80000001, NA, CPUID_REG_ECX, 2, 1},
3656 {"cmplegacy", 0x80000001, NA, CPUID_REG_ECX, 1, 1},
3657 {"lahfsahf", 0x80000001, NA, CPUID_REG_ECX, 0, 1},
3658 {"3dnow", 0x80000001, NA, CPUID_REG_EDX, 31, 1},
3659 {"3dnowext", 0x80000001, NA, CPUID_REG_EDX, 30, 1},
3660 {"lm", 0x80000001, NA, CPUID_REG_EDX, 29, 1},
3661 {"rdtscp", 0x80000001, NA, CPUID_REG_EDX, 27, 1},
3662 {"page1gb", 0x80000001, NA, CPUID_REG_EDX, 26, 1},
3663 {"ffxsr", 0x80000001, NA, CPUID_REG_EDX, 25, 1},
3664 {"mmxext", 0x80000001, NA, CPUID_REG_EDX, 22, 1},
3665 {"nx", 0x80000001, NA, CPUID_REG_EDX, 20, 1},
3666 {"syscall", 0x80000001, NA, CPUID_REG_EDX, 11, 1},
3667 {"procpkg", 0x00000004, 0, CPUID_REG_EAX, 26, 6},
3668 {"apicidsize", 0x80000008, NA, CPUID_REG_ECX, 12, 4},
3669 {"nc", 0x80000008, NA, CPUID_REG_ECX, 0, 8},
3671 {NULL, 0, CPUID_REG_INV, 0, 0}
3672 };
3673 #undef NA
3674 char *sep, *val, *endptr;
3675 int i;
3676 struct cpuid_flags *flag;
3677 struct libxl__cpuid_policy *entry;
3678 unsigned long num;
3679 char flags[33], *resstr;
3681 sep = strchr(str, '=');
3682 if (sep == NULL) {
3683 return 1;
3684 } else {
3685 val = sep + 1;
3687 for (flag = cpuid_flags; flag->name != NULL; flag++) {
3688 if(!strncmp(str, flag->name, sep - str) && flag->name[sep - str] == 0)
3689 break;
3691 if (flag->name == NULL) {
3692 return 2;
3694 entry = cpuid_find_match(cpuid, flag->leaf, flag->subleaf);
3695 resstr = entry->policy[flag->reg - 1];
3696 if (resstr == NULL) {
3697 resstr = strdup("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
3699 num = strtoull(val, &endptr, 0);
3700 flags[flag->length] = 0;
3701 if (endptr != val) {
3702 /* is this was a valid number, write the binary form into the string */
3703 for (i = 0; i < flag->length; i++) {
3704 flags[flag->length - 1 - i] = "01"[!!(num & (1 << i))];
3706 } else {
3707 switch(val[0]) {
3708 case 'x': case 'k': case 's':
3709 memset(flags, val[0], flag->length);
3710 break;
3711 default:
3712 return 3;
3715 /* the family and model entry is potentially split up across
3716 * two fields in Fn0000_0001_EAX, so handle them here separately.
3717 */
3718 if (!strncmp(str, "family", sep - str)) {
3719 if (num < 16) {
3720 memcpy(resstr + (32 - 4) - flag->bit, flags + 4, 4);
3721 memcpy(resstr + (32 - 8) - 20, "00000000", 8);
3722 } else {
3723 num -= 15;
3724 memcpy(resstr + (32 - 4) - flag->bit, "1111", 4);
3725 for (i = 0; i < 7; i++) {
3726 flags[7 - i] = "01"[num & 1];
3727 num >>= 1;
3729 memcpy(resstr + (32 - 8) - 20, flags, 8);
3731 } else if (!strncmp(str, "model", sep - str)) {
3732 memcpy(resstr + (32 - 4) - 16, flags, 4);
3733 memcpy(resstr + (32 - 4) - flag->bit, flags + 4, 4);
3734 } else {
3735 memcpy(resstr + (32 - flag->length) - flag->bit, flags,
3736 flag->length);
3738 entry->policy[flag->reg - 1] = resstr;
3740 return 0;
3743 /* parse a single list item from the legacy Python xend syntax, where
3744 * the strings for each register were directly exposed to the user.
3745 * Used for maintaining compatibility with older config files
3746 */
3747 int libxl_cpuid_parse_config_xend(libxl_cpuid_policy_list *cpuid,
3748 const char* str)
3750 char *endptr;
3751 unsigned long value;
3752 uint32_t leaf, subleaf = XEN_CPUID_INPUT_UNUSED;
3753 struct libxl__cpuid_policy *entry;
3755 /* parse the leaf number */
3756 value = strtoul(str, &endptr, 0);
3757 if (str == endptr) {
3758 return 1;
3760 leaf = value;
3761 /* check for an optional subleaf number */
3762 if (*endptr == ',') {
3763 str = endptr + 1;
3764 value = strtoul(str, &endptr, 0);
3765 if (str == endptr) {
3766 return 2;
3768 subleaf = value;
3770 if (*endptr != ':') {
3771 return 3;
3773 str = endptr + 1;
3774 entry = cpuid_find_match(cpuid, leaf, subleaf);
3775 for (str = endptr + 1; *str != 0;) {
3776 if (str[0] != 'e' || str[2] != 'x') {
3777 return 4;
3779 value = str[1] - 'a';
3780 endptr = strchr(str, '=');
3781 if (value < 0 || value > 3 || endptr == NULL) {
3782 return 4;
3784 str = endptr + 1;
3785 endptr = strchr(str, ',');
3786 if (endptr == NULL) {
3787 endptr = strchr(str, 0);
3789 if (endptr - str != 32) {
3790 return 5;
3792 entry->policy[value] = calloc(32 + 1, 1);
3793 strncpy(entry->policy[value], str, 32);
3794 entry->policy[value][32] = 0;
3795 if (*endptr == 0) {
3796 break;
3798 for (str = endptr + 1; *str == ' ' || *str == '\n'; str++);
3800 return 0;
3803 char *libxl_tmem_list(libxl_ctx *ctx, uint32_t domid, int use_long)
3805 int rc;
3806 char _buf[32768];
3808 rc = xc_tmem_control(ctx->xch, -1, TMEMC_LIST, domid, 32768, use_long,
3809 0, _buf);
3810 if (rc < 0) {
3811 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
3812 "Can not get tmem list");
3813 return NULL;
3816 return strdup(_buf);
3819 int libxl_tmem_freeze(libxl_ctx *ctx, uint32_t domid)
3821 int rc;
3823 rc = xc_tmem_control(ctx->xch, -1, TMEMC_FREEZE, domid, 0, 0,
3824 0, NULL);
3825 if (rc < 0) {
3826 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
3827 "Can not freeze tmem pools");
3828 return ERROR_FAIL;
3831 return rc;
3834 int libxl_tmem_destroy(libxl_ctx *ctx, uint32_t domid)
3836 int rc;
3838 rc = xc_tmem_control(ctx->xch, -1, TMEMC_DESTROY, domid, 0, 0,
3839 0, NULL);
3840 if (rc < 0) {
3841 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
3842 "Can not destroy tmem pools");
3843 return ERROR_FAIL;
3846 return rc;
3849 int libxl_tmem_thaw(libxl_ctx *ctx, uint32_t domid)
3851 int rc;
3853 rc = xc_tmem_control(ctx->xch, -1, TMEMC_THAW, domid, 0, 0,
3854 0, NULL);
3855 if (rc < 0) {
3856 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
3857 "Can not thaw tmem pools");
3858 return ERROR_FAIL;
3861 return rc;
3864 static int32_t tmem_setop_from_string(char *set_name)
3866 if (!strcmp(set_name, "weight"))
3867 return TMEMC_SET_WEIGHT;
3868 else if (!strcmp(set_name, "cap"))
3869 return TMEMC_SET_CAP;
3870 else if (!strcmp(set_name, "compress"))
3871 return TMEMC_SET_COMPRESS;
3872 else
3873 return -1;
3876 int libxl_tmem_set(libxl_ctx *ctx, uint32_t domid, char* name, uint32_t set)
3878 int rc;
3879 int32_t subop = tmem_setop_from_string(name);
3881 if (subop == -1) {
3882 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, -1,
3883 "Invalid set, valid sets are <weight|cap|compress>");
3884 return ERROR_INVAL;
3886 rc = xc_tmem_control(ctx->xch, -1, subop, domid, set, 0, 0, NULL);
3887 if (rc < 0) {
3888 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
3889 "Can not set tmem %s", name);
3890 return ERROR_FAIL;
3893 return rc;
3896 int libxl_tmem_shared_auth(libxl_ctx *ctx, uint32_t domid,
3897 char* uuid, int auth)
3899 int rc;
3901 rc = xc_tmem_auth(ctx->xch, domid, uuid, auth);
3902 if (rc < 0) {
3903 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
3904 "Can not set tmem shared auth");
3905 return ERROR_FAIL;
3908 return rc;
3911 int libxl_tmem_freeable(libxl_ctx *ctx)
3913 int rc;
3915 rc = xc_tmem_control(ctx->xch, -1, TMEMC_QUERY_FREEABLE_MB, -1, 0, 0, 0, 0);
3916 if (rc < 0) {
3917 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
3918 "Can not get tmem freeable memory");
3919 return ERROR_FAIL;
3922 return rc;
3925 void libxl_file_reference_destroy(libxl_file_reference *f)
3927 libxl__file_reference_unmap(f);
3928 free(f->path);
3931 int libxl_get_freecpus(libxl_ctx *ctx, libxl_cpumap *cpumap)
3933 int ncpus;
3935 cpumap->map = xc_cpupool_freeinfo(ctx->xch, &ncpus);
3936 if (cpumap->map == NULL)
3937 return ERROR_FAIL;
3939 cpumap->size = (ncpus + 7) / 8;
3941 return 0;
3944 int libxl_create_cpupool(libxl_ctx *ctx, char *name, int schedid,
3945 libxl_cpumap cpumap, libxl_uuid *uuid,
3946 uint32_t *poolid)
3948 libxl__gc gc = LIBXL_INIT_GC(ctx);
3949 int rc;
3950 int i;
3951 xs_transaction_t t;
3952 char *uuid_string;
3954 uuid_string = libxl__uuid2string(&gc, *uuid);
3955 if (!uuid_string)
3956 return ERROR_NOMEM;
3958 rc = xc_cpupool_create(ctx->xch, poolid, schedid);
3959 if (rc) {
3960 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
3961 "Could not create cpupool");
3962 return ERROR_FAIL;
3965 for (i = 0; i < cpumap.size * 8; i++)
3966 if (cpumap.map[i / 64] & (1L << (i % 64))) {
3967 rc = xc_cpupool_addcpu(ctx->xch, *poolid, i);
3968 if (rc) {
3969 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
3970 "Error moving cpu to cpupool");
3971 libxl_destroy_cpupool(ctx, *poolid);
3972 return ERROR_FAIL;
3976 for (;;) {
3977 t = xs_transaction_start(ctx->xsh);
3979 xs_mkdir(ctx->xsh, t, libxl__sprintf(&gc, "/local/pool/%d", *poolid));
3980 libxl__xs_write(&gc, t, libxl__sprintf(&gc, "/local/pool/%d/uuid", *poolid),
3981 uuid_string);
3982 libxl__xs_write(&gc, t, libxl__sprintf(&gc, "/local/pool/%d/name", *poolid),
3983 name);
3985 if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN))
3986 return 0;
3990 int libxl_destroy_cpupool(libxl_ctx *ctx, uint32_t poolid)
3992 libxl__gc gc = LIBXL_INIT_GC(ctx);
3993 int rc, i;
3994 xc_cpupoolinfo_t *info;
3995 xs_transaction_t t;
3997 info = xc_cpupool_getinfo(ctx->xch, poolid);
3998 if (info == NULL)
3999 return ERROR_NOMEM;
4001 rc = ERROR_INVAL;
4002 if ((info->cpupool_id != poolid) || (info->n_dom))
4003 goto out;
4005 for (i = 0; i < info->cpumap_size; i++)
4006 if (info->cpumap[i / 64] & (1L << (i % 64))) {
4007 rc = xc_cpupool_removecpu(ctx->xch, poolid, i);
4008 if (rc) {
4009 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
4010 "Error removing cpu from cpupool");
4011 rc = ERROR_FAIL;
4012 goto out;
4016 rc = xc_cpupool_destroy(ctx->xch, poolid);
4017 if (rc) {
4018 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc, "Could not destroy cpupool");
4019 rc = ERROR_FAIL;
4020 goto out;
4023 for (;;) {
4024 t = xs_transaction_start(ctx->xsh);
4026 xs_rm(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "/local/pool/%d", poolid));
4028 if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN))
4029 break;
4032 rc = 0;
4034 out:
4035 free(info);
4037 return rc;
4040 int libxl_cpupool_cpuadd(libxl_ctx *ctx, uint32_t poolid, int cpu)
4042 int rc;
4044 rc = xc_cpupool_addcpu(ctx->xch, poolid, cpu);
4045 if (rc) {
4046 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
4047 "Error moving cpu to cpupool");
4048 return ERROR_FAIL;
4050 return 0;
4053 int libxl_cpupool_cpuremove(libxl_ctx *ctx, uint32_t poolid, int cpu)
4055 int rc;
4057 rc = xc_cpupool_removecpu(ctx->xch, poolid, cpu);
4058 if (rc) {
4059 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
4060 "Error removing cpu from cpupool");
4061 return ERROR_FAIL;
4063 return 0;
4066 int libxl_cpupool_movedomain(libxl_ctx *ctx, uint32_t poolid, uint32_t domid)
4068 libxl__gc gc = LIBXL_INIT_GC(ctx);
4069 int rc;
4070 char *dom_path;
4071 char *vm_path;
4072 char *poolname;
4073 xs_transaction_t t;
4075 dom_path = libxl__xs_get_dompath(&gc, domid);
4076 if (!dom_path) {
4077 return ERROR_FAIL;
4080 rc = xc_cpupool_movedomain(ctx->xch, poolid, domid);
4081 if (rc) {
4082 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, rc,
4083 "Error moving domain to cpupool");
4084 return ERROR_FAIL;
4087 for (;;) {
4088 t = xs_transaction_start(ctx->xsh);
4090 poolname = libxl__cpupoolid_to_name(&gc, poolid);
4091 vm_path = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/vm", dom_path));
4092 if (!vm_path)
4093 break;
4095 libxl__xs_write(&gc, t, libxl__sprintf(&gc, "%s/pool_name", vm_path), poolname);
4097 if (xs_transaction_end(ctx->xsh, t, 0) || (errno != EAGAIN))
4098 break;
4101 return 0;