debuggers.hg

annotate tools/libxl/libxl.c @ 21186:d005aa895b5a

xenstore,libxl: cleanup of xenstore connections across fork()

Provide a new function xs_daemon_destroy_postfork which can be called
by a libxenstore user who has called fork, to close the fd for the
connection to xenstored and free the memory, without trying to do
anything to any threads which libxenstore may have created.

Use this new function in libxl_fork, to avoid accidental use of a
xenstore connection in both parent and child.

Also, fix the doc comment for libxl_spawn_spawn to have the success
return codes the right way round.

Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Apr 12 17:41:58 2010 +0100 (2010-04-12)
parents 86e82ab8d4de
children cd05b6aa8c0a
rev   line source
keir@20462 1 /*
keir@20462 2 * Copyright (C) 2009 Citrix Ltd.
keir@20462 3 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
keir@20462 4 * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
keir@20462 5 *
keir@20462 6 * This program is free software; you can redistribute it and/or modify
keir@20462 7 * it under the terms of the GNU Lesser General Public License as published
keir@20462 8 * by the Free Software Foundation; version 2.1 only. with the special
keir@20462 9 * exception on linking described in file LICENSE.
keir@20462 10 *
keir@20462 11 * This program is distributed in the hope that it will be useful,
keir@20462 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
keir@20462 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
keir@20462 14 * GNU Lesser General Public License for more details.
keir@20462 15 */
keir@20462 16
keir@20513 17 #include "libxl_osdeps.h"
keir@20513 18
keir@20462 19 #include <stdio.h>
keir@20462 20 #include <string.h>
keir@20462 21 #include <stdlib.h>
keir@20462 22 #include <sys/types.h>
keir@20462 23 #include <fcntl.h>
keir@20462 24 #include <sys/select.h>
keir@20514 25 #include <sys/wait.h>
keir@20462 26 #include <signal.h>
keir@20468 27 #include <unistd.h> /* for write, unlink and close */
keir@20509 28 #include <stdint.h>
keir@20509 29 #include <inttypes.h>
keir@20514 30 #include <assert.h>
keir@20513 31
keir@20462 32 #include "libxl.h"
keir@20462 33 #include "libxl_utils.h"
keir@20462 34 #include "libxl_internal.h"
keir@20462 35 #include "flexarray.h"
keir@20462 36
keir@20860 37 #define PAGE_TO_MEMKB(pages) ((pages) * 4)
keir@20860 38
keir@20788 39 int libxl_ctx_init(struct libxl_ctx *ctx, int version)
keir@20462 40 {
keir@20788 41 if (version != LIBXL_VERSION)
keir@20788 42 return ERROR_VERSION;
keir@20462 43 memset(ctx, 0, sizeof(struct libxl_ctx));
keir@20462 44 ctx->alloc_maxsize = 256;
keir@20462 45 ctx->alloc_ptrs = calloc(ctx->alloc_maxsize, sizeof(void *));
keir@20462 46 if (!ctx->alloc_ptrs)
keir@20462 47 return ERROR_NOMEM;
keir@20462 48
keir@20462 49 ctx->xch = xc_interface_open();
keir@20819 50 if (ctx->xch == -1) {
keir@20819 51 free(ctx->alloc_ptrs);
keir@20819 52 return ERROR_FAIL;
keir@20819 53 }
keir@20819 54
keir@20462 55 ctx->xsh = xs_daemon_open();
keir@20819 56 if (!ctx->xsh) {
keir@20819 57 xc_interface_close(ctx->xch);
keir@20819 58 free(ctx->alloc_ptrs);
keir@20819 59 return ERROR_FAIL;
keir@20819 60 }
keir@20462 61 return 0;
keir@20462 62 }
keir@20462 63
keir@20462 64 int libxl_ctx_free(struct libxl_ctx *ctx)
keir@20462 65 {
keir@20462 66 libxl_free_all(ctx);
keir@20462 67 free(ctx->alloc_ptrs);
keir@20462 68 xc_interface_close(ctx->xch);
keir@21186 69 if (ctx->xsh) xs_daemon_close(ctx->xsh);
keir@20462 70 return 0;
keir@20462 71 }
keir@20462 72
keir@20462 73 int libxl_ctx_set_log(struct libxl_ctx *ctx, libxl_log_callback log_callback, void *log_data)
keir@20462 74 {
keir@20462 75 ctx->log_callback = log_callback;
keir@20462 76 ctx->log_userdata = log_data;
keir@20462 77 return 0;
keir@20462 78 }
keir@20462 79
keir@20462 80 /******************************************************************************/
keir@20462 81
keir@20462 82 int libxl_domain_make(struct libxl_ctx *ctx, libxl_domain_create_info *info,
keir@20462 83 uint32_t *domid)
keir@20462 84 {
keir@21184 85 int flags, ret, i, rc;
keir@20468 86 char *uuid_string;
keir@20646 87 char *rw_paths[] = { "device", "device/suspend/event-channel" , "data"};
keir@20462 88 char *ro_paths[] = { "cpu", "memory", "device", "error", "drivers",
keir@20646 89 "control", "attr", "messages" };
keir@20462 90 char *dom_path, *vm_path, *vss_path;
keir@20462 91 struct xs_permissions roperm[2];
keir@20462 92 struct xs_permissions rwperm[1];
keir@20462 93 xs_transaction_t t;
keir@20468 94 xen_domain_handle_t handle;
keir@20462 95
keir@20801 96 uuid_string = string_of_uuid(ctx, info->uuid);
keir@20462 97 if (!uuid_string) {
keir@20801 98 XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate uuid string");
keir@20462 99 return ERROR_FAIL;
keir@20462 100 }
keir@20462 101
keir@20462 102 flags = info->hvm ? XEN_DOMCTL_CDF_hvm_guest : 0;
keir@20462 103 flags |= info->hap ? XEN_DOMCTL_CDF_hap : 0;
keir@20824 104 *domid = -1;
keir@20462 105
keir@20580 106 /* Ultimately, handle is an array of 16 uint8_t, same as uuid */
keir@20580 107 memcpy(handle, info->uuid, sizeof(xen_domain_handle_t));
keir@20468 108
keir@20468 109 ret = xc_domain_create(ctx->xch, info->ssidref, handle, flags, domid);
keir@20462 110 if (ret < 0) {
keir@20512 111 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, ret, "domain creation fail");
keir@20462 112 return ERROR_FAIL;
keir@20462 113 }
keir@20462 114
keir@20462 115 dom_path = libxl_xs_get_dompath(ctx, *domid);
keir@20512 116 if (!dom_path)
keir@20512 117 return ERROR_FAIL;
keir@20512 118
keir@20462 119 vm_path = libxl_sprintf(ctx, "/vm/%s", uuid_string);
keir@20462 120 vss_path = libxl_sprintf(ctx, "/vss/%s", uuid_string);
keir@20512 121 if (!vm_path || !vss_path) {
keir@20462 122 XL_LOG(ctx, XL_LOG_ERROR, "cannot allocate create paths");
keir@20462 123 return ERROR_FAIL;
keir@20462 124 }
keir@20462 125
keir@20462 126 roperm[0].id = 0;
keir@20462 127 roperm[0].perms = XS_PERM_NONE;
keir@20462 128 roperm[1].id = *domid;
keir@20462 129 roperm[1].perms = XS_PERM_READ;
keir@20462 130 rwperm[0].id = *domid;
keir@20462 131 rwperm[0].perms = XS_PERM_NONE;
keir@20462 132
keir@20462 133 retry_transaction:
keir@20462 134 t = xs_transaction_start(ctx->xsh);
keir@20462 135 xs_rm(ctx->xsh, t, dom_path);
keir@20462 136 xs_mkdir(ctx->xsh, t, dom_path);
keir@20462 137 xs_set_permissions(ctx->xsh, t, dom_path, roperm, ARRAY_SIZE(roperm));
keir@20462 138
keir@20462 139 xs_rm(ctx->xsh, t, vm_path);
keir@20462 140 xs_mkdir(ctx->xsh, t, vm_path);
keir@20462 141 xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));
keir@20462 142
keir@20462 143 xs_rm(ctx->xsh, t, vss_path);
keir@20462 144 xs_mkdir(ctx->xsh, t, vss_path);
keir@20462 145 xs_set_permissions(ctx->xsh, t, vss_path, rwperm, ARRAY_SIZE(rwperm));
keir@20462 146
keir@20462 147 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vm", dom_path), vm_path, strlen(vm_path));
keir@20462 148 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vss", dom_path), vss_path, strlen(vss_path));
keir@21184 149 rc = libxl_domain_rename(ctx, *domid, 0, info->name, t);
keir@21184 150 if (rc) return rc;
keir@20462 151
keir@20462 152 for (i = 0; i < ARRAY_SIZE(rw_paths); i++) {
keir@20462 153 char *path = libxl_sprintf(ctx, "%s/%s", dom_path, rw_paths[i]);
keir@20462 154 xs_mkdir(ctx->xsh, t, path);
keir@20462 155 xs_set_permissions(ctx->xsh, t, path, rwperm, ARRAY_SIZE(rwperm));
keir@20462 156 libxl_free(ctx, path);
keir@20462 157 }
keir@20462 158 for (i = 0; i < ARRAY_SIZE(ro_paths); i++) {
keir@20462 159 char *path = libxl_sprintf(ctx, "%s/%s", dom_path, ro_paths[i]);
keir@20462 160 xs_mkdir(ctx->xsh, t, path);
keir@20462 161 xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm));
keir@20462 162 libxl_free(ctx, path);
keir@20462 163 }
keir@20462 164
keir@20462 165 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
keir@20462 166 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/name", vm_path), info->name, strlen(info->name));
keir@20462 167
keir@20462 168 libxl_xs_writev(ctx, t, dom_path, info->xsdata);
keir@20462 169 libxl_xs_writev(ctx, t, libxl_sprintf(ctx, "%s/platform", dom_path), info->platformdata);
keir@20462 170
keir@20462 171 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1);
keir@20462 172
keir@20462 173 if (!xs_transaction_end(ctx->xsh, t, 0))
keir@20462 174 if (errno == EAGAIN)
keir@20462 175 goto retry_transaction;
keir@20462 176 return 0;
keir@20462 177 }
keir@20462 178
keir@21184 179 int libxl_domain_rename(struct libxl_ctx *ctx, uint32_t domid,
keir@21184 180 const char *old_name, const char *new_name,
keir@21184 181 xs_transaction_t trans) {
keir@21184 182 char *dom_path = 0;
keir@21184 183 const char *name_path;
keir@21184 184 char *got_old_name;
keir@21184 185 unsigned int got_old_len;
keir@21184 186 xs_transaction_t our_trans = 0;
keir@21184 187 int rc;
keir@21184 188
keir@21184 189 dom_path = libxl_xs_get_dompath(ctx, domid);
keir@21184 190 if (!dom_path) goto x_nomem;
keir@21184 191
keir@21184 192 name_path= libxl_sprintf(ctx, "%s/name", dom_path);
keir@21184 193 if (!name_path) goto x_nomem;
keir@21184 194
keir@21184 195 retry_transaction:
keir@21184 196 if (!trans) {
keir@21184 197 trans = our_trans = xs_transaction_start(ctx->xsh);
keir@21184 198 if (!our_trans) {
keir@21184 199 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, errno,
keir@21184 200 "create xs transaction for domain (re)name");
keir@21184 201 goto x_fail;
keir@21184 202 }
keir@21184 203 }
keir@21184 204
keir@21184 205 if (old_name) {
keir@21184 206 got_old_name = xs_read(ctx->xsh, trans, name_path, &got_old_len);
keir@21184 207 if (!got_old_name) {
keir@21184 208 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, errno, "check old name"
keir@21184 209 " for domain %"PRIu32" allegedly named `%s'",
keir@21184 210 domid, old_name);
keir@21184 211 goto x_fail;
keir@21184 212 }
keir@21184 213 if (strcmp(old_name, got_old_name)) {
keir@21184 214 XL_LOG(ctx, XL_LOG_ERROR, "domain %"PRIu32" allegedly named "
keir@21184 215 "`%s' is actually named `%s' - racing ?",
keir@21184 216 domid, old_name, got_old_name);
keir@21184 217 free(got_old_name);
keir@21184 218 goto x_fail;
keir@21184 219 }
keir@21184 220 free(got_old_name);
keir@21184 221 }
keir@21184 222 if (!xs_write(ctx->xsh, trans, name_path,
keir@21184 223 new_name, strlen(new_name))) {
keir@21184 224 XL_LOG(ctx, XL_LOG_ERROR, "failed to write new name `%s'"
keir@21184 225 " for domain %"PRIu32" previously named `%s'",
keir@21184 226 domid, new_name, old_name);
keir@21184 227 goto x_fail;
keir@21184 228 }
keir@21184 229
keir@21184 230 if (our_trans) {
keir@21184 231 if (!xs_transaction_end(ctx->xsh, our_trans, 0)) {
keir@21184 232 trans = our_trans = 0;
keir@21184 233 if (errno != EAGAIN) {
keir@21184 234 XL_LOG(ctx, XL_LOG_ERROR, "failed to commit new name `%s'"
keir@21184 235 " for domain %"PRIu32" previously named `%s'",
keir@21184 236 domid, new_name, old_name);
keir@21184 237 goto x_fail;
keir@21184 238 }
keir@21184 239 XL_LOG(ctx, XL_LOG_DEBUG, "need to retry rename transaction"
keir@21184 240 " for domain %"PRIu32" (name_path=\"%s\", new_name=\"%s\")",
keir@21184 241 domid, name_path, new_name);
keir@21184 242 goto retry_transaction;
keir@21184 243 }
keir@21184 244 our_trans = 0;
keir@21184 245 }
keir@21184 246
keir@21184 247 rc = 0;
keir@21184 248 x_rc:
keir@21184 249 if (dom_path) libxl_free(ctx, dom_path);
keir@21184 250 if (our_trans) xs_transaction_end(ctx->xsh, our_trans, 1);
keir@21184 251 return rc;
keir@21184 252
keir@21184 253 x_fail: rc = ERROR_FAIL; goto x_rc;
keir@21184 254 x_nomem: rc = ERROR_NOMEM; goto x_rc;
keir@21184 255 }
keir@21184 256
keir@20516 257 int libxl_domain_build(struct libxl_ctx *ctx, libxl_domain_build_info *info, uint32_t domid, libxl_domain_build_state *state)
keir@20462 258 {
keir@20462 259 char **vments = NULL, **localents = NULL;
keir@20829 260 int i, ret;
keir@20829 261
keir@20829 262 ret = build_pre(ctx, domid, info, state);
keir@20829 263 if (ret) goto out;
keir@20462 264
keir@20462 265 if (info->hvm) {
keir@20829 266 ret = build_hvm(ctx, domid, info, state);
keir@20829 267 if (ret) goto out;
keir@20829 268
keir@20509 269 vments = libxl_calloc(ctx, 5, sizeof(char *));
keir@20516 270 vments[0] = "rtc/timeoffset";
keir@20516 271 vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
keir@20516 272 vments[2] = "image/ostype";
keir@20516 273 vments[3] = "hvm";
keir@20462 274 } else {
keir@20829 275 ret = build_pv(ctx, domid, info, state);
keir@20829 276 if (ret) goto out;
keir@20829 277
keir@20509 278 vments = libxl_calloc(ctx, 9, sizeof(char *));
keir@20578 279 i = 0;
keir@20578 280 vments[i++] = "image/ostype";
keir@20578 281 vments[i++] = "linux";
keir@20578 282 vments[i++] = "image/kernel";
keir@20578 283 vments[i++] = (char*) info->kernel;
keir@20578 284 if (info->u.pv.ramdisk) {
keir@20578 285 vments[i++] = "image/ramdisk";
keir@20578 286 vments[i++] = (char*) info->u.pv.ramdisk;
keir@20578 287 }
keir@20578 288 if (info->u.pv.cmdline) {
keir@20578 289 vments[i++] = "image/cmdline";
keir@20578 290 vments[i++] = (char*) info->u.pv.cmdline;
keir@20578 291 }
keir@20462 292 }
keir@20829 293 ret = build_post(ctx, domid, info, state, vments, localents);
keir@20829 294 out:
keir@20829 295 return ret;
keir@20462 296 }
keir@20462 297
keir@20462 298 int libxl_domain_restore(struct libxl_ctx *ctx, libxl_domain_build_info *info,
keir@20565 299 uint32_t domid, int fd, libxl_domain_build_state *state,
keir@20565 300 libxl_device_model_info *dm_info)
keir@20462 301 {
keir@20462 302 char **vments = NULL, **localents = NULL;
keir@21183 303 int i, ret, esave, flags;
keir@20462 304
keir@20829 305 ret = build_pre(ctx, domid, info, state);
keir@20829 306 if (ret) goto out;
keir@20829 307
keir@20829 308 ret = restore_common(ctx, domid, info, state, fd);
keir@20829 309 if (ret) goto out;
keir@20829 310
keir@20462 311 if (info->hvm) {
keir@20565 312 vments = libxl_calloc(ctx, 5, sizeof(char *));
keir@20516 313 vments[0] = "rtc/timeoffset";
keir@20516 314 vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
keir@20565 315 vments[2] = "image/ostype";
keir@20565 316 vments[3] = "hvm";
keir@20462 317 } else {
keir@20565 318 vments = libxl_calloc(ctx, 9, sizeof(char *));
keir@20627 319 i = 0;
keir@20627 320 vments[i++] = "image/ostype";
keir@20627 321 vments[i++] = "linux";
keir@20627 322 vments[i++] = "image/kernel";
keir@20627 323 vments[i++] = (char*) info->kernel;
keir@20627 324 if (info->u.pv.ramdisk) {
keir@20627 325 vments[i++] = "image/ramdisk";
keir@20627 326 vments[i++] = (char*) info->u.pv.ramdisk;
keir@20627 327 }
keir@20627 328 if (info->u.pv.cmdline) {
keir@20627 329 vments[i++] = "image/cmdline";
keir@20627 330 vments[i++] = (char*) info->u.pv.cmdline;
keir@20627 331 }
keir@20462 332 }
keir@20829 333 ret = build_post(ctx, domid, info, state, vments, localents);
keir@20829 334 if (ret) goto out;
keir@20829 335
keir@20565 336 if (info->hvm)
keir@20565 337 asprintf(&(dm_info->saved_state), "/var/lib/xen/qemu-save.%d", domid);
keir@20565 338 else
keir@20565 339 dm_info->saved_state = NULL;
keir@20829 340 out:
keir@21183 341 esave = errno;
keir@21183 342
keir@21183 343 flags = fcntl(fd, F_GETFL);
keir@21183 344 if (flags == -1) {
keir@21183 345 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "unable to get flags on restore fd");
keir@21183 346 } else {
keir@21183 347 flags &= ~O_NONBLOCK;
keir@21183 348 if (fcntl(fd, F_SETFL, flags) == -1)
keir@21183 349 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "unable to put restore fd"
keir@21183 350 " back to blocking mode");
keir@21183 351 }
keir@21183 352
keir@21183 353 errno = esave;
keir@20829 354 return ret;
keir@20462 355 }
keir@20462 356
keir@20629 357 int libxl_domain_resume(struct libxl_ctx *ctx, uint32_t domid)
keir@20629 358 {
keir@20629 359 if (is_hvm(ctx, domid)) {
keir@20629 360 XL_LOG(ctx, XL_LOG_DEBUG, "Called domain_resume on "
keir@20629 361 "non-cooperative hvm domain %u", domid);
keir@20629 362 return ERROR_NI;
keir@20629 363 }
keir@20629 364 if (xc_domain_resume(ctx->xch, domid, 1)) {
keir@20629 365 XL_LOG_ERRNO(ctx, XL_LOG_ERROR,
keir@20629 366 "xc_domain_resume failed for domain %u",
keir@20629 367 domid);
keir@20629 368 return ERROR_FAIL;
keir@20629 369 }
keir@20629 370 if (!xs_resume_domain(ctx->xsh, domid)) {
keir@20629 371 XL_LOG_ERRNO(ctx, XL_LOG_ERROR,
keir@20629 372 "xs_resume_domain failed for domain %u",
keir@20629 373 domid);
keir@20629 374 return ERROR_FAIL;
keir@20629 375 }
keir@20629 376 return 0;
keir@20629 377 }
keir@20629 378
keir@20860 379 struct libxl_dominfo * libxl_list_domain(struct libxl_ctx *ctx, int *nb_domain)
keir@20462 380 {
keir@20462 381 struct libxl_dominfo *ptr;
keir@20867 382 int i, ret;
keir@20822 383 xc_domaininfo_t info[1024];
keir@20822 384 int size = 1024;
keir@20462 385
keir@20516 386 ptr = calloc(size, sizeof(struct libxl_dominfo));
keir@20462 387 if (!ptr)
keir@20462 388 return NULL;
keir@20822 389
keir@20860 390 ret = xc_domain_getinfolist(ctx->xch, 0, 1024, info);
keir@20867 391 for (i = 0; i < ret; i++) {
keir@20867 392 memcpy(&(ptr[i].uuid), info[i].handle, sizeof(xen_domain_handle_t));
keir@20867 393 ptr[i].domid = info[i].domain;
keir@20784 394
keir@20784 395 if (info[i].flags & XEN_DOMINF_dying)
keir@20867 396 ptr[i].dying = 1;
keir@20784 397 else if (info[i].flags & XEN_DOMINF_paused)
keir@20867 398 ptr[i].paused = 1;
keir@20784 399 else if (info[i].flags & XEN_DOMINF_blocked || info[i].flags & XEN_DOMINF_running)
keir@20867 400 ptr[i].running = 1;
keir@20867 401 ptr[i].max_memkb = PAGE_TO_MEMKB(info[i].tot_pages);
keir@20867 402 ptr[i].cpu_time = info[i].cpu_time;
keir@20867 403 ptr[i].vcpu_max_id = info[i].max_vcpu_id;
keir@20867 404 ptr[i].vcpu_online = info[i].nr_online_vcpus;
keir@20462 405 }
keir@20867 406 *nb_domain = ret;
keir@20462 407 return ptr;
keir@20462 408 }
keir@20462 409
keir@20860 410 /* this API call only list VM running on this host. a VM can be an aggregate of multiple domains. */
keir@20860 411 struct libxl_vminfo * libxl_list_vm(struct libxl_ctx *ctx, int *nb_vm)
keir@20860 412 {
keir@20860 413 struct libxl_vminfo *ptr;
keir@20860 414 int index, i, ret;
keir@20860 415 xc_domaininfo_t info[1024];
keir@20860 416 int size = 1024;
keir@20860 417
keir@20860 418 ptr = calloc(size, sizeof(struct libxl_dominfo));
keir@20860 419 if (!ptr)
keir@20860 420 return NULL;
keir@20860 421
keir@20860 422 ret = xc_domain_getinfolist(ctx->xch, 1, 1024, info);
keir@20860 423 for (index = i = 0; i < ret; i++) {
keir@20860 424 if (libxl_is_stubdom(ctx, info[i].domain, NULL))
keir@20860 425 continue;
keir@20860 426 memcpy(&(ptr[index].uuid), info[i].handle, sizeof(xen_domain_handle_t));
keir@20860 427 ptr[index].domid = info[i].domain;
keir@20860 428
keir@20860 429 index++;
keir@20860 430 }
keir@20860 431 *nb_vm = index;
keir@20860 432 return ptr;
keir@20860 433 }
keir@20860 434
keir@20462 435 int libxl_domain_suspend(struct libxl_ctx *ctx, libxl_domain_suspend_info *info,
keir@20462 436 uint32_t domid, int fd)
keir@20462 437 {
keir@20565 438 int hvm = is_hvm(ctx, domid);
keir@20565 439 int live = info != NULL && info->flags & XL_SUSPEND_LIVE;
keir@20565 440 int debug = info != NULL && info->flags & XL_SUSPEND_LIVE;
keir@20462 441
keir@20462 442 core_suspend(ctx, domid, fd, hvm, live, debug);
keir@20565 443 if (hvm)
keir@20779 444 save_device_model(ctx, domid, fd);
keir@20462 445 return 0;
keir@20462 446 }
keir@20462 447
keir@20462 448 int libxl_domain_pause(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 449 {
keir@20462 450 xc_domain_pause(ctx->xch, domid);
keir@20462 451 return 0;
keir@20462 452 }
keir@20462 453
keir@20462 454 int libxl_domain_unpause(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 455 {
keir@20779 456 char *path;
keir@20565 457 char *state;
keir@20565 458
keir@20565 459 if (is_hvm(ctx, domid)) {
keir@20779 460 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/state", domid);
keir@20565 461 state = libxl_xs_read(ctx, XBT_NULL, path);
keir@20565 462 if (state != NULL && !strcmp(state, "paused")) {
keir@20565 463 libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid), "continue", strlen("continue"));
keir@20565 464 libxl_wait_for_device_model(ctx, domid, "running", NULL, NULL);
keir@20565 465 }
keir@20565 466 }
keir@20462 467 xc_domain_unpause(ctx->xch, domid);
keir@20565 468
keir@20462 469 return 0;
keir@20462 470 }
keir@20462 471
keir@20462 472 static char *req_table[] = {
keir@20462 473 [0] = "poweroff",
keir@20462 474 [1] = "reboot",
keir@20462 475 [2] = "suspend",
keir@20462 476 [3] = "crash",
keir@20462 477 [4] = "halt",
keir@20462 478 };
keir@20462 479
keir@20462 480 int libxl_domain_shutdown(struct libxl_ctx *ctx, uint32_t domid, int req)
keir@20462 481 {
keir@20462 482 char *shutdown_path;
keir@20462 483 char *dom_path;
keir@20462 484
keir@20462 485 if (req > ARRAY_SIZE(req_table))
keir@20462 486 return ERROR_INVAL;
keir@20462 487
keir@20462 488 dom_path = libxl_xs_get_dompath(ctx, domid);
keir@20512 489 if (!dom_path)
keir@20512 490 return ERROR_FAIL;
keir@20512 491
keir@20462 492 shutdown_path = libxl_sprintf(ctx, "%s/control/shutdown", dom_path);
keir@20462 493
keir@20462 494 xs_write(ctx->xsh, XBT_NULL, shutdown_path, req_table[req], strlen(req_table[req]));
keir@20462 495 if (/* hvm */ 0) {
keir@20462 496 unsigned long acpi_s_state = 0;
keir@20462 497 unsigned long pvdriver = 0;
keir@20462 498 xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_ACPI_S_STATE, &acpi_s_state);
keir@20462 499 xc_get_hvm_param(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver);
keir@20462 500 if (!pvdriver && acpi_s_state != 0)
keir@20462 501 xc_domain_shutdown(ctx->xch, domid, req);
keir@20462 502 }
keir@20462 503 return 0;
keir@20462 504 }
keir@20462 505
keir@20637 506 int libxl_get_wait_fd(struct libxl_ctx *ctx, int *fd)
keir@20545 507 {
keir@20545 508 *fd = xs_fileno(ctx->xsh);
keir@20545 509 return 0;
keir@20545 510 }
keir@20545 511
keir@20637 512 int libxl_wait_for_domain_death(struct libxl_ctx *ctx, uint32_t domid, libxl_waiter *waiter)
keir@20637 513 {
keir@20637 514 waiter->path = strdup("@releaseDomain");
keir@20637 515 asprintf(&(waiter->token), "%d", DOMAIN_DEATH);
keir@20637 516 if (!xs_watch(ctx->xsh, waiter->path, waiter->token))
keir@20637 517 return -1;
keir@20637 518 return 0;
keir@20637 519 }
keir@20637 520
keir@20637 521 int libxl_wait_for_disk_ejects(struct libxl_ctx *ctx, uint32_t guest_domid, libxl_device_disk *disks, int num_disks, libxl_waiter *waiter)
keir@20637 522 {
keir@20637 523 int i;
keir@20637 524 uint32_t domid = libxl_get_stubdom_id(ctx, guest_domid);
keir@20637 525
keir@20637 526 if (!domid)
keir@20637 527 domid = guest_domid;
keir@20637 528
keir@20637 529 for (i = 0; i < num_disks; i++) {
keir@20637 530 asprintf(&(waiter[i].path), "%s/device/vbd/%d/eject", libxl_xs_get_dompath(ctx, domid), device_disk_dev_number(disks[i].virtpath));
keir@20637 531 asprintf(&(waiter[i].token), "%d", DISK_EJECT);
keir@20637 532 xs_watch(ctx->xsh, waiter->path, waiter->token);
keir@20637 533 }
keir@20637 534 return 0;
keir@20637 535 }
keir@20637 536
keir@20637 537 int libxl_get_event(struct libxl_ctx *ctx, libxl_event *event)
keir@20545 538 {
keir@20545 539 unsigned int num;
keir@20637 540 char **events = xs_read_watch(ctx->xsh, &num);
keir@20637 541 if (num != 2) {
keir@20637 542 free(events);
keir@20637 543 return -1;
keir@20637 544 }
keir@20637 545 event->path = strdup(events[XS_WATCH_PATH]);
keir@20637 546 event->token = strdup(events[XS_WATCH_TOKEN]);
keir@20637 547 event->type = atoi(event->token);
keir@20637 548 free(events);
keir@20637 549 return 0;
keir@20637 550 }
keir@20637 551
keir@20637 552 int libxl_stop_waiting(struct libxl_ctx *ctx, libxl_waiter *waiter)
keir@20637 553 {
keir@20637 554 if (!xs_unwatch(ctx->xsh, waiter->path, waiter->token))
keir@20637 555 return -1;
keir@20637 556 else
keir@20637 557 return 0;
keir@20637 558 }
keir@20637 559
keir@20637 560 int libxl_free_event(libxl_event *event)
keir@20637 561 {
keir@20637 562 free(event->path);
keir@20637 563 free(event->token);
keir@20637 564 return 0;
keir@20637 565 }
keir@20637 566
keir@20637 567 int libxl_free_waiter(libxl_waiter *waiter)
keir@20637 568 {
keir@20637 569 free(waiter->path);
keir@20637 570 free(waiter->token);
keir@20637 571 return 0;
keir@20637 572 }
keir@20637 573
keir@20785 574 int libxl_event_get_domain_death_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, xc_domaininfo_t *info)
keir@20637 575 {
keir@20785 576 int rc = 0, ret;
keir@20545 577
keir@20637 578 if (event && event->type == DOMAIN_DEATH) {
keir@20785 579 ret = xc_domain_getinfolist(ctx->xch, domid, 1, info);
keir@20785 580 if (ret == 1 && info->domain == domid) {
keir@20785 581 if (info->flags & XEN_DOMINF_running ||
keir@20785 582 (!(info->flags & XEN_DOMINF_shutdown) && !(info->flags & XEN_DOMINF_dying)))
keir@20545 583 goto out;
keir@20545 584 rc = 1;
keir@20545 585 goto out;
keir@20545 586 }
keir@20785 587 memset(info, 0, sizeof(xc_dominfo_t));
keir@20545 588 rc = 1;
keir@20545 589 goto out;
keir@20545 590 }
keir@20545 591 out:
keir@20545 592 return rc;
keir@20545 593 }
keir@20545 594
keir@20637 595 int libxl_event_get_disk_eject_info(struct libxl_ctx *ctx, uint32_t domid, libxl_event *event, libxl_device_disk *disk)
keir@20637 596 {
keir@20637 597 if (event && event->type == DISK_EJECT) {
keir@20637 598 char *path;
keir@20637 599 char *backend;
keir@20637 600 char *value = libxl_xs_read(ctx, XBT_NULL, event->path);
keir@20637 601
keir@20637 602 if (!value || strcmp(value, "eject"))
keir@20637 603 return 0;
keir@20637 604
keir@20637 605 path = strdup(event->path);
keir@20637 606 path[strlen(path) - 6] = '\0';
keir@20637 607 backend = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend", path));
keir@20637 608
keir@20637 609 disk->backend_domid = 0;
keir@20637 610 disk->domid = domid;
keir@20637 611 disk->physpath = NULL;
keir@20637 612 disk->phystype = 0;
keir@20637 613 /* this value is returned to the user: do not free right away */
keir@20637 614 disk->virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev", backend));
keir@20637 615 disk->unpluggable = 1;
keir@20637 616 disk->readwrite = 0;
keir@20637 617 disk->is_cdrom = 1;
keir@20637 618
keir@20637 619 free(path);
keir@20637 620 return 1;
keir@20637 621 }
keir@20637 622 return 0;
keir@20637 623 }
keir@20637 624
keir@20462 625 static int libxl_destroy_device_model(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 626 {
keir@20462 627 char *pid;
keir@20462 628 int ret;
keir@20462 629
keir@20462 630 pid = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/image/device-model-pid", domid));
keir@20462 631 if (!pid) {
keir@20542 632 int stubdomid = libxl_get_stubdom_id(ctx, domid);
keir@20542 633 if (!stubdomid) {
keir@20542 634 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't find device model's pid");
keir@20542 635 return -1;
keir@20542 636 }
keir@20542 637 XL_LOG(ctx, XL_LOG_ERROR, "Device model is a stubdom, domid=%d\n", stubdomid);
keir@20542 638 return libxl_domain_destroy(ctx, stubdomid, 0);
keir@20462 639 }
keir@20462 640 xs_rm(ctx->xsh, XBT_NULL, libxl_sprintf(ctx, "/local/domain/0/device-model/%d", domid));
keir@20462 641
keir@20462 642 ret = kill(atoi(pid), SIGHUP);
keir@20462 643 if (ret < 0 && errno == ESRCH) {
keir@20512 644 XL_LOG(ctx, XL_LOG_DEBUG, "Device Model already exited");
keir@20462 645 ret = 0;
keir@20462 646 } else if (ret == 0) {
keir@20512 647 XL_LOG(ctx, XL_LOG_DEBUG, "Device Model signaled");
keir@20462 648 ret = 0;
keir@20462 649 } else {
keir@20512 650 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to kill Device Model [%d]",
keir@20512 651 atoi(pid));
keir@20462 652 }
keir@20462 653 return ret;
keir@20462 654 }
keir@20462 655
keir@20462 656 int libxl_domain_destroy(struct libxl_ctx *ctx, uint32_t domid, int force)
keir@20462 657 {
keir@20801 658 char *dom_path;
keir@20779 659 char *vm_path, *vss_path, *xapi_path;
keir@20628 660 int rc, dm_present;
keir@20628 661
keir@20628 662 if (is_hvm(ctx, domid)) {
keir@20628 663 dm_present = 1;
keir@20628 664 } else {
keir@20628 665 char *pid;
keir@20628 666 pid = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/image/device-model-pid", domid));
keir@20628 667 dm_present = (pid != NULL);
keir@20628 668 libxl_free(ctx, pid);
keir@20628 669 }
keir@20462 670
keir@20462 671 dom_path = libxl_xs_get_dompath(ctx, domid);
keir@20512 672 if (!dom_path)
keir@20462 673 return -1;
keir@20512 674
keir@20482 675 if (libxl_device_pci_shutdown(ctx, domid) < 0)
keir@20512 676 XL_LOG(ctx, XL_LOG_ERROR, "pci shutdown failed for domid %d", domid);
keir@20628 677 if (dm_present) {
keir@20628 678 xs_write(ctx->xsh, XBT_NULL,
keir@20628 679 libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid),
keir@20628 680 "shutdown", strlen("shutdown"));
keir@20628 681 }
keir@20512 682 rc = xc_domain_pause(ctx->xch, domid);
keir@20512 683 if (rc < 0) {
keir@20512 684 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_domain_pause failed for %d", domid);
keir@20462 685 return -1;
keir@20462 686 }
keir@20628 687 if (dm_present) {
keir@20628 688 if (libxl_destroy_device_model(ctx, domid) < 0)
keir@20628 689 XL_LOG(ctx, XL_LOG_ERROR, "libxl_destroy_device_model failed for %d", domid);
keir@20628 690 }
keir@20462 691 if (libxl_devices_destroy(ctx, domid, force) < 0)
keir@20512 692 XL_LOG(ctx, XL_LOG_ERROR, "libxl_destroy_devices failed for %d", domid);
keir@20462 693 if (!xs_rm(ctx->xsh, XBT_NULL, dom_path))
keir@20512 694 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xs_rm failed for %s", dom_path);
keir@20779 695
keir@20801 696 vm_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/vm", domid));
keir@20823 697 if (vm_path)
keir@20823 698 if (!xs_rm(ctx->xsh, XBT_NULL, vm_path))
keir@20823 699 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xs_rm failed for %s", vm_path);
keir@20779 700
keir@20801 701 vss_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/vss", domid));
keir@20823 702 if (vss_path)
keir@20823 703 if (!xs_rm(ctx->xsh, XBT_NULL, vss_path))
keir@20823 704 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xs_rm failed for %s", vss_path);
keir@20779 705
keir@20779 706 xapi_path = libxl_sprintf(ctx, "/xapi/%u", domid);
keir@20823 707 if (xapi_path)
keir@20823 708 if (!xs_rm(ctx->xsh, XBT_NULL, xapi_path))
keir@20823 709 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "xs_rm failed for %s", xapi_path);
keir@20779 710
keir@20545 711 rc = xc_domain_destroy(ctx->xch, domid);
keir@20545 712 if (rc < 0) {
keir@20545 713 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_domain_destroy failed for %d", domid);
keir@20545 714 return -1;
keir@20545 715 }
keir@20462 716 return 0;
keir@20462 717 }
keir@20462 718
keir@20564 719 int libxl_console_attach(struct libxl_ctx *ctx, uint32_t domid, int cons_num)
keir@20564 720 {
keir@20564 721 struct stat st;
keir@20564 722 const char *XENCONSOLE = "/usr/lib/xen/bin/xenconsole";
keir@20564 723 char *cmd;
keir@20564 724
keir@20564 725 if (stat(XENCONSOLE, &st) != 0) {
keir@20564 726 XL_LOG(ctx, XL_LOG_ERROR, "could not access %s", XENCONSOLE);
keir@20564 727 return ERROR_FAIL;
keir@20564 728 }
keir@20564 729
keir@20564 730 cmd = libxl_sprintf(ctx, "%s %d --num %d", XENCONSOLE, domid, cons_num);
keir@20564 731 return (system(cmd) != 0) ? ERROR_FAIL : 0;
keir@20564 732 }
keir@20564 733
keir@20462 734 static char ** libxl_build_device_model_args(struct libxl_ctx *ctx,
keir@20462 735 libxl_device_model_info *info,
keir@20462 736 libxl_device_nic *vifs,
keir@20462 737 int num_vifs)
keir@20462 738 {
keir@20462 739 int num = 0, i;
keir@20462 740 flexarray_t *dm_args;
keir@20462 741 dm_args = flexarray_make(16, 1);
keir@20462 742 if (!dm_args)
keir@20462 743 return NULL;
keir@20462 744
keir@20516 745 flexarray_set(dm_args, num++, "qemu-dm");
keir@20516 746 flexarray_set(dm_args, num++, "-d");
keir@20462 747
keir@20462 748 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->domid));
keir@20462 749
keir@20462 750 if (info->dom_name) {
keir@20516 751 flexarray_set(dm_args, num++, "-domain-name");
keir@20516 752 flexarray_set(dm_args, num++, info->dom_name);
keir@20462 753 }
keir@20462 754 if (info->vnc || info->vncdisplay || info->vnclisten || info->vncunused) {
keir@20516 755 flexarray_set(dm_args, num++, "-vnc");
keir@20462 756 if (info->vncdisplay) {
keir@20462 757 if (info->vnclisten && strchr(info->vnclisten, ':') == NULL) {
keir@20462 758 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s:%d", info->vnclisten, info->vncdisplay));
keir@20462 759 } else {
keir@20462 760 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "127.0.0.1:%d", info->vncdisplay));
keir@20462 761 }
keir@20462 762 } else if (info->vnclisten) {
keir@20462 763 if (strchr(info->vnclisten, ':') != NULL) {
keir@20516 764 flexarray_set(dm_args, num++, info->vnclisten);
keir@20462 765 } else {
keir@20462 766 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%s:0", info->vnclisten));
keir@20462 767 }
keir@20462 768 } else {
keir@20516 769 flexarray_set(dm_args, num++, "127.0.0.1:0");
keir@20462 770 }
keir@20462 771 if (info->vncunused) {
keir@20516 772 flexarray_set(dm_args, num++, "-vncunused");
keir@20462 773 }
keir@20462 774 }
keir@20462 775 if (info->sdl || info->opengl) {
keir@20516 776 flexarray_set(dm_args, num++, "-sdl");
keir@20462 777 if (info->opengl) {
keir@20516 778 flexarray_set(dm_args, num++, "-disable-opengl");
keir@20462 779 }
keir@20462 780 }
keir@20462 781 if (info->keymap) {
keir@20516 782 flexarray_set(dm_args, num++, "-k");
keir@20516 783 flexarray_set(dm_args, num++, info->keymap);
keir@20462 784 }
keir@20462 785 if (info->nographic && (!info->sdl && !info->vnc)) {
keir@20516 786 flexarray_set(dm_args, num++, "-nographic");
keir@20462 787 }
keir@20462 788 if (info->serial) {
keir@20516 789 flexarray_set(dm_args, num++, "-serial");
keir@20516 790 flexarray_set(dm_args, num++, info->serial);
keir@20462 791 }
keir@20509 792 if (info->type == XENFV) {
keir@20509 793 if (info->videoram) {
keir@20516 794 flexarray_set(dm_args, num++, "-videoram");
keir@20509 795 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "%d", info->videoram));
keir@20509 796 }
keir@20509 797 if (info->stdvga) {
keir@20516 798 flexarray_set(dm_args, num++, "-std-vga");
keir@20509 799 }
keir@20509 800
keir@20509 801 if (info->boot) {
keir@20516 802 flexarray_set(dm_args, num++, "-boot");
keir@20516 803 flexarray_set(dm_args, num++, info->boot);
keir@20509 804 }
keir@20509 805 if (info->usb) {
keir@20516 806 flexarray_set(dm_args, num++, "-usb");
keir@20509 807 if (info->usbdevice) {
keir@20516 808 flexarray_set(dm_args, num++, "-usbdevice");
keir@20516 809 flexarray_set(dm_args, num++, info->usbdevice);
keir@20509 810 }
keir@20509 811 }
keir@20509 812 if (info->apic) {
keir@20516 813 flexarray_set(dm_args, num++, "-acpi");
keir@20509 814 }
keir@20509 815 for (i = 0; i < num_vifs; i++) {
keir@20509 816 if (vifs[i].nictype == NICTYPE_IOEMU) {
keir@20780 817 char *smac = libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
keir@20780 818 vifs[i].mac[0], vifs[i].mac[1], vifs[i].mac[2],
keir@20780 819 vifs[i].mac[3], vifs[i].mac[4], vifs[i].mac[5]);
keir@20781 820 if (!vifs[i].ifname)
keir@20781 821 vifs[i].ifname = libxl_sprintf(ctx, "tap%d.%d", info->domid, vifs[i].devid - 1);
keir@20516 822 flexarray_set(dm_args, num++, "-net");
keir@20509 823 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "nic,vlan=%d,macaddr=%s,model=%s",
keir@20780 824 vifs[i].devid, smac, vifs[i].model));
keir@20516 825 flexarray_set(dm_args, num++, "-net");
keir@20509 826 flexarray_set(dm_args, num++, libxl_sprintf(ctx, "tap,vlan=%d,ifname=%s,bridge=%s",
keir@20509 827 vifs[i].devid, vifs[i].ifname, vifs[i].bridge));
keir@20509 828 }
keir@20462 829 }
keir@20462 830 }
keir@20565 831 if (info->saved_state) {
keir@20565 832 flexarray_set(dm_args, num++, "-loadvm");
keir@20565 833 flexarray_set(dm_args, num++, info->saved_state);
keir@20565 834 }
keir@20509 835 for (i = 0; info->extra && info->extra[i] != NULL; i++)
keir@20509 836 flexarray_set(dm_args, num++, info->extra[i]);
keir@20516 837 flexarray_set(dm_args, num++, "-M");
keir@20509 838 if (info->type == XENPV)
keir@20516 839 flexarray_set(dm_args, num++, "xenpv");
keir@20509 840 else
keir@20516 841 flexarray_set(dm_args, num++, "xenfv");
keir@20462 842 flexarray_set(dm_args, num++, NULL);
keir@20462 843
keir@20462 844 return (char **) flexarray_contents(dm_args);
keir@20462 845 }
keir@20462 846
keir@20834 847 void dm_xenstore_record_pid(void *for_spawn, pid_t innerchild)
keir@20834 848 {
keir@20514 849 struct libxl_device_model_starting *starting = for_spawn;
keir@20514 850 char *kvs[3];
keir@20820 851 int rc;
keir@20820 852 struct xs_handle *xsh;
keir@20514 853
keir@20820 854 xsh = xs_daemon_open();
keir@20514 855 /* we mustn't use the parent's handle in the child */
keir@20514 856
keir@20514 857 kvs[0] = "image/device-model-pid";
keir@20820 858 asprintf(&kvs[1], "%d", innerchild);
keir@20514 859 kvs[2] = NULL;
keir@20820 860
keir@20820 861 rc = xs_writev(xsh, XBT_NULL, starting->dom_path, kvs);
keir@20820 862 if (rc)
keir@20820 863 return;
keir@20820 864 xs_daemon_close(xsh);
keir@20514 865 }
keir@20514 866
keir@20542 867 static int libxl_vfb_and_vkb_from_device_model_info(struct libxl_ctx *ctx,
keir@20542 868 libxl_device_model_info *info,
keir@20542 869 libxl_device_vfb *vfb,
keir@20542 870 libxl_device_vkb *vkb)
keir@20542 871 {
keir@20542 872 memset(vfb, 0x00, sizeof(libxl_device_vfb));
keir@20542 873 memset(vkb, 0x00, sizeof(libxl_device_vkb));
keir@20542 874
keir@20542 875 vfb->backend_domid = 0;
keir@20542 876 vfb->devid = 0;
keir@20542 877 vfb->vnc = info->vnc;
keir@20542 878 vfb->vnclisten = info->vnclisten;
keir@20542 879 vfb->vncdisplay = info->vncdisplay;
keir@20542 880 vfb->vncunused = info->vncunused;
keir@20542 881 vfb->keymap = info->keymap;
keir@20542 882 vfb->sdl = info->sdl;
keir@20542 883 vfb->opengl = info->opengl;
keir@20542 884
keir@20542 885 vkb->backend_domid = 0;
keir@20542 886 vkb->devid = 0;
keir@20542 887 return 0;
keir@20542 888 }
keir@20542 889
keir@20542 890 static int libxl_write_dmargs(struct libxl_ctx *ctx, int domid, int guest_domid, char **args)
keir@20542 891 {
keir@20542 892 int i;
keir@20542 893 char *vm_path;
keir@20542 894 char *dmargs, *path;
keir@20542 895 int dmargs_size;
keir@20542 896 struct xs_permissions roperm[2];
keir@20542 897 xs_transaction_t t;
keir@20542 898
keir@20542 899 roperm[0].id = 0;
keir@20542 900 roperm[0].perms = XS_PERM_NONE;
keir@20542 901 roperm[1].id = domid;
keir@20542 902 roperm[1].perms = XS_PERM_READ;
keir@20542 903
keir@20542 904 vm_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "/local/domain/%d/vm", guest_domid));
keir@20542 905
keir@20542 906 i = 0;
keir@20542 907 dmargs_size = 0;
keir@20542 908 while (args[i] != NULL) {
keir@20542 909 dmargs_size = dmargs_size + strlen(args[i]) + 1;
keir@20542 910 i++;
keir@20542 911 }
keir@20542 912 dmargs_size++;
keir@20542 913 dmargs = (char *) malloc(dmargs_size);
keir@20542 914 i = 1;
keir@20542 915 dmargs[0] = '\0';
keir@20542 916 while (args[i] != NULL) {
keir@20542 917 if (strcmp(args[i], "-sdl") && strcmp(args[i], "-M") && strcmp(args[i], "xenfv")) {
keir@20542 918 strcat(dmargs, " ");
keir@20542 919 strcat(dmargs, args[i]);
keir@20542 920 }
keir@20542 921 i++;
keir@20542 922 }
keir@20542 923 path = libxl_sprintf(ctx, "%s/image/dmargs", vm_path);
keir@20542 924
keir@20542 925 retry_transaction:
keir@20542 926 t = xs_transaction_start(ctx->xsh);
keir@20542 927 xs_write(ctx->xsh, t, path, dmargs, strlen(dmargs));
keir@20542 928 xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm));
keir@20542 929 xs_set_permissions(ctx->xsh, t, libxl_sprintf(ctx, "%s/rtc/timeoffset", vm_path), roperm, ARRAY_SIZE(roperm));
keir@20542 930 if (!xs_transaction_end(ctx->xsh, t, 0))
keir@20542 931 if (errno == EAGAIN)
keir@20542 932 goto retry_transaction;
keir@20542 933 free(dmargs);
keir@20542 934 return 0;
keir@20542 935 }
keir@20542 936
keir@20542 937 static int libxl_create_stubdom(struct libxl_ctx *ctx,
keir@20542 938 libxl_device_model_info *info,
keir@20542 939 libxl_device_disk *disks, int num_disks,
keir@20542 940 libxl_device_nic *vifs, int num_vifs,
keir@20542 941 libxl_device_vfb *vfb,
keir@20542 942 libxl_device_vkb *vkb,
keir@20542 943 libxl_device_model_starting **starting_r)
keir@20542 944 {
keir@20843 945 int i, num_console = 1, ret;
keir@20570 946 libxl_device_console *console;
keir@20542 947 libxl_domain_create_info c_info;
keir@20542 948 libxl_domain_build_info b_info;
keir@20542 949 libxl_domain_build_state state;
keir@20542 950 uint32_t domid;
keir@20542 951 char **args;
keir@20542 952 struct xs_permissions perm[2];
keir@20542 953 xs_transaction_t t;
keir@20594 954 libxl_device_model_starting *dm_starting = 0;
keir@20542 955
keir@20542 956 args = libxl_build_device_model_args(ctx, info, vifs, num_vifs);
keir@20542 957 if (!args)
keir@20542 958 return ERROR_FAIL;
keir@20542 959
keir@20542 960 memset(&c_info, 0x00, sizeof(libxl_domain_create_info));
keir@20542 961 c_info.hvm = 0;
keir@20542 962 c_info.name = libxl_sprintf(ctx, "%s-dm", libxl_domid_to_name(ctx, info->domid));
keir@20801 963 for (i = 0; i < 16; i++)
keir@20801 964 c_info.uuid[i] = info->uuid[i];
keir@20542 965
keir@20542 966 memset(&b_info, 0x00, sizeof(libxl_domain_build_info));
keir@20542 967 b_info.max_vcpus = 1;
keir@20542 968 b_info.max_memkb = 32 * 1024;
keir@20647 969 b_info.target_memkb = b_info.max_memkb;
keir@20542 970 b_info.kernel = "/usr/lib/xen/boot/ioemu-stubdom.gz";
keir@20542 971 b_info.u.pv.cmdline = libxl_sprintf(ctx, " -d %d", info->domid);
keir@20542 972 b_info.u.pv.ramdisk = "";
keir@20542 973 b_info.u.pv.features = "";
keir@20542 974 b_info.hvm = 0;
keir@20542 975
keir@20843 976 ret = libxl_domain_make(ctx, &c_info, &domid);
keir@20843 977 if (ret) return ret;
keir@20843 978 ret = libxl_domain_build(ctx, &b_info, domid, &state);
keir@20843 979 if (ret) return ret;
keir@20542 980
keir@20542 981 libxl_write_dmargs(ctx, domid, info->domid, args);
keir@20843 982 libxl_xs_write(ctx, XBT_NULL,
keir@20843 983 libxl_sprintf(ctx, "%s/image/device-model-domid", libxl_xs_get_dompath(ctx, info->domid)),
keir@20843 984 "%d", domid);
keir@20843 985 libxl_xs_write(ctx, XBT_NULL,
keir@20843 986 libxl_sprintf(ctx, "%s/target", libxl_xs_get_dompath(ctx, domid)),
keir@20843 987 "%d", info->domid);
keir@20542 988 xc_domain_set_target(ctx->xch, domid, info->domid);
keir@20542 989 xs_set_target(ctx->xsh, domid, info->domid);
keir@20542 990
keir@20542 991 perm[0].id = domid;
keir@20542 992 perm[0].perms = XS_PERM_NONE;
keir@20542 993 perm[1].id = info->domid;
keir@20542 994 perm[1].perms = XS_PERM_READ;
keir@20542 995 retry_transaction:
keir@20542 996 t = xs_transaction_start(ctx->xsh);
keir@20542 997 xs_mkdir(ctx->xsh, t, libxl_sprintf(ctx, "/local/domain/0/device-model/%d", info->domid));
keir@20542 998 xs_set_permissions(ctx->xsh, t, libxl_sprintf(ctx, "/local/domain/0/device-model/%d", info->domid), perm, ARRAY_SIZE(perm));
keir@20635 999 xs_mkdir(ctx->xsh, t, libxl_sprintf(ctx, "/local/domain/%d/device/vfs", domid));
keir@20635 1000 xs_set_permissions(ctx->xsh, t, libxl_sprintf(ctx, "/local/domain/%d/device/vfs",domid), perm, ARRAY_SIZE(perm));
keir@20542 1001 if (!xs_transaction_end(ctx->xsh, t, 0))
keir@20542 1002 if (errno == EAGAIN)
keir@20542 1003 goto retry_transaction;
keir@20542 1004
keir@20542 1005 for (i = 0; i < num_disks; i++) {
keir@20781 1006 disks[i].domid = domid;
keir@20843 1007 ret = libxl_device_disk_add(ctx, domid, &disks[i]);
keir@20843 1008 if (ret) return ret;
keir@20542 1009 }
keir@20542 1010 for (i = 0; i < num_vifs; i++) {
keir@20781 1011 vifs[i].domid = domid;
keir@20843 1012 ret = libxl_device_nic_add(ctx, domid, &vifs[i]);
keir@20843 1013 if (ret) return ret;
keir@20542 1014 }
keir@20781 1015 vfb->domid = domid;
keir@20843 1016 ret = libxl_device_vfb_add(ctx, domid, vfb);
keir@20843 1017 if (ret) return ret;
keir@20781 1018 vkb->domid = domid;
keir@20843 1019 ret = libxl_device_vkb_add(ctx, domid, vkb);
keir@20843 1020 if (ret) return ret;
keir@20542 1021
keir@20570 1022 if (info->serial)
keir@20570 1023 num_console++;
keir@20843 1024
keir@20570 1025 console = libxl_calloc(ctx, num_console, sizeof(libxl_device_console));
keir@20843 1026 if (!console)
keir@20843 1027 return ERROR_NOMEM;
keir@20843 1028
keir@20570 1029 for (i = 0; i < num_console; i++) {
keir@20781 1030 console[i].devid = i;
keir@20781 1031 console[i].constype = CONSTYPE_IOEMU;
keir@20781 1032 console[i].domid = domid;
keir@20570 1033 if (!i)
keir@20781 1034 console[i].build_state = &state;
keir@20843 1035 ret = libxl_device_console_add(ctx, domid, &console[i]);
keir@20843 1036 if (ret) return ret;
keir@20570 1037 }
keir@20594 1038 if (libxl_create_xenpv_qemu(ctx, vfb, num_console, console, &dm_starting) < 0) {
keir@20594 1039 free(args);
keir@20594 1040 return -1;
keir@20594 1041 }
keir@20594 1042 if (libxl_confirm_device_model_startup(ctx, dm_starting) < 0) {
keir@20594 1043 free(args);
keir@20594 1044 return -1;
keir@20594 1045 }
keir@20542 1046
keir@20542 1047 libxl_domain_unpause(ctx, domid);
keir@20542 1048
keir@20594 1049 if (starting_r) {
keir@20594 1050 *starting_r = libxl_calloc(ctx, sizeof(libxl_device_model_starting), 1);
keir@20598 1051 (*starting_r)->domid = info->domid;
keir@20594 1052 (*starting_r)->dom_path = libxl_xs_get_dompath(ctx, info->domid);
keir@20594 1053 (*starting_r)->for_spawn = NULL;
keir@20594 1054 }
keir@20594 1055
keir@20542 1056 free(args);
keir@20542 1057 return 0;
keir@20542 1058 }
keir@20542 1059
keir@20462 1060 int libxl_create_device_model(struct libxl_ctx *ctx,
keir@20462 1061 libxl_device_model_info *info,
keir@20542 1062 libxl_device_disk *disks, int num_disks,
keir@20514 1063 libxl_device_nic *vifs, int num_vifs,
keir@20514 1064 libxl_device_model_starting **starting_r)
keir@20462 1065 {
keir@20546 1066 char *path, *logfile;
keir@20514 1067 int logfile_w, null;
keir@20546 1068 int rc;
keir@20462 1069 char **args;
keir@20594 1070 struct libxl_device_model_starting buf_starting, *p;
keir@20514 1071
keir@20542 1072 if (strstr(info->device_model, "stubdom-dm")) {
keir@20542 1073 libxl_device_vfb vfb;
keir@20542 1074 libxl_device_vkb vkb;
keir@20542 1075
keir@20542 1076 libxl_vfb_and_vkb_from_device_model_info(ctx, info, &vfb, &vkb);
keir@20542 1077 return libxl_create_stubdom(ctx, info, disks, num_disks, vifs, num_vifs, &vfb, &vkb, starting_r);
keir@20542 1078 }
keir@20542 1079
keir@20462 1080 args = libxl_build_device_model_args(ctx, info, vifs, num_vifs);
keir@20462 1081 if (!args)
keir@20462 1082 return ERROR_FAIL;
keir@20462 1083
keir@20462 1084 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d", info->domid);
keir@20462 1085 xs_mkdir(ctx->xsh, XBT_NULL, path);
keir@20462 1086
keir@20546 1087 libxl_create_logfile(ctx, libxl_sprintf(ctx, "qemu-dm-%s", info->dom_name), &logfile);
keir@20467 1088 logfile_w = open(logfile, O_WRONLY|O_CREAT, 0644);
keir@20546 1089 free(logfile);
keir@20462 1090 null = open("/dev/null", O_RDONLY);
keir@20514 1091
keir@20514 1092 if (starting_r) {
keir@20516 1093 rc = ERROR_NOMEM;
keir@20594 1094 *starting_r = libxl_calloc(ctx, sizeof(libxl_device_model_starting), 1);
keir@20516 1095 if (!*starting_r) goto xit;
keir@20594 1096 p = *starting_r;
keir@20611 1097 p->for_spawn = libxl_calloc(ctx, sizeof(struct libxl_spawn_starting), 1);
keir@20594 1098 } else {
keir@20594 1099 p = &buf_starting;
keir@20594 1100 p->for_spawn = NULL;
keir@20594 1101 }
keir@20514 1102
keir@20594 1103 p->domid = info->domid;
keir@20594 1104 p->dom_path = libxl_xs_get_dompath(ctx, info->domid);
keir@20594 1105 if (!p->dom_path) { libxl_free(ctx, p); return ERROR_FAIL; }
keir@20594 1106
keir@20594 1107 rc = libxl_spawn_spawn(ctx, p, "device model", dm_xenstore_record_pid);
keir@20514 1108 if (rc < 0) goto xit;
keir@20514 1109 if (!rc) { /* inner child */
keir@20833 1110 libxl_exec(null, logfile_w, logfile_w,
keir@20514 1111 info->device_model, args);
keir@20514 1112 }
keir@20514 1113
keir@20514 1114 rc = 0;
keir@20514 1115 xit:
keir@20516 1116 free(args);
keir@20462 1117 close(null);
keir@20462 1118 close(logfile_w);
keir@20462 1119
keir@20514 1120 return rc;
keir@20514 1121 }
keir@20514 1122
keir@20514 1123 int libxl_detach_device_model(struct libxl_ctx *ctx,
keir@20779 1124 libxl_device_model_starting *starting)
keir@20779 1125 {
keir@20514 1126 int rc;
keir@20594 1127 rc = libxl_spawn_detach(ctx, starting->for_spawn);
keir@20594 1128 if (starting->for_spawn) libxl_free(ctx, starting->for_spawn);
keir@20514 1129 libxl_free(ctx, starting);
keir@20514 1130 return rc;
keir@20514 1131 }
keir@20462 1132
keir@20514 1133
keir@20514 1134 int libxl_confirm_device_model_startup(struct libxl_ctx *ctx,
keir@20779 1135 libxl_device_model_starting *starting)
keir@20779 1136 {
keir@20514 1137 int problem = libxl_wait_for_device_model(ctx, starting->domid, "running",
keir@20514 1138 libxl_spawn_check,
keir@20594 1139 starting->for_spawn);
keir@20514 1140 int detach = libxl_detach_device_model(ctx, starting);
keir@20514 1141 return problem ? problem : detach;
keir@20542 1142 return 0;
keir@20462 1143 }
keir@20462 1144
keir@20514 1145
keir@20462 1146 /******************************************************************************/
keir@20566 1147
keir@20566 1148 static int is_blktap2_supported(void)
keir@20566 1149 {
keir@20566 1150 char buf[1024];
keir@20566 1151 FILE *f = fopen("/proc/devices", "r");
keir@20566 1152
keir@20566 1153
keir@20566 1154 while (fgets(buf, sizeof(buf), f) != NULL) {
keir@20566 1155 if (strstr(buf, "blktap2")) {
keir@20566 1156 fclose(f);
keir@20566 1157 return 1;
keir@20566 1158 }
keir@20566 1159 }
keir@20566 1160 fclose(f);
keir@20566 1161 return 0;
keir@20566 1162 }
keir@20566 1163
keir@20566 1164 static char *get_blktap2_device(struct libxl_ctx *ctx, char *name, char *type)
keir@20566 1165 {
keir@20566 1166 char buf[1024];
keir@20566 1167 char *p;
keir@20566 1168 int devnum;
keir@20566 1169 FILE *f = fopen("/sys/class/blktap2/devices", "r");
keir@20566 1170
keir@20566 1171
keir@20566 1172 while (!feof(f)) {
keir@20566 1173 fscanf(f, "%d %s", &devnum, buf);
keir@20566 1174 p = strchr(buf, ':');
keir@20571 1175 if (p == NULL)
keir@20571 1176 continue;
keir@20566 1177 p++;
keir@20566 1178 if (!strcmp(p, name) && !strncmp(buf, type, 3)) {
keir@20566 1179 fclose(f);
keir@20566 1180 return libxl_sprintf(ctx, "/dev/xen/blktap-2/tapdev%d", devnum);
keir@20566 1181 }
keir@20566 1182 }
keir@20566 1183 fclose(f);
keir@20566 1184 return NULL;
keir@20566 1185 }
keir@20566 1186
keir@20462 1187 int libxl_device_disk_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
keir@20462 1188 {
keir@20462 1189 flexarray_t *front;
keir@20462 1190 flexarray_t *back;
keir@20462 1191 char *backend_type;
keir@20462 1192 unsigned int boffset = 0;
keir@20462 1193 unsigned int foffset = 0;
keir@20462 1194 int devid;
keir@20462 1195 libxl_device device;
keir@20566 1196 int major, minor;
keir@20462 1197
keir@20462 1198 front = flexarray_make(16, 1);
keir@20462 1199 if (!front)
keir@20462 1200 return ERROR_NOMEM;
keir@20462 1201 back = flexarray_make(16, 1);
keir@20462 1202 if (!back) /* leaks front if error */
keir@20462 1203 return ERROR_NOMEM;
keir@20462 1204
keir@20462 1205 backend_type = device_disk_backend_type_of_phystype(disk->phystype);
keir@20462 1206 devid = device_disk_dev_number(disk->virtpath);
keir@20947 1207 if (devid==-1) {
keir@20947 1208 XL_LOG(ctx, XL_LOG_ERROR, "Invalid or unuspported"
keir@20947 1209 " virtual disk identifier %s", disk->virtpath);
keir@20947 1210 return ERROR_INVAL;
keir@20947 1211 }
keir@20462 1212
keir@20462 1213 device.backend_devid = devid;
keir@20462 1214 device.backend_domid = disk->backend_domid;
keir@20462 1215 device.devid = devid;
keir@20462 1216 device.domid = disk->domid;
keir@20462 1217 device.kind = DEVICE_VBD;
keir@20462 1218
keir@20462 1219 switch (disk->phystype) {
keir@20462 1220 case PHYSTYPE_PHY: {
keir@20462 1221
keir@20509 1222 device_physdisk_major_minor(disk->physpath, &major, &minor);
keir@20516 1223 flexarray_set(back, boffset++, "physical-device");
keir@20462 1224 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x:%x", major, minor));
keir@20462 1225
keir@20516 1226 flexarray_set(back, boffset++, "params");
keir@20516 1227 flexarray_set(back, boffset++, disk->physpath);
keir@20462 1228
keir@20462 1229 device.backend_kind = DEVICE_VBD;
keir@20462 1230 break;
keir@20462 1231 }
keir@20566 1232 case PHYSTYPE_FILE:
keir@20566 1233 /* let's pretend is tap:aio for the moment */
keir@20566 1234 disk->phystype = PHYSTYPE_AIO;
keir@20462 1235 case PHYSTYPE_AIO: case PHYSTYPE_QCOW: case PHYSTYPE_QCOW2: case PHYSTYPE_VHD:
keir@20566 1236 if (is_blktap2_supported()) {
keir@20566 1237 int rc, c, p[2], tot;
keir@20566 1238 char buf[1024], *dev;
keir@20779 1239 dev = get_blktap2_device(ctx, disk->physpath, device_disk_string_of_phystype(disk->phystype));
keir@20779 1240 if (dev == NULL) {
keir@21185 1241 rc= libxl_pipe(ctx, p); if (rc==-1) return -1;
keir@21185 1242 rc= libxl_fork(ctx); if (rc==-1) return -1;
keir@21185 1243 if (!rc) { /* child */
keir@20566 1244 int null_r, null_w;
keir@20566 1245 char *args[4];
keir@20566 1246 args[0] = "tapdisk2";
keir@20566 1247 args[1] = "-n";
keir@20566 1248 args[2] = libxl_sprintf(ctx, "%s:%s", device_disk_string_of_phystype(disk->phystype), disk->physpath);
keir@20566 1249 args[3] = NULL;
keir@20566 1250
keir@20566 1251 null_r = open("/dev/null", O_RDONLY);
keir@20566 1252 null_w = open("/dev/null", O_WRONLY);
keir@20833 1253 libxl_exec(null_r, p[1], null_w, "/usr/sbin/tapdisk2", args);
keir@20566 1254 XL_LOG(ctx, XL_LOG_ERROR, "Error execing tapdisk2");
keir@20566 1255 }
keir@20566 1256 close(p[1]);
keir@20566 1257 tot = 0;
keir@20566 1258 while ((c = read(p[0], buf + tot, sizeof(buf) - tot)) > 0)
keir@20566 1259 tot = tot + c;
keir@20566 1260 close(p[0]);
keir@20566 1261 buf[tot - 1] = '\0';
keir@20566 1262 dev = buf;
keir@20566 1263 }
keir@20566 1264 flexarray_set(back, boffset++, "tapdisk-params");
keir@20566 1265 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s:%s", device_disk_string_of_phystype(disk->phystype), disk->physpath));
keir@20566 1266 flexarray_set(back, boffset++, "params");
keir@20566 1267 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s", dev));
keir@20566 1268 backend_type = "phy";
keir@20566 1269 device_physdisk_major_minor(dev, &major, &minor);
keir@20566 1270 flexarray_set(back, boffset++, "physical-device");
keir@20566 1271 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x:%x", major, minor));
keir@20566 1272 device.backend_kind = DEVICE_VBD;
keir@20566 1273
keir@20566 1274 break;
keir@20566 1275 }
keir@20516 1276 flexarray_set(back, boffset++, "params");
keir@20462 1277 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%s:%s",
keir@20462 1278 device_disk_string_of_phystype(disk->phystype), disk->physpath));
keir@20462 1279
keir@20462 1280 device.backend_kind = DEVICE_TAP;
keir@20462 1281 break;
keir@20846 1282 default:
keir@20846 1283 XL_LOG(ctx, XL_LOG_ERROR, "unrecognized disk physical type: %d\n", disk->phystype);
keir@20846 1284 return ERROR_INVAL;
keir@20462 1285 }
keir@20462 1286
keir@20516 1287 flexarray_set(back, boffset++, "frontend-id");
keir@20462 1288 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", disk->domid));
keir@20516 1289 flexarray_set(back, boffset++, "online");
keir@20516 1290 flexarray_set(back, boffset++, "1");
keir@20516 1291 flexarray_set(back, boffset++, "removable");
keir@20462 1292 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", (disk->unpluggable) ? 1 : 0));
keir@20516 1293 flexarray_set(back, boffset++, "bootable");
keir@20509 1294 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20516 1295 flexarray_set(back, boffset++, "state");
keir@20462 1296 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20516 1297 flexarray_set(back, boffset++, "dev");
keir@20516 1298 flexarray_set(back, boffset++, disk->virtpath);
keir@20516 1299 flexarray_set(back, boffset++, "type");
keir@20516 1300 flexarray_set(back, boffset++, backend_type);
keir@20516 1301 flexarray_set(back, boffset++, "mode");
keir@20516 1302 flexarray_set(back, boffset++, disk->readwrite ? "w" : "r");
keir@20462 1303
keir@20516 1304 flexarray_set(front, foffset++, "backend-id");
keir@20462 1305 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", disk->backend_domid));
keir@20516 1306 flexarray_set(front, foffset++, "state");
keir@20462 1307 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
keir@20516 1308 flexarray_set(front, foffset++, "virtual-device");
keir@20462 1309 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", devid));
keir@20516 1310 flexarray_set(front, foffset++, "device-type");
keir@20516 1311 flexarray_set(front, foffset++, disk->is_cdrom ? "cdrom" : "disk");
keir@20462 1312
keir@20462 1313 if (0 /* protocol != native*/) {
keir@20516 1314 flexarray_set(front, foffset++, "protocol");
keir@20516 1315 flexarray_set(front, foffset++, "x86_32-abi"); /* hardcoded ! */
keir@20462 1316 }
keir@20462 1317
keir@20462 1318 libxl_device_generic_add(ctx, &device,
keir@20462 1319 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
keir@20462 1320 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
keir@20516 1321 flexarray_free(back);
keir@20516 1322 flexarray_free(front);
keir@20462 1323 return 0;
keir@20462 1324 }
keir@20462 1325
keir@20626 1326 int libxl_device_disk_del(struct libxl_ctx *ctx,
keir@20626 1327 libxl_device_disk *disk, int wait)
keir@20462 1328 {
keir@20626 1329 libxl_device device;
keir@20626 1330 int devid;
keir@20462 1331
keir@20626 1332 devid = device_disk_dev_number(disk->virtpath);
keir@20626 1333 device.backend_domid = disk->backend_domid;
keir@20626 1334 device.backend_devid = devid;
keir@20626 1335 device.backend_kind =
keir@20626 1336 (disk->phystype == PHYSTYPE_PHY) ? DEVICE_VBD : DEVICE_TAP;
keir@20626 1337 device.domid = disk->domid;
keir@20626 1338 device.devid = devid;
keir@20626 1339 device.kind = DEVICE_VBD;
keir@20626 1340 return libxl_device_del(ctx, &device, wait);
keir@20462 1341 }
keir@20462 1342
keir@20462 1343 /******************************************************************************/
keir@20462 1344 int libxl_device_nic_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_nic *nic)
keir@20462 1345 {
keir@20462 1346 flexarray_t *front;
keir@20462 1347 flexarray_t *back;
keir@20462 1348 unsigned int boffset = 0;
keir@20462 1349 unsigned int foffset = 0;
keir@20462 1350 libxl_device device;
keir@20462 1351
keir@20462 1352 front = flexarray_make(16, 1);
keir@20462 1353 if (!front)
keir@20462 1354 return ERROR_NOMEM;
keir@20462 1355 back = flexarray_make(16, 1);
keir@20462 1356 if (!back)
keir@20462 1357 return ERROR_NOMEM;
keir@20462 1358
keir@20462 1359 device.backend_devid = nic->devid;
keir@20462 1360 device.backend_domid = nic->backend_domid;
keir@20462 1361 device.backend_kind = DEVICE_VIF;
keir@20462 1362 device.devid = nic->devid;
keir@20462 1363 device.domid = nic->domid;
keir@20462 1364 device.kind = DEVICE_VIF;
keir@20462 1365
keir@20516 1366 flexarray_set(back, boffset++, "frontend-id");
keir@20462 1367 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->domid));
keir@20516 1368 flexarray_set(back, boffset++, "online");
keir@20516 1369 flexarray_set(back, boffset++, "1");
keir@20516 1370 flexarray_set(back, boffset++, "state");
keir@20462 1371 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20516 1372 flexarray_set(back, boffset++, "script");
keir@20516 1373 flexarray_set(back, boffset++, nic->script);
keir@20516 1374 flexarray_set(back, boffset++, "mac");
keir@20462 1375 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
keir@20462 1376 nic->mac[0], nic->mac[1], nic->mac[2],
keir@20462 1377 nic->mac[3], nic->mac[4], nic->mac[5]));
keir@20516 1378 flexarray_set(back, boffset++, "handle");
keir@20462 1379 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", nic->devid));
keir@20462 1380
keir@20516 1381 flexarray_set(front, foffset++, "backend-id");
keir@20462 1382 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", nic->backend_domid));
keir@20516 1383 flexarray_set(front, foffset++, "state");
keir@20462 1384 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
keir@20516 1385 flexarray_set(front, foffset++, "handle");
keir@20462 1386 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", nic->devid));
keir@20516 1387 flexarray_set(front, foffset++, "mac");
keir@20462 1388 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x",
keir@20462 1389 nic->mac[0], nic->mac[1], nic->mac[2],
keir@20462 1390 nic->mac[3], nic->mac[4], nic->mac[5]));
keir@20462 1391 if (0 /* protocol != native*/) {
keir@20516 1392 flexarray_set(front, foffset++, "protocol");
keir@20516 1393 flexarray_set(front, foffset++, "x86_32-abi"); /* hardcoded ! */
keir@20462 1394 }
keir@20462 1395
keir@20462 1396 libxl_device_generic_add(ctx, &device,
keir@20462 1397 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
keir@20462 1398 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
keir@20462 1399
keir@20462 1400 /* FIXME: wait for plug */
keir@20516 1401 flexarray_free(back);
keir@20516 1402 flexarray_free(front);
keir@20462 1403 return 0;
keir@20462 1404 }
keir@20462 1405
keir@20626 1406 int libxl_device_nic_del(struct libxl_ctx *ctx,
keir@20626 1407 libxl_device_nic *nic, int wait)
keir@20462 1408 {
keir@20626 1409 libxl_device device;
keir@20462 1410
keir@20626 1411 device.backend_devid = nic->devid;
keir@20626 1412 device.backend_domid = nic->backend_domid;
keir@20626 1413 device.backend_kind = DEVICE_VIF;
keir@20626 1414 device.devid = nic->devid;
keir@20626 1415 device.domid = nic->domid;
keir@20626 1416 device.kind = DEVICE_VIF;
keir@20626 1417
keir@20626 1418 return libxl_device_del(ctx, &device, wait);
keir@20462 1419 }
keir@20462 1420
keir@20462 1421 /******************************************************************************/
keir@20509 1422 int libxl_device_console_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_console *console)
keir@20462 1423 {
keir@20509 1424 flexarray_t *front;
keir@20509 1425 flexarray_t *back;
keir@20509 1426 unsigned int boffset = 0;
keir@20509 1427 unsigned int foffset = 0;
keir@20509 1428 libxl_device device;
keir@20509 1429
keir@20509 1430 if (console->build_state) {
keir@20509 1431 xs_transaction_t t;
keir@20509 1432 char **ents = (char **) libxl_calloc(ctx, 9, sizeof(char *));
keir@20516 1433 ents[0] = "console/port";
keir@20509 1434 ents[1] = libxl_sprintf(ctx, "%"PRIu32, console->build_state->console_port);
keir@20516 1435 ents[2] = "console/ring-ref";
keir@20509 1436 ents[3] = libxl_sprintf(ctx, "%lu", console->build_state->console_mfn);
keir@20516 1437 ents[4] = "console/limit";
keir@20509 1438 ents[5] = libxl_sprintf(ctx, "%d", LIBXL_XENCONSOLE_LIMIT);
keir@20516 1439 ents[6] = "console/type";
keir@20509 1440 if (console->constype == CONSTYPE_XENCONSOLED)
keir@20509 1441 ents[7] = "xenconsoled";
keir@20509 1442 else
keir@20509 1443 ents[7] = "ioemu";
keir@20509 1444 retry_transaction:
keir@20509 1445 t = xs_transaction_start(ctx->xsh);
keir@20516 1446 libxl_xs_writev(ctx, t, libxl_xs_get_dompath(ctx, console->domid), ents);
keir@20509 1447 if (!xs_transaction_end(ctx->xsh, t, 0))
keir@20509 1448 if (errno == EAGAIN)
keir@20509 1449 goto retry_transaction;
keir@20509 1450 }
keir@20509 1451
keir@20509 1452 front = flexarray_make(16, 1);
keir@20509 1453 if (!front)
keir@20509 1454 return ERROR_NOMEM;
keir@20509 1455 back = flexarray_make(16, 1);
keir@20509 1456 if (!back)
keir@20509 1457 return ERROR_NOMEM;
keir@20509 1458
keir@20509 1459 device.backend_devid = console->devid;
keir@20509 1460 device.backend_domid = console->backend_domid;
keir@20509 1461 device.backend_kind = DEVICE_CONSOLE;
keir@20509 1462 device.devid = console->devid;
keir@20509 1463 device.domid = console->domid;
keir@20509 1464 device.kind = DEVICE_CONSOLE;
keir@20509 1465
keir@20516 1466 flexarray_set(back, boffset++, "frontend-id");
keir@20509 1467 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", console->domid));
keir@20516 1468 flexarray_set(back, boffset++, "online");
keir@20516 1469 flexarray_set(back, boffset++, "1");
keir@20516 1470 flexarray_set(back, boffset++, "state");
keir@20509 1471 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20516 1472 flexarray_set(back, boffset++, "domain");
keir@20516 1473 flexarray_set(back, boffset++, libxl_domid_to_name(ctx, domid));
keir@20516 1474 flexarray_set(back, boffset++, "protocol");
keir@20516 1475 flexarray_set(back, boffset++, LIBXL_XENCONSOLE_PROTOCOL);
keir@20509 1476
keir@20516 1477 flexarray_set(front, foffset++, "backend-id");
keir@20509 1478 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", console->backend_domid));
keir@20516 1479 flexarray_set(front, foffset++, "state");
keir@20509 1480 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
keir@20516 1481 flexarray_set(front, foffset++, "limit");
keir@20509 1482 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", LIBXL_XENCONSOLE_LIMIT));
keir@20516 1483 flexarray_set(front, foffset++, "protocol");
keir@20516 1484 flexarray_set(front, foffset++, LIBXL_XENCONSOLE_PROTOCOL);
keir@20516 1485 flexarray_set(front, foffset++, "type");
keir@20509 1486 if (console->constype == CONSTYPE_XENCONSOLED)
keir@20516 1487 flexarray_set(front, foffset++, "xenconsoled");
keir@20509 1488 else
keir@20516 1489 flexarray_set(front, foffset++, "ioemu");
keir@20509 1490
keir@20509 1491 libxl_device_generic_add(ctx, &device,
keir@20509 1492 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
keir@20509 1493 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
keir@20516 1494 flexarray_free(back);
keir@20516 1495 flexarray_free(front);
keir@20509 1496
keir@20509 1497 return 0;
keir@20509 1498 }
keir@20509 1499
keir@20509 1500 /******************************************************************************/
keir@20509 1501 int libxl_device_vkb_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb)
keir@20509 1502 {
keir@20509 1503 flexarray_t *front;
keir@20509 1504 flexarray_t *back;
keir@20509 1505 unsigned int boffset = 0;
keir@20509 1506 unsigned int foffset = 0;
keir@20509 1507 libxl_device device;
keir@20509 1508
keir@20509 1509 front = flexarray_make(16, 1);
keir@20509 1510 if (!front)
keir@20509 1511 return ERROR_NOMEM;
keir@20509 1512 back = flexarray_make(16, 1);
keir@20509 1513 if (!back)
keir@20509 1514 return ERROR_NOMEM;
keir@20509 1515
keir@20509 1516 device.backend_devid = vkb->devid;
keir@20509 1517 device.backend_domid = vkb->backend_domid;
keir@20509 1518 device.backend_kind = DEVICE_VKBD;
keir@20509 1519 device.devid = vkb->devid;
keir@20509 1520 device.domid = vkb->domid;
keir@20509 1521 device.kind = DEVICE_VKBD;
keir@20509 1522
keir@20516 1523 flexarray_set(back, boffset++, "frontend-id");
keir@20509 1524 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vkb->domid));
keir@20516 1525 flexarray_set(back, boffset++, "online");
keir@20516 1526 flexarray_set(back, boffset++, "1");
keir@20516 1527 flexarray_set(back, boffset++, "state");
keir@20509 1528 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20516 1529 flexarray_set(back, boffset++, "domain");
keir@20516 1530 flexarray_set(back, boffset++, libxl_domid_to_name(ctx, domid));
keir@20509 1531
keir@20516 1532 flexarray_set(front, foffset++, "backend-id");
keir@20509 1533 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", vkb->backend_domid));
keir@20516 1534 flexarray_set(front, foffset++, "state");
keir@20509 1535 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
keir@20509 1536
keir@20509 1537 libxl_device_generic_add(ctx, &device,
keir@20509 1538 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
keir@20509 1539 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
keir@20516 1540 flexarray_free(back);
keir@20516 1541 flexarray_free(front);
keir@20509 1542
keir@20509 1543 return 0;
keir@20462 1544 }
keir@20462 1545
keir@20462 1546 int libxl_device_vkb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 1547 {
keir@20462 1548 return ERROR_NI;
keir@20462 1549 }
keir@20462 1550
keir@20462 1551 int libxl_device_vkb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 1552 {
keir@20462 1553 return ERROR_NI;
keir@20462 1554 }
keir@20462 1555
keir@20637 1556 libxl_device_disk *libxl_device_disk_list(struct libxl_ctx *ctx, uint32_t domid, int *num)
keir@20637 1557 {
keir@20637 1558 char *be_path_tap, *be_path_vbd;
keir@20637 1559 libxl_device_disk *disks = NULL;
keir@20637 1560 char **l = NULL;
keir@20637 1561 unsigned int numl;
keir@20637 1562 int num_disks = 0, i;
keir@20637 1563 char *type;
keir@20637 1564
keir@20637 1565 be_path_vbd = libxl_sprintf(ctx, "%s/backend/vbd/%d", libxl_xs_get_dompath(ctx, 0), domid);
keir@20637 1566 be_path_tap = libxl_sprintf(ctx, "%s/backend/tap/%d", libxl_xs_get_dompath(ctx, 0), domid);
keir@20637 1567
keir@20637 1568 l = libxl_xs_directory(ctx, XBT_NULL, be_path_vbd, &numl);
keir@20637 1569 if (l) {
keir@20637 1570 num_disks += numl;
keir@20637 1571 disks = realloc(disks, sizeof(libxl_device_disk) * num_disks);
keir@20637 1572 for (i = 0; i < numl; i++) {
keir@20637 1573 disks[i].backend_domid = 0;
keir@20637 1574 disks[i].domid = domid;
keir@20637 1575 disks[i].physpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/params", be_path_vbd, l[i]));
keir@20637 1576 libxl_string_to_phystype(ctx, libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/type", be_path_vbd, l[i])), &(disks[i].phystype));
keir@20637 1577 disks[i].virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/dev", be_path_vbd, l[i]));
keir@20637 1578 disks[i].unpluggable = atoi(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/removable", be_path_vbd, l[i])));
keir@20637 1579 if (!strcmp(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/mode", be_path_vbd, l[i])), "w"))
keir@20637 1580 disks[i].readwrite = 1;
keir@20637 1581 else
keir@20637 1582 disks[i].readwrite = 0;
keir@20637 1583 type = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/device-type", libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/frontend", be_path_vbd, l[i]))));
keir@20637 1584 disks[i].is_cdrom = !strcmp(type, "cdrom");
keir@20637 1585 }
keir@20637 1586 free(l);
keir@20637 1587 }
keir@20637 1588 l = libxl_xs_directory(ctx, XBT_NULL, be_path_tap, &numl);
keir@20637 1589 if (l) {
keir@20637 1590 num_disks += numl;
keir@20637 1591 disks = realloc(disks, sizeof(libxl_device_disk) * num_disks);
keir@20637 1592 for (i = 0; i < numl; i++) {
keir@20637 1593 disks[i].backend_domid = 0;
keir@20637 1594 disks[i].domid = domid;
keir@20637 1595 disks[i].physpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/params", be_path_tap, l[i]));
keir@20637 1596 libxl_string_to_phystype(ctx, libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/type", be_path_tap, l[i])), &(disks[i].phystype));
keir@20637 1597 disks[i].virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/dev", be_path_tap, l[i]));
keir@20637 1598 disks[i].unpluggable = atoi(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/removable", be_path_tap, l[i])));
keir@20637 1599 if (!strcmp(libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/mode", be_path_tap, l[i])), "w"))
keir@20637 1600 disks[i].readwrite = 1;
keir@20637 1601 else
keir@20637 1602 disks[i].readwrite = 0;
keir@20637 1603 type = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/device-type", libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/%s/frontend", be_path_vbd, l[i]))));
keir@20637 1604 disks[i].is_cdrom = !strcmp(type, "cdrom");
keir@20637 1605 }
keir@20637 1606 free(l);
keir@20637 1607 }
keir@20637 1608 *num = num_disks;
keir@20637 1609 return disks;
keir@20637 1610 }
keir@20637 1611
keir@20637 1612 int libxl_cdrom_insert(struct libxl_ctx *ctx, uint32_t domid, libxl_device_disk *disk)
keir@20637 1613 {
keir@20637 1614 int num, i;
keir@20637 1615 uint32_t stubdomid;
keir@20637 1616 libxl_device_disk *disks;
keir@20637 1617
keir@20637 1618 if (!disk->physpath) {
keir@20637 1619 disk->physpath = "";
keir@20637 1620 disk->phystype = PHYSTYPE_PHY;
keir@20637 1621 }
keir@20637 1622 disks = libxl_device_disk_list(ctx, domid, &num);
keir@20637 1623 for (i = 0; i < num; i++) {
keir@20637 1624 if (disks[i].is_cdrom && !strcmp(disk->virtpath, disks[i].virtpath))
keir@20637 1625 /* found */
keir@20637 1626 break;
keir@20637 1627 }
keir@20637 1628 if (i == num) {
keir@20637 1629 XL_LOG(ctx, XL_LOG_ERROR, "Virtual device not found");
keir@20637 1630 return -1;
keir@20637 1631 }
keir@20637 1632 libxl_device_disk_del(ctx, disks + i, 1);
keir@20637 1633 libxl_device_disk_add(ctx, domid, disk);
keir@20637 1634 stubdomid = libxl_get_stubdom_id(ctx, domid);
keir@20637 1635 if (stubdomid) {
keir@20781 1636 disks[i].domid = stubdomid;
keir@20637 1637 libxl_device_disk_del(ctx, disks + i, 1);
keir@20781 1638 disk->domid = stubdomid;
keir@20637 1639 libxl_device_disk_add(ctx, stubdomid, disk);
keir@20781 1640 disk->domid = domid;
keir@20637 1641 }
keir@20637 1642 return 0;
keir@20637 1643 }
keir@20637 1644
keir@20462 1645 /******************************************************************************/
keir@20509 1646 static int libxl_build_xenpv_qemu_args(struct libxl_ctx *ctx,
keir@20509 1647 libxl_device_vfb *vfb,
keir@20509 1648 int num_console,
keir@20509 1649 libxl_device_console *console,
keir@20860 1650 libxl_device_model_info *info)
keir@20860 1651 {
keir@20509 1652 int i = 0, j = 0, num = 0;
keir@20509 1653 memset(info, 0x00, sizeof(libxl_device_model_info));
keir@20509 1654
keir@20509 1655 info->vnc = vfb->vnc;
keir@20509 1656 if (vfb->vnclisten)
keir@20509 1657 info->vnclisten = libxl_sprintf(ctx, "%s", vfb->vnclisten);
keir@20509 1658 info->vncdisplay = vfb->vncdisplay;
keir@20509 1659 info->vncunused = vfb->vncunused;
keir@20509 1660 if (vfb->keymap)
keir@20509 1661 info->keymap = libxl_sprintf(ctx, "%s", vfb->keymap);
keir@20509 1662 info->sdl = vfb->sdl;
keir@20509 1663 info->opengl = vfb->opengl;
keir@20509 1664 for (i = 0; i < num_console; i++) {
keir@20509 1665 if (console->constype == CONSTYPE_IOEMU)
keir@20509 1666 num++;
keir@20509 1667 }
keir@20509 1668 if (num > 0) {
keir@20860 1669 uint32_t guest_domid;
keir@20860 1670 if (libxl_is_stubdom(ctx, vfb->domid, &guest_domid)) {
keir@20599 1671 char *filename;
keir@20599 1672 char *name = libxl_sprintf(ctx, "qemu-dm-%s", libxl_domid_to_name(ctx, guest_domid));
keir@20599 1673 libxl_create_logfile(ctx, name, &filename);
keir@20599 1674 info->serial = libxl_sprintf(ctx, "file:%s", filename);
keir@20599 1675 free(filename);
keir@20599 1676 } else {
keir@20599 1677 info->serial = "pty";
keir@20599 1678 }
keir@20509 1679 num--;
keir@20509 1680 }
keir@20509 1681 if (num > 0) {
keir@20509 1682 info->extra = (char **) libxl_calloc(ctx, num * 2 + 1, sizeof(char *));
keir@20509 1683 for (j = 0; j < num * 2; j = j + 2) {
keir@20509 1684 info->extra[j] = "-serial";
keir@20509 1685 info->extra[j + 1] = "pty";
keir@20509 1686 }
keir@20509 1687 info->extra[j] = NULL;
keir@20509 1688 }
keir@20509 1689 info->domid = vfb->domid;
keir@20509 1690 info->dom_name = libxl_domid_to_name(ctx, vfb->domid);
keir@20509 1691 info->device_model = "/usr/lib/xen/bin/qemu-dm";
keir@20509 1692 info->type = XENPV;
keir@20509 1693 return 0;
keir@20509 1694 }
keir@20509 1695
keir@20509 1696 int libxl_create_xenpv_qemu(struct libxl_ctx *ctx, libxl_device_vfb *vfb,
keir@20514 1697 int num_console, libxl_device_console *console,
keir@20514 1698 struct libxl_device_model_starting **starting_r)
keir@20509 1699 {
keir@20509 1700 libxl_device_model_info info;
keir@20509 1701
keir@20509 1702 libxl_build_xenpv_qemu_args(ctx, vfb, num_console, console, &info);
keir@20542 1703 libxl_create_device_model(ctx, &info, NULL, 0, NULL, 0, starting_r);
keir@20509 1704 return 0;
keir@20509 1705 }
keir@20509 1706
keir@20509 1707 int libxl_device_vfb_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_vfb *vfb)
keir@20462 1708 {
keir@20509 1709 flexarray_t *front;
keir@20509 1710 flexarray_t *back;
keir@20509 1711 unsigned int boffset = 0;
keir@20509 1712 unsigned int foffset = 0;
keir@20509 1713 libxl_device device;
keir@20509 1714
keir@20509 1715 front = flexarray_make(16, 1);
keir@20509 1716 if (!front)
keir@20509 1717 return ERROR_NOMEM;
keir@20509 1718 back = flexarray_make(16, 1);
keir@20509 1719 if (!back)
keir@20509 1720 return ERROR_NOMEM;
keir@20509 1721
keir@20509 1722 device.backend_devid = vfb->devid;
keir@20509 1723 device.backend_domid = vfb->backend_domid;
keir@20509 1724 device.backend_kind = DEVICE_VFB;
keir@20509 1725 device.devid = vfb->devid;
keir@20509 1726 device.domid = vfb->domid;
keir@20509 1727 device.kind = DEVICE_VFB;
keir@20509 1728
keir@20516 1729 flexarray_set(back, boffset++, "frontend-id");
keir@20509 1730 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->domid));
keir@20516 1731 flexarray_set(back, boffset++, "online");
keir@20516 1732 flexarray_set(back, boffset++, "1");
keir@20516 1733 flexarray_set(back, boffset++, "state");
keir@20509 1734 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20516 1735 flexarray_set(back, boffset++, "domain");
keir@20516 1736 flexarray_set(back, boffset++, libxl_domid_to_name(ctx, domid));
keir@20516 1737 flexarray_set(back, boffset++, "vnc");
keir@20509 1738 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->vnc));
keir@20516 1739 flexarray_set(back, boffset++, "vnclisten");
keir@20516 1740 flexarray_set(back, boffset++, vfb->vnclisten);
keir@20516 1741 flexarray_set(back, boffset++, "vncdisplay");
keir@20509 1742 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->vncdisplay));
keir@20516 1743 flexarray_set(back, boffset++, "vncunused");
keir@20509 1744 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->vncunused));
keir@20516 1745 flexarray_set(back, boffset++, "sdl");
keir@20509 1746 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->sdl));
keir@20516 1747 flexarray_set(back, boffset++, "opengl");
keir@20509 1748 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", vfb->opengl));
keir@20509 1749 if (vfb->xauthority) {
keir@20516 1750 flexarray_set(back, boffset++, "xauthority");
keir@20516 1751 flexarray_set(back, boffset++, vfb->xauthority);
keir@20509 1752 }
keir@20509 1753 if (vfb->display) {
keir@20516 1754 flexarray_set(back, boffset++, "display");
keir@20516 1755 flexarray_set(back, boffset++, vfb->display);
keir@20509 1756 }
keir@20509 1757
keir@20516 1758 flexarray_set(front, foffset++, "backend-id");
keir@20509 1759 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", vfb->backend_domid));
keir@20516 1760 flexarray_set(front, foffset++, "state");
keir@20509 1761 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
keir@20509 1762
keir@20509 1763 libxl_device_generic_add(ctx, &device,
keir@20509 1764 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
keir@20509 1765 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
keir@20509 1766 flexarray_free(front);
keir@20509 1767 flexarray_free(back);
keir@20509 1768
keir@20509 1769 return 0;
keir@20462 1770 }
keir@20462 1771
keir@20462 1772 int libxl_device_vfb_clean_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 1773 {
keir@20462 1774 return ERROR_NI;
keir@20462 1775 }
keir@20462 1776
keir@20462 1777 int libxl_device_vfb_hard_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20462 1778 {
keir@20462 1779 return ERROR_NI;
keir@20462 1780 }
keir@20462 1781
keir@20462 1782 /******************************************************************************/
keir@20482 1783
keir@20482 1784 int libxl_device_pci_init(libxl_device_pci *pcidev, unsigned int domain,
keir@20482 1785 unsigned int bus, unsigned int dev,
keir@20482 1786 unsigned int func, unsigned int vdevfn)
keir@20482 1787 {
keir@20482 1788 pcidev->domain = domain;
keir@20482 1789 pcidev->bus = bus;
keir@20482 1790 pcidev->dev = dev;
keir@20482 1791 pcidev->func = func;
keir@20482 1792 pcidev->vdevfn = vdevfn;
keir@20482 1793 return 0;
keir@20482 1794 }
keir@20482 1795
keir@20482 1796 static int libxl_create_pci_backend(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev, int num)
keir@20482 1797 {
keir@20482 1798 flexarray_t *front;
keir@20482 1799 flexarray_t *back;
keir@20482 1800 unsigned int boffset = 0;
keir@20482 1801 unsigned int foffset = 0;
keir@20482 1802 libxl_device device;
keir@20482 1803 int i;
keir@20482 1804
keir@20482 1805 front = flexarray_make(16, 1);
keir@20482 1806 if (!front)
keir@20482 1807 return ERROR_NOMEM;
keir@20482 1808 back = flexarray_make(16, 1);
keir@20482 1809 if (!back)
keir@20482 1810 return ERROR_NOMEM;
keir@20482 1811
keir@20512 1812 XL_LOG(ctx, XL_LOG_DEBUG, "Creating pci backend");
keir@20482 1813
keir@20482 1814 /* add pci device */
keir@20482 1815 device.backend_devid = 0;
keir@20482 1816 device.backend_domid = 0;
keir@20482 1817 device.backend_kind = DEVICE_PCI;
keir@20482 1818 device.devid = 0;
keir@20482 1819 device.domid = domid;
keir@20482 1820 device.kind = DEVICE_PCI;
keir@20482 1821
keir@20516 1822 flexarray_set(back, boffset++, "frontend-id");
keir@20482 1823 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", domid));
keir@20516 1824 flexarray_set(back, boffset++, "online");
keir@20516 1825 flexarray_set(back, boffset++, "1");
keir@20516 1826 flexarray_set(back, boffset++, "state");
keir@20482 1827 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20516 1828 flexarray_set(back, boffset++, "domain");
keir@20516 1829 flexarray_set(back, boffset++, libxl_domid_to_name(ctx, domid));
keir@20482 1830 for (i = 0; i < num; i++) {
keir@20482 1831 flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", i));
keir@20482 1832 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
keir@20482 1833 flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", i));
keir@20482 1834 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
keir@20482 1835 if (pcidev->vdevfn) {
keir@20482 1836 flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", i));
keir@20482 1837 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn));
keir@20482 1838 }
keir@20482 1839 flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", i));
keir@20482 1840 flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
keir@20482 1841 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", i));
keir@20482 1842 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20482 1843 }
keir@20516 1844 flexarray_set(back, boffset++, "num_devs");
keir@20482 1845 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num));
keir@20482 1846
keir@20516 1847 flexarray_set(front, foffset++, "backend-id");
keir@20482 1848 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 0));
keir@20516 1849 flexarray_set(front, foffset++, "state");
keir@20482 1850 flexarray_set(front, foffset++, libxl_sprintf(ctx, "%d", 1));
keir@20482 1851
keir@20482 1852 libxl_device_generic_add(ctx, &device,
keir@20482 1853 libxl_xs_kvs_of_flexarray(ctx, back, boffset),
keir@20482 1854 libxl_xs_kvs_of_flexarray(ctx, front, foffset));
keir@20482 1855
keir@20482 1856 flexarray_free(back);
keir@20482 1857 flexarray_free(front);
keir@20482 1858 return 0;
keir@20482 1859 }
keir@20482 1860
keir@20482 1861 static int libxl_device_pci_add_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
keir@20462 1862 {
keir@20482 1863 flexarray_t *back;
keir@20482 1864 char *num_devs, *be_path;
keir@20482 1865 int num = 0;
keir@20482 1866 unsigned int boffset = 0;
keir@20482 1867 xs_transaction_t t;
keir@20482 1868
keir@20516 1869 be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", libxl_xs_get_dompath(ctx, 0), domid);
keir@20482 1870 num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path));
keir@20482 1871 if (!num_devs)
keir@20482 1872 return libxl_create_pci_backend(ctx, domid, pcidev, 1);
keir@20482 1873
keir@20482 1874 if (!is_hvm(ctx, domid)) {
keir@20482 1875 if (libxl_wait_for_backend(ctx, be_path, "4") < 0)
keir@20482 1876 return -1;
keir@20482 1877 }
keir@20482 1878
keir@20482 1879 back = flexarray_make(16, 1);
keir@20482 1880 if (!back)
keir@20482 1881 return ERROR_NOMEM;
keir@20482 1882
keir@20512 1883 XL_LOG(ctx, XL_LOG_DEBUG, "Adding new pci device to xenstore");
keir@20482 1884 num = atoi(num_devs);
keir@20482 1885 flexarray_set(back, boffset++, libxl_sprintf(ctx, "key-%d", num));
keir@20482 1886 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
keir@20482 1887 flexarray_set(back, boffset++, libxl_sprintf(ctx, "dev-%d", num));
keir@20482 1888 flexarray_set(back, boffset++, libxl_sprintf(ctx, PCI_BDF, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func));
keir@20482 1889 if (pcidev->vdevfn) {
keir@20482 1890 flexarray_set(back, boffset++, libxl_sprintf(ctx, "vdevfn-%d", num));
keir@20482 1891 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%x", pcidev->vdevfn));
keir@20482 1892 }
keir@20482 1893 flexarray_set(back, boffset++, libxl_sprintf(ctx, "opts-%d", num));
keir@20482 1894 flexarray_set(back, boffset++, libxl_sprintf(ctx, "msitranslate=%d,power_mgmt=%d", pcidev->msitranslate, pcidev->power_mgmt));
keir@20482 1895 flexarray_set(back, boffset++, libxl_sprintf(ctx, "state-%d", num));
keir@20482 1896 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 1));
keir@20516 1897 flexarray_set(back, boffset++, "num_devs");
keir@20482 1898 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", num + 1));
keir@20516 1899 flexarray_set(back, boffset++, "state");
keir@20482 1900 flexarray_set(back, boffset++, libxl_sprintf(ctx, "%d", 7));
keir@20482 1901
keir@20482 1902 retry_transaction:
keir@20482 1903 t = xs_transaction_start(ctx->xsh);
keir@20482 1904 libxl_xs_writev(ctx, t, be_path,
keir@20482 1905 libxl_xs_kvs_of_flexarray(ctx, back, boffset));
keir@20482 1906 if (!xs_transaction_end(ctx->xsh, t, 0))
keir@20482 1907 if (errno == EAGAIN)
keir@20482 1908 goto retry_transaction;
keir@20482 1909
keir@20482 1910 flexarray_free(back);
keir@20482 1911 return 0;
keir@20482 1912 }
keir@20482 1913
keir@20482 1914 static int libxl_device_pci_remove_xenstore(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
keir@20482 1915 {
keir@20542 1916 char *be_path, *num_devs_path, *num_devs, *xsdev, *tmp, *tmppath;
keir@20542 1917 int num, i, j;
keir@20482 1918 xs_transaction_t t;
keir@20482 1919 unsigned int domain = 0, bus = 0, dev = 0, func = 0;
keir@20482 1920
keir@20516 1921 be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", libxl_xs_get_dompath(ctx, 0), domid);
keir@20482 1922 num_devs_path = libxl_sprintf(ctx, "%s/num_devs", be_path);
keir@20482 1923 num_devs = libxl_xs_read(ctx, XBT_NULL, num_devs_path);
keir@20482 1924 if (!num_devs)
keir@20482 1925 return -1;
keir@20482 1926 num = atoi(num_devs);
keir@20482 1927
keir@20482 1928 if (!is_hvm(ctx, domid)) {
keir@20482 1929 if (libxl_wait_for_backend(ctx, be_path, "4") < 0) {
keir@20542 1930 XL_LOG(ctx, XL_LOG_DEBUG, "pci backend at %s is not ready", be_path);
keir@20482 1931 return -1;
keir@20482 1932 }
keir@20482 1933 }
keir@20482 1934
keir@20482 1935 for (i = 0; i < num; i++) {
keir@20482 1936 xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
keir@20482 1937 sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
keir@20482 1938 if (domain == pcidev->domain && bus == pcidev->bus &&
keir@20482 1939 pcidev->dev == dev && pcidev->func == func) {
keir@20482 1940 break;
keir@20482 1941 }
keir@20482 1942 }
keir@20482 1943 if (i == num) {
keir@20512 1944 XL_LOG(ctx, XL_LOG_ERROR, "Couldn't find the device on xenstore");
keir@20482 1945 return -1;
keir@20482 1946 }
keir@20482 1947
keir@20482 1948 retry_transaction:
keir@20482 1949 t = xs_transaction_start(ctx->xsh);
keir@20542 1950 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state-%d", be_path, i), "5", strlen("5"));
keir@20482 1951 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state", be_path), "7", strlen("7"));
keir@20482 1952 if (!xs_transaction_end(ctx->xsh, t, 0))
keir@20482 1953 if (errno == EAGAIN)
keir@20482 1954 goto retry_transaction;
keir@20542 1955
keir@20542 1956 if (!is_hvm(ctx, domid)) {
keir@20542 1957 if (libxl_wait_for_backend(ctx, be_path, "4") < 0) {
keir@20542 1958 XL_LOG(ctx, XL_LOG_DEBUG, "pci backend at %s is not ready", be_path);
keir@20542 1959 return -1;
keir@20542 1960 }
keir@20542 1961 }
keir@20542 1962
keir@20542 1963 retry_transaction2:
keir@20542 1964 t = xs_transaction_start(ctx->xsh);
keir@20542 1965 xs_rm(ctx->xsh, t, libxl_sprintf(ctx, "%s/state-%d", be_path, i));
keir@20542 1966 xs_rm(ctx->xsh, t, libxl_sprintf(ctx, "%s/key-%d", be_path, i));
keir@20542 1967 xs_rm(ctx->xsh, t, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
keir@20542 1968 xs_rm(ctx->xsh, t, libxl_sprintf(ctx, "%s/vdev-%d", be_path, i));
keir@20542 1969 xs_rm(ctx->xsh, t, libxl_sprintf(ctx, "%s/opts-%d", be_path, i));
keir@20542 1970 xs_rm(ctx->xsh, t, libxl_sprintf(ctx, "%s/vdevfn-%d", be_path, i));
keir@20542 1971 libxl_xs_write(ctx, t, num_devs_path, "%d", num - 1);
keir@20542 1972 for (j = i + 1; j < num; j++) {
keir@20542 1973 tmppath = libxl_sprintf(ctx, "%s/state-%d", be_path, j);
keir@20542 1974 tmp = libxl_xs_read(ctx, t, tmppath);
keir@20542 1975 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/state-%d", be_path, j - 1), tmp, strlen(tmp));
keir@20542 1976 xs_rm(ctx->xsh, t, tmppath);
keir@20542 1977 tmppath = libxl_sprintf(ctx, "%s/dev-%d", be_path, j);
keir@20542 1978 tmp = libxl_xs_read(ctx, t, tmppath);
keir@20542 1979 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/dev-%d", be_path, j - 1), tmp, strlen(tmp));
keir@20542 1980 xs_rm(ctx->xsh, t, tmppath);
keir@20542 1981 tmppath = libxl_sprintf(ctx, "%s/key-%d", be_path, j);
keir@20542 1982 tmp = libxl_xs_read(ctx, t, tmppath);
keir@20542 1983 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/key-%d", be_path, j - 1), tmp, strlen(tmp));
keir@20542 1984 xs_rm(ctx->xsh, t, tmppath);
keir@20542 1985 tmppath = libxl_sprintf(ctx, "%s/vdev-%d", be_path, j);
keir@20542 1986 tmp = libxl_xs_read(ctx, t, tmppath);
keir@20542 1987 if (tmp) {
keir@20542 1988 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vdev-%d", be_path, j - 1), tmp, strlen(tmp));
keir@20542 1989 xs_rm(ctx->xsh, t, tmppath);
keir@20542 1990 }
keir@20542 1991 tmppath = libxl_sprintf(ctx, "%s/opts-%d", be_path, j);
keir@20542 1992 tmp = libxl_xs_read(ctx, t, tmppath);
keir@20542 1993 if (tmp) {
keir@20542 1994 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/opts-%d", be_path, j - 1), tmp, strlen(tmp));
keir@20542 1995 xs_rm(ctx->xsh, t, tmppath);
keir@20542 1996 }
keir@20542 1997 tmppath = libxl_sprintf(ctx, "%s/vdevfn-%d", be_path, j);
keir@20542 1998 tmp = libxl_xs_read(ctx, t, tmppath);
keir@20542 1999 if (tmp) {
keir@20542 2000 xs_write(ctx->xsh, t, libxl_sprintf(ctx, "%s/vdevfn-%d", be_path, j - 1), tmp, strlen(tmp));
keir@20542 2001 xs_rm(ctx->xsh, t, tmppath);
keir@20542 2002 }
keir@20542 2003 }
keir@20542 2004 if (!xs_transaction_end(ctx->xsh, t, 0))
keir@20542 2005 if (errno == EAGAIN)
keir@20542 2006 goto retry_transaction2;
keir@20542 2007
keir@20542 2008 if (num == 1) {
keir@20542 2009 char *fe_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/frontend", be_path));
keir@20542 2010 libxl_device_destroy(ctx, be_path, 1);
keir@20542 2011 xs_rm(ctx->xsh, XBT_NULL, be_path);
keir@20542 2012 xs_rm(ctx->xsh, XBT_NULL, fe_path);
keir@20542 2013 return 0;
keir@20542 2014 }
keir@20542 2015
keir@20482 2016 return 0;
keir@20462 2017 }
keir@20462 2018
keir@20482 2019 int libxl_device_pci_add(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
keir@20462 2020 {
keir@20779 2021 char *path;
keir@20482 2022 char *state, *vdevfn;
keir@20482 2023 int rc, hvm;
keir@20542 2024 int stubdomid = 0;
keir@20482 2025
keir@20482 2026 /* TODO: check if the device can be assigned */
keir@20482 2027
keir@20482 2028 libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 2029
keir@20779 2030 stubdomid = libxl_get_stubdom_id(ctx, domid);
keir@20779 2031 if (stubdomid != 0) {
keir@20542 2032 libxl_device_pci pcidev_s = *pcidev;
keir@20542 2033 libxl_device_pci_add(ctx, stubdomid, &pcidev_s);
keir@20542 2034 }
keir@20542 2035
keir@20482 2036 hvm = is_hvm(ctx, domid);
keir@20482 2037 if (hvm) {
keir@20831 2038 if (libxl_wait_for_device_model(ctx, domid, "running", NULL, NULL) < 0) {
keir@20482 2039 return -1;
keir@20482 2040 }
keir@20779 2041 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/state", domid);
keir@20482 2042 state = libxl_xs_read(ctx, XBT_NULL, path);
keir@20779 2043 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/parameter", domid);
keir@20482 2044 if (pcidev->vdevfn)
keir@20482 2045 libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF_VDEVFN, pcidev->domain,
keir@20482 2046 pcidev->bus, pcidev->dev, pcidev->func, pcidev->vdevfn);
keir@20482 2047 else
keir@20482 2048 libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
keir@20482 2049 pcidev->bus, pcidev->dev, pcidev->func);
keir@20779 2050 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid);
keir@20482 2051 xs_write(ctx->xsh, XBT_NULL, path, "pci-ins", strlen("pci-ins"));
keir@20831 2052 if (libxl_wait_for_device_model(ctx, domid, "pci-inserted", NULL, NULL) < 0)
keir@20512 2053 XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time");
keir@20779 2054 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/parameter", domid);
keir@20482 2055 vdevfn = libxl_xs_read(ctx, XBT_NULL, path);
keir@20482 2056 sscanf(vdevfn + 2, "%x", &pcidev->vdevfn);
keir@20779 2057 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/state", domid);
keir@20482 2058 xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
keir@20482 2059 } else {
keir@20542 2060 char *sysfs_path = libxl_sprintf(ctx, SYSFS_PCI_DEV"/"PCI_BDF"/resource", pcidev->domain,
keir@20482 2061 pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 2062 FILE *f = fopen(sysfs_path, "r");
keir@20482 2063 unsigned int start = 0, end = 0, flags = 0, size = 0;
keir@20482 2064 int irq = 0;
keir@20482 2065 int i;
keir@20482 2066
keir@20482 2067 if (f == NULL) {
keir@20512 2068 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't open %s", sysfs_path);
keir@20482 2069 return -1;
keir@20482 2070 }
keir@20482 2071 for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
keir@20512 2072 fscanf(f, "0x%x 0x%x 0x%x", &start, &end, &flags);
keir@20482 2073 size = end - start + 1;
keir@20482 2074 if (start) {
keir@20482 2075 if (flags & PCI_BAR_IO) {
keir@20482 2076 rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 1);
keir@20482 2077 if (rc < 0)
keir@20512 2078 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "Error: xc_domain_ioport_permission error 0x%x/0x%x", start, size);
keir@20482 2079 } else {
keir@20482 2080 rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT,
keir@20482 2081 (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 1);
keir@20482 2082 if (rc < 0)
keir@20512 2083 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "Error: xc_domain_iomem_permission error 0x%x/0x%x", start, size);
keir@20482 2084 }
keir@20482 2085 }
keir@20482 2086 }
keir@20482 2087 fclose(f);
keir@20542 2088 sysfs_path = libxl_sprintf(ctx, SYSFS_PCI_DEV"/"PCI_BDF"/irq", pcidev->domain,
keir@20482 2089 pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 2090 f = fopen(sysfs_path, "r");
keir@20482 2091 if (f == NULL) {
keir@20512 2092 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't open %s", sysfs_path);
keir@20482 2093 goto out;
keir@20482 2094 }
keir@20482 2095 fscanf(f, "%u", &irq);
keir@20482 2096 if (irq) {
keir@20482 2097 rc = xc_physdev_map_pirq(ctx->xch, domid, irq, &irq);
keir@20482 2098 if (rc < 0) {
keir@20512 2099 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "Error: xc_physdev_map_pirq irq=%d", irq);
keir@20482 2100 }
keir@20482 2101 rc = xc_domain_irq_permission(ctx->xch, domid, irq, 1);
keir@20482 2102 if (rc < 0) {
keir@20512 2103 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "Error: xc_domain_irq_permission irq=%d", irq);
keir@20482 2104 }
keir@20482 2105 }
keir@20482 2106 fclose(f);
keir@20482 2107 }
keir@20482 2108 out:
keir@20860 2109 if (!libxl_is_stubdom(ctx, domid, NULL)) {
keir@20779 2110 rc = xc_assign_device(ctx->xch, domid, pcidev->value);
keir@20779 2111 if (rc < 0)
keir@20542 2112 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_assign_device failed");
keir@20542 2113 }
keir@20482 2114
keir@20482 2115 libxl_device_pci_add_xenstore(ctx, domid, pcidev);
keir@20482 2116 return 0;
keir@20462 2117 }
keir@20462 2118
keir@20482 2119 int libxl_device_pci_remove(struct libxl_ctx *ctx, uint32_t domid, libxl_device_pci *pcidev)
keir@20462 2120 {
keir@20779 2121 char *path;
keir@20482 2122 char *state;
keir@20482 2123 int hvm, rc;
keir@20542 2124 int stubdomid = 0;
keir@20482 2125
keir@20482 2126 /* TODO: check if the device can be detached */
keir@20542 2127 libxl_device_pci_remove_xenstore(ctx, domid, pcidev);
keir@20482 2128
keir@20482 2129 hvm = is_hvm(ctx, domid);
keir@20482 2130 if (hvm) {
keir@20831 2131 if (libxl_wait_for_device_model(ctx, domid, "running", NULL, NULL) < 0) {
keir@20482 2132 return -1;
keir@20482 2133 }
keir@20779 2134 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/state", domid);
keir@20482 2135 state = libxl_xs_read(ctx, XBT_NULL, path);
keir@20779 2136 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/parameter", domid);
keir@20482 2137 libxl_xs_write(ctx, XBT_NULL, path, PCI_BDF, pcidev->domain,
keir@20482 2138 pcidev->bus, pcidev->dev, pcidev->func);
keir@20779 2139 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/command", domid);
keir@20482 2140 xs_write(ctx->xsh, XBT_NULL, path, "pci-rem", strlen("pci-rem"));
keir@20831 2141 if (libxl_wait_for_device_model(ctx, domid, "pci-removed", NULL, NULL) < 0) {
keir@20512 2142 XL_LOG(ctx, XL_LOG_ERROR, "Device Model didn't respond in time");
keir@20482 2143 return -1;
keir@20482 2144 }
keir@20779 2145 path = libxl_sprintf(ctx, "/local/domain/0/device-model/%d/state", domid);
keir@20482 2146 xs_write(ctx->xsh, XBT_NULL, path, state, strlen(state));
keir@20482 2147 } else {
keir@20542 2148 char *sysfs_path = libxl_sprintf(ctx, SYSFS_PCI_DEV"/"PCI_BDF"/resource", pcidev->domain,
keir@20482 2149 pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 2150 FILE *f = fopen(sysfs_path, "r");
keir@20482 2151 unsigned int start = 0, end = 0, flags = 0, size = 0;
keir@20482 2152 int irq = 0;
keir@20482 2153 int i;
keir@20482 2154
keir@20482 2155 if (f == NULL) {
keir@20512 2156 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't open %s", sysfs_path);
keir@20482 2157 goto skip1;
keir@20482 2158 }
keir@20482 2159 for (i = 0; i < PROC_PCI_NUM_RESOURCES; i++) {
keir@20482 2160 fscanf(f, "0x%x 0x%x 0x%x\n", &start, &end, &flags);
keir@20482 2161 size = end - start + 1;
keir@20482 2162 if (start) {
keir@20482 2163 if (flags & PCI_BAR_IO) {
keir@20482 2164 rc = xc_domain_ioport_permission(ctx->xch, domid, start, size, 0);
keir@20482 2165 if (rc < 0)
keir@20512 2166 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_domain_ioport_permission error 0x%x/0x%x", start, size);
keir@20482 2167 } else {
keir@20482 2168 rc = xc_domain_iomem_permission(ctx->xch, domid, start>>XC_PAGE_SHIFT,
keir@20482 2169 (size+(XC_PAGE_SIZE-1))>>XC_PAGE_SHIFT, 0);
keir@20482 2170 if (rc < 0)
keir@20512 2171 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_domain_iomem_permission error 0x%x/0x%x", start, size);
keir@20482 2172 }
keir@20482 2173 }
keir@20482 2174 }
keir@20482 2175 fclose(f);
keir@20482 2176 skip1:
keir@20542 2177 sysfs_path = libxl_sprintf(ctx, SYSFS_PCI_DEV"/"PCI_BDF"/irq", pcidev->domain,
keir@20482 2178 pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 2179 f = fopen(sysfs_path, "r");
keir@20482 2180 if (f == NULL) {
keir@20512 2181 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "Couldn't open %s", sysfs_path);
keir@20482 2182 goto out;
keir@20482 2183 }
keir@20482 2184 fscanf(f, "%u", &irq);
keir@20482 2185 if (irq) {
keir@20482 2186 rc = xc_physdev_unmap_pirq(ctx->xch, domid, irq);
keir@20482 2187 if (rc < 0) {
keir@20512 2188 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_physdev_map_pirq irq=%d", irq);
keir@20482 2189 }
keir@20482 2190 rc = xc_domain_irq_permission(ctx->xch, domid, irq, 0);
keir@20482 2191 if (rc < 0) {
keir@20512 2192 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_domain_irq_permission irq=%d", irq);
keir@20482 2193 }
keir@20482 2194 }
keir@20482 2195 fclose(f);
keir@20482 2196 }
keir@20482 2197 out:
keir@20482 2198 libxl_device_pci_flr(ctx, pcidev->domain, pcidev->bus, pcidev->dev, pcidev->func);
keir@20482 2199
keir@20860 2200 if (!libxl_is_stubdom(ctx, domid, NULL)) {
keir@20779 2201 rc = xc_deassign_device(ctx->xch, domid, pcidev->value);
keir@20779 2202 if (rc < 0)
keir@20542 2203 XL_LOG_ERRNOVAL(ctx, XL_LOG_ERROR, rc, "xc_deassign_device failed");
keir@20542 2204 }
keir@20542 2205
keir@20779 2206 stubdomid = libxl_get_stubdom_id(ctx, domid);
keir@20779 2207 if (stubdomid != 0) {
keir@20542 2208 libxl_device_pci pcidev_s = *pcidev;
keir@20542 2209 libxl_device_pci_remove(ctx, stubdomid, &pcidev_s);
keir@20542 2210 }
keir@20542 2211
keir@20482 2212 return 0;
keir@20462 2213 }
keir@20482 2214
keir@20482 2215 libxl_device_pci *libxl_device_pci_list(struct libxl_ctx *ctx, uint32_t domid, int *num)
keir@20482 2216 {
keir@20482 2217 char *be_path, *num_devs, *xsdev, *xsvdevfn, *xsopts;
keir@20482 2218 int n, i;
keir@20482 2219 unsigned int domain = 0, bus = 0, dev = 0, func = 0, vdevfn = 0;
keir@20482 2220 libxl_device_pci *pcidevs;
keir@20482 2221
keir@20516 2222 be_path = libxl_sprintf(ctx, "%s/backend/pci/%d/0", libxl_xs_get_dompath(ctx, 0), domid);
keir@20482 2223 num_devs = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/num_devs", be_path));
keir@20482 2224 if (!num_devs) {
keir@20482 2225 *num = 0;
keir@20482 2226 return NULL;
keir@20482 2227 }
keir@20482 2228 n = atoi(num_devs);
keir@20779 2229 pcidevs = calloc(n, sizeof(libxl_device_pci));
keir@20482 2230 *num = n;
keir@20482 2231
keir@20482 2232 for (i = 0; i < n; i++) {
keir@20482 2233 xsdev = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev-%d", be_path, i));
keir@20482 2234 sscanf(xsdev, PCI_BDF, &domain, &bus, &dev, &func);
keir@20482 2235 xsvdevfn = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/vdevfn-%d", be_path, i));
keir@20482 2236 if (xsvdevfn)
keir@20482 2237 vdevfn = strtol(xsvdevfn, (char **) NULL, 16);
keir@20482 2238 libxl_device_pci_init(pcidevs + i, domain, bus, dev, func, vdevfn);
keir@20482 2239 xsopts = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/opts-%d", be_path, i));
keir@20482 2240 if (xsopts) {
keir@20482 2241 char *saveptr;
keir@20482 2242 char *p = strtok_r(xsopts, ",=", &saveptr);
keir@20482 2243 do {
keir@20482 2244 while (*p == ' ')
keir@20482 2245 p++;
keir@20482 2246 if (!strcmp(p, "msitranslate")) {
keir@20482 2247 p = strtok_r(NULL, ",=", &saveptr);
keir@20482 2248 pcidevs[i].msitranslate = atoi(p);
keir@20482 2249 } else if (!strcmp(p, "power_mgmt")) {
keir@20482 2250 p = strtok_r(NULL, ",=", &saveptr);
keir@20482 2251 pcidevs[i].power_mgmt = atoi(p);
keir@20482 2252 }
keir@20482 2253 } while ((p = strtok_r(NULL, ",=", &saveptr)) != NULL);
keir@20482 2254 }
keir@20482 2255 }
keir@20482 2256 return pcidevs;
keir@20482 2257 }
keir@20482 2258
keir@20482 2259 int libxl_device_pci_shutdown(struct libxl_ctx *ctx, uint32_t domid)
keir@20482 2260 {
keir@20482 2261 libxl_device_pci *pcidevs;
keir@20482 2262 int num, i;
keir@20482 2263
keir@20482 2264 pcidevs = libxl_device_pci_list(ctx, domid, &num);
keir@20482 2265 for (i = 0; i < num; i++) {
keir@20482 2266 if (libxl_device_pci_remove(ctx, domid, pcidevs + i) < 0)
keir@20482 2267 return -1;
keir@20482 2268 }
keir@20516 2269 free(pcidevs);
keir@20482 2270 return 0;
keir@20482 2271 }
keir@20482 2272
keir@20647 2273 int libxl_set_memory_target(struct libxl_ctx *ctx, uint32_t domid, uint32_t target_memkb)
keir@20647 2274 {
keir@20647 2275 int rc = 0;
keir@20647 2276 uint32_t videoram;
keir@20647 2277 char *videoram_s = NULL;
keir@20647 2278 char *dompath = libxl_xs_get_dompath(ctx, domid);
keir@20542 2279
keir@20647 2280 videoram_s = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/memory/videoram", dompath));
keir@20647 2281 if (!videoram_s)
keir@20647 2282 return -1;
keir@20647 2283 videoram = atoi(videoram_s);
keir@20647 2284
keir@20647 2285 libxl_xs_write(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/memory/target", dompath), "%lu", target_memkb);
keir@20779 2286 rc = xc_domain_setmaxmem(ctx->xch, domid, target_memkb + LIBXL_MAXMEM_CONSTANT);
keir@20779 2287 if (rc != 0)
keir@20779 2288 return rc;
keir@20647 2289 rc = xc_domain_memory_set_pod_target(ctx->xch, domid, (target_memkb - videoram) / 4, NULL, NULL, NULL);
keir@20647 2290 return rc;
keir@20647 2291 }
keir@20875 2292
keir@20875 2293 int libxl_button_press(struct libxl_ctx *ctx, uint32_t domid, libxl_button button)
keir@20875 2294 {
keir@20875 2295 int rc = -1;
keir@20875 2296
keir@20875 2297 switch (button) {
keir@20875 2298 case POWER_BUTTON:
keir@20875 2299 rc = xc_domain_send_trigger(ctx->xch, domid, XEN_DOMCTL_SENDTRIGGER_POWER, 0);
keir@20875 2300 break;
keir@20875 2301 case SLEEP_BUTTON:
keir@20875 2302 rc = xc_domain_send_trigger(ctx->xch, domid, XEN_DOMCTL_SENDTRIGGER_SLEEP, 0);
keir@20875 2303 break;
keir@20875 2304 default:
keir@20875 2305 break;
keir@20875 2306 }
keir@20875 2307
keir@20875 2308 return rc;
keir@20875 2309 }
keir@21141 2310
keir@21141 2311 int libxl_get_physinfo(struct libxl_ctx *ctx, struct libxl_physinfo *physinfo)
keir@21141 2312 {
keir@21141 2313 xc_physinfo_t xcphysinfo = { 0 };
keir@21141 2314 int rc;
keir@21141 2315
keir@21141 2316 rc = xc_physinfo(ctx->xch, &xcphysinfo);
keir@21141 2317 if (rc != 0) {
keir@21141 2318 return rc;
keir@21141 2319 }
keir@21141 2320 physinfo->threads_per_core = xcphysinfo.threads_per_core;
keir@21141 2321 physinfo->cores_per_socket = xcphysinfo.cores_per_socket;
keir@21142 2322 physinfo->max_cpu_id = xcphysinfo.max_cpu_id;
keir@21141 2323 physinfo->nr_cpus = xcphysinfo.nr_cpus;
keir@21141 2324 physinfo->cpu_khz = xcphysinfo.cpu_khz;
keir@21141 2325 physinfo->total_pages = xcphysinfo.total_pages;
keir@21141 2326 physinfo->free_pages = xcphysinfo.free_pages;
keir@21141 2327 physinfo->scrub_pages = xcphysinfo.scrub_pages;
keir@21141 2328 return 0;
keir@21141 2329 }
keir@21141 2330
keir@21141 2331 struct libxl_vcpuinfo *libxl_list_vcpu(struct libxl_ctx *ctx, uint32_t domid,
keir@21141 2332 int *nb_vcpu, int *cpusize)
keir@21141 2333 {
keir@21141 2334 struct libxl_vcpuinfo *ptr, *ret;
keir@21141 2335 xc_domaininfo_t domaininfo;
keir@21141 2336 xc_vcpuinfo_t vcpuinfo;
keir@21141 2337 xc_physinfo_t physinfo = { 0 };
keir@21141 2338
keir@21141 2339 if (xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo) != 1) {
keir@21141 2340 return NULL;
keir@21141 2341 }
keir@21141 2342 if (xc_physinfo(ctx->xch, &physinfo) == -1) {
keir@21141 2343 return NULL;
keir@21141 2344 }
keir@21141 2345 *cpusize = physinfo.max_cpu_id + 1;
keir@21141 2346 ptr = libxl_calloc(ctx, domaininfo.max_vcpu_id + 1, sizeof (struct libxl_vcpuinfo));
keir@21141 2347 if (!ptr) {
keir@21141 2348 return NULL;
keir@21141 2349 }
keir@21141 2350
keir@21141 2351 ret = ptr;
keir@21141 2352 for (*nb_vcpu = 0; *nb_vcpu <= domaininfo.max_vcpu_id; ++*nb_vcpu, ++ptr) {
keir@21141 2353 ptr->cpumap = libxl_calloc(ctx, (*cpusize + 63) / 64, sizeof (uint64_t));
keir@21141 2354 if (!ptr->cpumap) {
keir@21141 2355 return NULL;
keir@21141 2356 }
keir@21141 2357 if (xc_vcpu_getinfo(ctx->xch, domid, *nb_vcpu, &vcpuinfo) == -1) {
keir@21141 2358 return NULL;
keir@21141 2359 }
keir@21141 2360 if (xc_vcpu_getaffinity(ctx->xch, domid, *nb_vcpu, ptr->cpumap, *cpusize) == -1) {
keir@21141 2361 return NULL;
keir@21141 2362 }
keir@21141 2363 ptr->vcpuid = *nb_vcpu;
keir@21141 2364 ptr->cpu = vcpuinfo.cpu;
keir@21141 2365 ptr->online = !!vcpuinfo.online;
keir@21141 2366 ptr->blocked = !!vcpuinfo.blocked;
keir@21141 2367 ptr->running = !!vcpuinfo.running;
keir@21141 2368 ptr->vcpu_time = vcpuinfo.cpu_time;
keir@21141 2369 }
keir@21141 2370 return ret;
keir@21141 2371 }
keir@21142 2372
keir@21142 2373 int libxl_set_vcpuaffinity(struct libxl_ctx *ctx, uint32_t domid, uint32_t vcpuid,
keir@21142 2374 uint64_t *cpumap, int cpusize)
keir@21142 2375 {
keir@21142 2376 return (xc_vcpu_setaffinity(ctx->xch, domid, vcpuid, cpumap, cpusize));
keir@21142 2377 }
keir@21143 2378
keir@21143 2379 int libxl_set_vcpucount(struct libxl_ctx *ctx, uint32_t domid, uint32_t count)
keir@21143 2380 {
keir@21143 2381 xc_domaininfo_t domaininfo;
keir@21143 2382 char *dompath;
keir@21143 2383 int i;
keir@21143 2384
keir@21143 2385 if (xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo) != 1) {
keir@21143 2386 return ERROR_FAIL;
keir@21143 2387 }
keir@21143 2388 if (!count || ((domaininfo.max_vcpu_id + 1) < count)) {
keir@21143 2389 return ERROR_INVAL;
keir@21143 2390 }
keir@21143 2391 if (!(dompath = libxl_xs_get_dompath(ctx, domid)))
keir@21143 2392 return ERROR_FAIL;
keir@21143 2393
keir@21143 2394 for (i = 0; i <= domaininfo.max_vcpu_id; ++i) {
keir@21143 2395 libxl_xs_write(ctx, XBT_NULL,
keir@21143 2396 libxl_sprintf(ctx, "%s/cpu/%u/availability", dompath, i),
keir@21143 2397 "%s", ((1 << i) & ((1 << count) - 1)) ? "online" : "offline");
keir@21143 2398 }
keir@21143 2399 return 0;
keir@21143 2400 }