debuggers.hg

view tools/libxl/libxl_create.c @ 22848:6341fe0f4e5a

Added tag 4.1.0-rc2 for changeset 9dca60d88c63
author Keir Fraser <keir@xen.org>
date Tue Jan 25 14:06:55 2011 +0000 (2011-01-25)
parents 8b6e7f43683e
children c5a7a40cc4f4
line source
1 /*
2 * Copyright (C) 2010 Citrix Ltd.
3 * Author Vincent Hanquez <vincent.hanquez@eu.citrix.com>
4 * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
5 * Author Gianni Tedesco <gianni.tedesco@citrix.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as published
9 * by the Free Software Foundation; version 2.1 only. with the special
10 * exception on linking described in file LICENSE.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
16 */
18 #include "libxl_osdeps.h"
20 #include <stdio.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <xenctrl.h>
26 #include <xc_dom.h>
27 #include <xenguest.h>
28 #include "libxl.h"
29 #include "libxl_utils.h"
30 #include "libxl_internal.h"
31 #include "flexarray.h"
33 void libxl_domain_config_destroy(libxl_domain_config *d_config)
34 {
35 int i;
37 for (i=0; i<d_config->num_disks; i++)
38 libxl_device_disk_destroy(&d_config->disks[i]);
39 free(d_config->disks);
41 for (i=0; i<d_config->num_vifs; i++)
42 libxl_device_nic_destroy(&d_config->vifs[i]);
43 free(d_config->vifs);
45 for (i=0; i<d_config->num_vif2s; i++)
46 libxl_device_net2_destroy(&d_config->vif2s[i]);
47 free(d_config->vif2s);
49 for (i=0; i<d_config->num_pcidevs; i++)
50 libxl_device_pci_destroy(&d_config->pcidevs[i]);
51 free(d_config->pcidevs);
53 for (i=0; i<d_config->num_vfbs; i++)
54 libxl_device_vfb_destroy(&d_config->vfbs[i]);
55 free(d_config->vfbs);
57 for (i=0; i<d_config->num_vkbs; i++)
58 libxl_device_vkb_destroy(&d_config->vkbs[i]);
59 free(d_config->vkbs);
61 libxl_domain_create_info_destroy(&d_config->c_info);
62 libxl_domain_build_info_destroy(&d_config->b_info);
63 libxl_device_model_info_destroy(&d_config->dm_info);
64 }
66 void libxl_init_create_info(libxl_domain_create_info *c_info)
67 {
68 memset(c_info, '\0', sizeof(*c_info));
69 c_info->xsdata = NULL;
70 c_info->platformdata = NULL;
71 c_info->hap = 1;
72 c_info->hvm = 1;
73 c_info->oos = 1;
74 c_info->ssidref = 0;
75 c_info->poolid = 0;
76 }
78 void libxl_init_build_info(libxl_domain_build_info *b_info, libxl_domain_create_info *c_info)
79 {
80 memset(b_info, '\0', sizeof(*b_info));
81 b_info->max_vcpus = 1;
82 b_info->cur_vcpus = 1;
83 b_info->max_memkb = 32 * 1024;
84 b_info->target_memkb = b_info->max_memkb;
85 b_info->disable_migrate = 0;
86 b_info->cpuid = NULL;
87 b_info->shadow_memkb = 0;
88 if (c_info->hvm) {
89 b_info->video_memkb = 8 * 1024;
90 b_info->kernel.path = strdup("hvmloader");
91 b_info->hvm = 1;
92 b_info->u.hvm.pae = 1;
93 b_info->u.hvm.apic = 1;
94 b_info->u.hvm.acpi = 1;
95 b_info->u.hvm.nx = 1;
96 b_info->u.hvm.viridian = 0;
97 b_info->u.hvm.hpet = 1;
98 b_info->u.hvm.vpt_align = 1;
99 b_info->u.hvm.timer_mode = 1;
100 } else {
101 b_info->u.pv.slack_memkb = 8 * 1024;
102 }
103 }
105 void libxl_init_dm_info(libxl_device_model_info *dm_info,
106 libxl_domain_create_info *c_info, libxl_domain_build_info *b_info)
107 {
108 memset(dm_info, '\0', sizeof(*dm_info));
110 libxl_uuid_generate(&dm_info->uuid);
112 dm_info->dom_name = strdup(c_info->name);
113 dm_info->device_model = strdup("qemu-dm");
114 dm_info->target_ram = libxl__sizekb_to_mb(b_info->target_memkb);
115 dm_info->videoram = libxl__sizekb_to_mb(b_info->video_memkb);
116 dm_info->apic = b_info->u.hvm.apic;
117 dm_info->vcpus = b_info->max_vcpus;
118 dm_info->vcpu_avail = b_info->cur_vcpus;
120 dm_info->stdvga = 0;
121 dm_info->vnc = 1;
122 dm_info->vnclisten = strdup("127.0.0.1");
123 dm_info->vncdisplay = 0;
124 dm_info->vncunused = 1;
125 dm_info->keymap = NULL;
126 dm_info->sdl = 0;
127 dm_info->opengl = 0;
128 dm_info->nographic = 0;
129 dm_info->serial = NULL;
130 dm_info->boot = strdup("cda");
131 dm_info->usb = 0;
132 dm_info->usbdevice = NULL;
133 dm_info->xen_platform_pci = 1;
134 }
136 static int init_console_info(libxl_device_console *console, int dev_num, libxl_domain_build_state *state)
137 {
138 memset(console, 0x00, sizeof(libxl_device_console));
139 console->devid = dev_num;
140 console->consback = LIBXL_CONSBACK_XENCONSOLED;
141 console->output = strdup("pty");
142 if ( NULL == console->output )
143 return ERROR_NOMEM;
144 if (state)
145 console->build_state = state;
146 return 0;
147 }
149 int libxl__domain_build(libxl_ctx *ctx, libxl_domain_build_info *info, uint32_t domid, libxl_domain_build_state *state)
150 {
151 libxl__gc gc = LIBXL_INIT_GC(ctx);
152 char **vments = NULL, **localents = NULL;
153 struct timeval start_time;
154 int i, ret;
156 ret = libxl__build_pre(ctx, domid, info, state);
157 if (ret)
158 goto out;
160 gettimeofday(&start_time, NULL);
162 if (info->hvm) {
163 ret = libxl__build_hvm(ctx, domid, info, state);
164 if (ret)
165 goto out;
167 vments = libxl__calloc(&gc, 7, sizeof(char *));
168 vments[0] = "rtc/timeoffset";
169 vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
170 vments[2] = "image/ostype";
171 vments[3] = "hvm";
172 vments[4] = "start_time";
173 vments[5] = libxl__sprintf(&gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
174 } else {
175 ret = libxl__build_pv(ctx, domid, info, state);
176 if (ret)
177 goto out;
179 vments = libxl__calloc(&gc, 11, sizeof(char *));
180 i = 0;
181 vments[i++] = "image/ostype";
182 vments[i++] = "linux";
183 vments[i++] = "image/kernel";
184 vments[i++] = (char*) info->kernel.path;
185 vments[i++] = "start_time";
186 vments[i++] = libxl__sprintf(&gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
187 if (info->u.pv.ramdisk.path) {
188 vments[i++] = "image/ramdisk";
189 vments[i++] = (char*) info->u.pv.ramdisk.path;
190 }
191 if (info->u.pv.cmdline) {
192 vments[i++] = "image/cmdline";
193 vments[i++] = (char*) info->u.pv.cmdline;
194 }
195 }
196 ret = libxl__build_post(ctx, domid, info, state, vments, localents);
197 out:
198 libxl__file_reference_unmap(&info->kernel);
199 if (!info->hvm)
200 libxl__file_reference_unmap(&info->u.pv.ramdisk);
202 libxl__free_all(&gc);
203 return ret;
204 }
206 static int domain_restore(libxl_ctx *ctx, libxl_domain_build_info *info,
207 uint32_t domid, int fd, libxl_domain_build_state *state,
208 libxl_device_model_info *dm_info)
209 {
210 libxl__gc gc = LIBXL_INIT_GC(ctx);
211 char **vments = NULL, **localents = NULL;
212 struct timeval start_time;
213 int i, ret, esave, flags;
215 ret = libxl__build_pre(ctx, domid, info, state);
216 if (ret)
217 goto out;
219 ret = libxl__domain_restore_common(ctx, domid, info, state, fd);
220 if (ret)
221 goto out;
223 gettimeofday(&start_time, NULL);
225 if (info->hvm) {
226 vments = libxl__calloc(&gc, 7, sizeof(char *));
227 vments[0] = "rtc/timeoffset";
228 vments[1] = (info->u.hvm.timeoffset) ? info->u.hvm.timeoffset : "";
229 vments[2] = "image/ostype";
230 vments[3] = "hvm";
231 vments[4] = "start_time";
232 vments[5] = libxl__sprintf(&gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
233 } else {
234 vments = libxl__calloc(&gc, 11, sizeof(char *));
235 i = 0;
236 vments[i++] = "image/ostype";
237 vments[i++] = "linux";
238 vments[i++] = "image/kernel";
239 vments[i++] = (char*) info->kernel.path;
240 vments[i++] = "start_time";
241 vments[i++] = libxl__sprintf(&gc, "%lu.%02d", start_time.tv_sec,(int)start_time.tv_usec/10000);
242 if (info->u.pv.ramdisk.path) {
243 vments[i++] = "image/ramdisk";
244 vments[i++] = (char*) info->u.pv.ramdisk.path;
245 }
246 if (info->u.pv.cmdline) {
247 vments[i++] = "image/cmdline";
248 vments[i++] = (char*) info->u.pv.cmdline;
249 }
250 }
251 ret = libxl__build_post(ctx, domid, info, state, vments, localents);
252 if (ret)
253 goto out;
255 dm_info->saved_state = NULL;
256 if (info->hvm) {
257 ret = asprintf(&dm_info->saved_state,
258 XC_DEVICE_MODEL_RESTORE_FILE".%d", domid);
259 ret = (ret < 0) ? ERROR_FAIL : 0;
260 }
262 out:
263 libxl__file_reference_unmap(&info->kernel);
264 if (!info->hvm)
265 libxl__file_reference_unmap(&info->u.pv.ramdisk);
267 esave = errno;
269 flags = fcntl(fd, F_GETFL);
270 if (flags == -1) {
271 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to get flags on restore fd");
272 } else {
273 flags &= ~O_NONBLOCK;
274 if (fcntl(fd, F_SETFL, flags) == -1)
275 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unable to put restore fd"
276 " back to blocking mode");
277 }
279 errno = esave;
280 libxl__free_all(&gc);
281 return ret;
282 }
284 int libxl__domain_make(libxl_ctx *ctx, libxl_domain_create_info *info,
285 uint32_t *domid)
286 {
287 libxl__gc gc = LIBXL_INIT_GC(ctx);
288 int flags, ret, i, rc;
289 char *uuid_string;
290 char *rw_paths[] = { "device", "device/suspend/event-channel" , "data"};
291 char *ro_paths[] = { "cpu", "memory", "device", "error", "drivers",
292 "control", "attr", "messages" };
293 char *dom_path, *vm_path;
294 struct xs_permissions roperm[2];
295 struct xs_permissions rwperm[1];
296 xs_transaction_t t;
297 xen_domain_handle_t handle;
299 uuid_string = libxl__uuid2string(&gc, info->uuid);
300 if (!uuid_string) {
301 libxl__free_all(&gc);
302 return ERROR_NOMEM;
303 }
305 flags = info->hvm ? XEN_DOMCTL_CDF_hvm_guest : 0;
306 flags |= info->hap ? XEN_DOMCTL_CDF_hap : 0;
307 flags |= info->oos ? 0 : XEN_DOMCTL_CDF_oos_off;
308 *domid = -1;
310 /* Ultimately, handle is an array of 16 uint8_t, same as uuid */
311 libxl_uuid_copy((libxl_uuid *)handle, &info->uuid);
313 ret = xc_domain_create(ctx->xch, info->ssidref, handle, flags, domid);
314 if (ret < 0) {
315 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain creation fail");
316 libxl__free_all(&gc);
317 return ERROR_FAIL;
318 }
320 ret = xc_cpupool_movedomain(ctx->xch, info->poolid, *domid);
321 if (ret < 0) {
322 LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain move fail");
323 libxl__free_all(&gc);
324 return ERROR_FAIL;
325 }
327 dom_path = libxl__xs_get_dompath(&gc, *domid);
328 if (!dom_path) {
329 libxl__free_all(&gc);
330 return ERROR_FAIL;
331 }
333 vm_path = libxl__sprintf(&gc, "/vm/%s", uuid_string);
334 if (!vm_path) {
335 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot allocate create paths");
336 libxl__free_all(&gc);
337 return ERROR_FAIL;
338 }
340 roperm[0].id = 0;
341 roperm[0].perms = XS_PERM_NONE;
342 roperm[1].id = *domid;
343 roperm[1].perms = XS_PERM_READ;
344 rwperm[0].id = *domid;
345 rwperm[0].perms = XS_PERM_NONE;
347 retry_transaction:
348 t = xs_transaction_start(ctx->xsh);
349 xs_rm(ctx->xsh, t, dom_path);
350 xs_mkdir(ctx->xsh, t, dom_path);
351 xs_set_permissions(ctx->xsh, t, dom_path, roperm, ARRAY_SIZE(roperm));
353 xs_rm(ctx->xsh, t, vm_path);
354 xs_mkdir(ctx->xsh, t, vm_path);
355 xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));
357 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/vm", dom_path), vm_path, strlen(vm_path));
358 rc = libxl_domain_rename(ctx, *domid, 0, info->name, t);
359 if (rc) {
360 libxl__free_all(&gc);
361 return rc;
362 }
364 for (i = 0; i < ARRAY_SIZE(rw_paths); i++) {
365 char *path = libxl__sprintf(&gc, "%s/%s", dom_path, rw_paths[i]);
366 xs_mkdir(ctx->xsh, t, path);
367 xs_set_permissions(ctx->xsh, t, path, rwperm, ARRAY_SIZE(rwperm));
368 }
369 for (i = 0; i < ARRAY_SIZE(ro_paths); i++) {
370 char *path = libxl__sprintf(&gc, "%s/%s", dom_path, ro_paths[i]);
371 xs_mkdir(ctx->xsh, t, path);
372 xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm));
373 }
375 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string));
376 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/name", vm_path), info->name, strlen(info->name));
377 if (info->poolname)
378 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/pool_name", vm_path), info->poolname, strlen(info->poolname));
380 libxl__xs_writev(&gc, t, dom_path, info->xsdata);
381 libxl__xs_writev(&gc, t, libxl__sprintf(&gc, "%s/platform", dom_path), info->platformdata);
383 xs_write(ctx->xsh, t, libxl__sprintf(&gc, "%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1);
384 if (!xs_transaction_end(ctx->xsh, t, 0))
385 if (errno == EAGAIN)
386 goto retry_transaction;
388 libxl__free_all(&gc);
389 return 0;
390 }
392 static int do_domain_create(libxl_ctx *ctx, libxl_domain_config *d_config,
393 libxl_console_ready cb, void *priv,
394 uint32_t *domid_out, int restore_fd)
395 {
396 libxl__device_model_starting *dm_starting = 0;
397 libxl_device_model_info *dm_info = &d_config->dm_info;
398 libxl_domain_build_state state;
399 uint32_t domid;
400 int i, ret;
402 domid = 0;
404 ret = libxl__domain_make(ctx, &d_config->c_info, &domid);
405 if (ret) {
406 fprintf(stderr, "cannot make domain: %d\n", ret);
407 ret = ERROR_FAIL;
408 goto error_out;
409 }
411 if ( !d_config->c_info.hvm && cb ) {
412 if ( (*cb)(ctx, domid, priv) )
413 goto error_out;
414 }
416 if ( restore_fd < 0 ) {
417 ret = libxl_run_bootloader(ctx, &d_config->b_info, d_config->num_disks > 0 ? &d_config->disks[0] : NULL, domid);
418 if (ret) {
419 fprintf(stderr, "failed to run bootloader: %d\n", ret);
420 goto error_out;
421 }
422 }
424 if ( restore_fd >= 0 ) {
425 ret = domain_restore(ctx, &d_config->b_info, domid, restore_fd, &state, dm_info);
426 } else {
427 if (dm_info->saved_state) {
428 free(dm_info->saved_state);
429 dm_info->saved_state = NULL;
430 }
431 ret = libxl__domain_build(ctx, &d_config->b_info, domid, &state);
432 }
434 if (ret) {
435 fprintf(stderr, "cannot (re-)build domain: %d\n", ret);
436 ret = ERROR_FAIL;
437 goto error_out;
438 }
440 for (i = 0; i < d_config->num_disks; i++) {
441 d_config->disks[i].domid = domid;
442 ret = libxl_device_disk_add(ctx, domid, &d_config->disks[i]);
443 if (ret) {
444 fprintf(stderr, "cannot add disk %d to domain: %d\n", i, ret);
445 ret = ERROR_FAIL;
446 goto error_out;
447 }
448 }
449 for (i = 0; i < d_config->num_vifs; i++) {
450 d_config->vifs[i].domid = domid;
451 ret = libxl_device_nic_add(ctx, domid, &d_config->vifs[i]);
452 if (ret) {
453 fprintf(stderr, "cannot add nic %d to domain: %d\n", i, ret);
454 ret = ERROR_FAIL;
455 goto error_out;
456 }
457 }
458 if (!d_config->c_info.hvm) {
459 for (i = 0; i < d_config->num_vif2s; i++) {
460 d_config->vif2s[i].domid = domid;
461 ret = libxl_device_net2_add(ctx, domid, &d_config->vif2s[i]);
462 if (ret) {
463 fprintf(stderr, "cannot add net2 %d to domain: %d\n", i, ret);
464 ret = ERROR_FAIL;
465 goto error_out;
466 }
467 }
468 }
469 if (d_config->c_info.hvm) {
470 libxl_device_console console;
472 ret = init_console_info(&console, 0, &state);
473 if ( ret )
474 goto error_out;
475 console.domid = domid;
476 libxl_device_console_add(ctx, domid, &console);
477 libxl_device_console_destroy(&console);
479 dm_info->domid = domid;
480 ret = libxl__create_device_model(ctx, dm_info,
481 d_config->disks, d_config->num_disks,
482 d_config->vifs, d_config->num_vifs,
483 &dm_starting);
484 if (ret < 0) {
485 fprintf(stderr,"xl: fatal error: %s:%d, rc=%d: libxl__create_device_model\n",
486 __FILE__,__LINE__, ret);
487 goto error_out;
488 }
489 } else {
490 int need_qemu = 0;
491 libxl_device_console console;
493 for (i = 0; i < d_config->num_vfbs; i++) {
494 d_config->vfbs[i].domid = domid;
495 libxl_device_vfb_add(ctx, domid, &d_config->vfbs[i]);
496 d_config->vkbs[i].domid = domid;
497 libxl_device_vkb_add(ctx, domid, &d_config->vkbs[i]);
498 }
500 ret = init_console_info(&console, 0, &state);
501 if ( ret )
502 goto error_out;
503 console.domid = domid;
505 need_qemu = libxl__need_xenpv_qemu(ctx, 1, &console,
506 d_config->num_vfbs, d_config->vfbs,
507 d_config->num_disks, &d_config->disks[0]);
509 if (need_qemu)
510 console.consback = LIBXL_CONSBACK_IOEMU;
512 libxl_device_console_add(ctx, domid, &console);
513 libxl_device_console_destroy(&console);
515 if (need_qemu)
516 libxl__create_xenpv_qemu(ctx, domid, d_config->vfbs, &dm_starting);
517 }
519 if (dm_starting) {
520 ret = libxl__confirm_device_model_startup(ctx, dm_starting);
521 if (ret < 0) {
522 fprintf(stderr,"xl: fatal error: %s:%d, rc=%d: libxl__confirm_device_model_startup\n",
523 __FILE__,__LINE__, ret);
524 goto error_out;
525 }
526 }
528 for (i = 0; i < d_config->num_pcidevs; i++)
529 libxl_device_pci_add(ctx, domid, &d_config->pcidevs[i]);
531 if ( d_config->c_info.hvm && cb ) {
532 if ( (*cb)(ctx, domid, priv) )
533 goto error_out;
534 }
536 *domid_out = domid;
537 return 0;
539 error_out:
540 if (domid)
541 libxl_domain_destroy(ctx, domid, 0);
543 return ret;
544 }
545 int libxl_domain_create_new(libxl_ctx *ctx, libxl_domain_config *d_config,
546 libxl_console_ready cb, void *priv, uint32_t *domid)
547 {
548 return do_domain_create(ctx, d_config, cb, priv, domid, -1);
549 }
551 int libxl_domain_create_restore(libxl_ctx *ctx, libxl_domain_config *d_config,
552 libxl_console_ready cb, void *priv, uint32_t *domid, int restore_fd)
553 {
554 return do_domain_create(ctx, d_config, cb, priv, domid, restore_fd);
555 }