1 /*
2 * Copyright 2009-2017 Citrix Ltd and other contributors
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; version 2.1 only. with the special
7 * exception on linking described in file LICENSE.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 */
14
15 #include "libxl_osdeps.h"
16
17 #include "libxl_internal.h"
18
19 #define PAGE_TO_MEMKB(pages) ((pages) * 4)
20
libxl__domain_rename(libxl__gc * gc,uint32_t domid,const char * old_name,const char * new_name,xs_transaction_t trans)21 int libxl__domain_rename(libxl__gc *gc, uint32_t domid,
22 const char *old_name, const char *new_name,
23 xs_transaction_t trans)
24 {
25 libxl_ctx *ctx = libxl__gc_owner(gc);
26 char *dom_path = 0;
27 const char *name_path;
28 char *got_old_name;
29 unsigned int got_old_len;
30 xs_transaction_t our_trans = 0;
31 uint32_t stub_dm_domid;
32 const char *stub_dm_old_name = NULL, *stub_dm_new_name = NULL;
33 int rc;
34 libxl_dominfo info;
35 char *uuid;
36 const char *vm_name_path;
37
38 libxl_dominfo_init(&info);
39
40 dom_path = libxl__xs_get_dompath(gc, domid);
41 if (!dom_path) goto x_nomem;
42
43 name_path= GCSPRINTF("%s/name", dom_path);
44 if (!name_path) goto x_nomem;
45
46 stub_dm_domid = libxl_get_stubdom_id(CTX, domid);
47 if (stub_dm_domid) {
48 stub_dm_old_name = libxl__stub_dm_name(gc, old_name);
49 stub_dm_new_name = libxl__stub_dm_name(gc, new_name);
50 }
51
52 retry_transaction:
53 if (!trans) {
54 trans = our_trans = xs_transaction_start(ctx->xsh);
55 if (!our_trans) {
56 LOGEVD(ERROR, errno, domid, "Create xs transaction for domain (re)name");
57 goto x_fail;
58 }
59 }
60
61 if (!new_name) {
62 LOGD(ERROR, domid, "New domain name not specified");
63 rc = ERROR_INVAL;
64 goto x_rc;
65 }
66
67 if (new_name[0]) {
68 /* nonempty names must be unique */
69 uint32_t domid_e;
70 rc = libxl_name_to_domid(ctx, new_name, &domid_e);
71 if (rc == ERROR_INVAL) {
72 /* no such domain, good */
73 } else if (rc != 0) {
74 LOGD(ERROR, domid, "Unexpected error checking for existing domain");
75 goto x_rc;
76 } else if (domid_e == domid) {
77 /* domain already has this name, ok (but we do still
78 * need the rest of the code as we may need to check
79 * old_name, for example). */
80 } else {
81 LOGD(ERROR, domid, "Domain with name \"%s\" already exists.", new_name);
82 rc = ERROR_INVAL;
83 goto x_rc;
84 }
85 }
86
87 if (old_name) {
88 got_old_name = xs_read(ctx->xsh, trans, name_path, &got_old_len);
89 if (!got_old_name) {
90 LOGEVD(ERROR, errno, domid,
91 "Check old name for domain allegedly named `%s'",
92 old_name);
93 goto x_fail;
94 }
95 if (strcmp(old_name, got_old_name)) {
96 LOGD(ERROR, domid,
97 "Allegedly named `%s' is actually named `%s' - racing ?",
98 old_name,
99 got_old_name);
100 free(got_old_name);
101 goto x_fail;
102 }
103 free(got_old_name);
104 }
105 if (!xs_write(ctx->xsh, trans, name_path,
106 new_name, strlen(new_name))) {
107 LOGD(ERROR, domid,
108 "Failed to write new name `%s'"
109 " for domain previously named `%s'",
110 new_name,
111 old_name);
112 goto x_fail;
113 }
114
115 /* update /vm/<uuid>/name */
116 rc = libxl_domain_info(ctx, &info, domid);
117 if (rc)
118 goto x_rc;
119
120 uuid = GCSPRINTF(LIBXL_UUID_FMT, LIBXL_UUID_BYTES(info.uuid));
121 vm_name_path = GCSPRINTF("/vm/%s/name", uuid);
122 if (libxl__xs_write_checked(gc, trans, vm_name_path, new_name))
123 goto x_fail;
124
125 if (stub_dm_domid) {
126 rc = libxl__domain_rename(gc, stub_dm_domid,
127 stub_dm_old_name,
128 stub_dm_new_name,
129 trans);
130 if (rc) {
131 LOGED(ERROR, domid, "Unable to rename stub-domain");
132 goto x_rc;
133 }
134 }
135
136 if (our_trans) {
137 if (!xs_transaction_end(ctx->xsh, our_trans, 0)) {
138 trans = our_trans = 0;
139 if (errno != EAGAIN) {
140 LOGD(ERROR, domid,
141 "Failed to commit new name `%s'"
142 " for domain previously named `%s'",
143 new_name,
144 old_name);
145 goto x_fail;
146 }
147 LOGD(DEBUG, domid,
148 "Need to retry rename transaction"
149 " for domain (name_path=\"%s\", new_name=\"%s\")",
150 name_path,
151 new_name);
152 goto retry_transaction;
153 }
154 our_trans = 0;
155 }
156
157 rc = 0;
158 x_rc:
159 if (our_trans) xs_transaction_end(ctx->xsh, our_trans, 1);
160 libxl_dominfo_dispose(&info);
161 return rc;
162
163 x_fail: rc = ERROR_FAIL; goto x_rc;
164 x_nomem: rc = ERROR_NOMEM; goto x_rc;
165 }
166
libxl_domain_rename(libxl_ctx * ctx,uint32_t domid,const char * old_name,const char * new_name)167 int libxl_domain_rename(libxl_ctx *ctx, uint32_t domid,
168 const char *old_name, const char *new_name)
169 {
170 GC_INIT(ctx);
171 int rc;
172 rc = libxl__domain_rename(gc, domid, old_name, new_name, XBT_NULL);
173 GC_FREE;
174 return rc;
175 }
176
libxl_domain_resume(libxl_ctx * ctx,uint32_t domid,int suspend_cancel,const libxl_asyncop_how * ao_how)177 int libxl_domain_resume(libxl_ctx *ctx, uint32_t domid, int suspend_cancel,
178 const libxl_asyncop_how *ao_how)
179 {
180 AO_CREATE(ctx, domid, ao_how);
181 int rc = libxl__domain_resume(gc, domid, suspend_cancel);
182 libxl__ao_complete(egc, ao, rc);
183 return AO_INPROGRESS;
184 }
185
186 /*
187 * Preserves a domain but rewrites xenstore etc to make it unique so
188 * that the domain can be restarted.
189 *
190 * Does not modify info so that it may be reused.
191 */
libxl_domain_preserve(libxl_ctx * ctx,uint32_t domid,libxl_domain_create_info * info,const char * name_suffix,libxl_uuid new_uuid)192 int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid,
193 libxl_domain_create_info *info, const char *name_suffix, libxl_uuid new_uuid)
194 {
195 GC_INIT(ctx);
196 struct xs_permissions roperm[2];
197 xs_transaction_t t;
198 char *preserved_name;
199 char *uuid_string;
200 char *vm_path;
201 char *dom_path;
202
203 int rc;
204
205 preserved_name = GCSPRINTF("%s%s", info->name, name_suffix);
206 if (!preserved_name) {
207 GC_FREE;
208 return ERROR_NOMEM;
209 }
210
211 uuid_string = libxl__uuid2string(gc, new_uuid);
212 if (!uuid_string) {
213 GC_FREE;
214 return ERROR_NOMEM;
215 }
216
217 dom_path = libxl__xs_get_dompath(gc, domid);
218 if (!dom_path) {
219 GC_FREE;
220 return ERROR_FAIL;
221 }
222
223 vm_path = GCSPRINTF("/vm/%s", uuid_string);
224 if (!vm_path) {
225 GC_FREE;
226 return ERROR_FAIL;
227 }
228
229 roperm[0].id = 0;
230 roperm[0].perms = XS_PERM_NONE;
231 roperm[1].id = domid;
232 roperm[1].perms = XS_PERM_READ;
233
234 retry_transaction:
235 t = xs_transaction_start(ctx->xsh);
236
237 xs_rm(ctx->xsh, t, vm_path);
238 xs_mkdir(ctx->xsh, t, vm_path);
239 xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm));
240
241 xs_write(ctx->xsh, t, GCSPRINTF("%s/vm", dom_path), vm_path, strlen(vm_path));
242 rc = libxl__domain_rename(gc, domid, info->name, preserved_name, t);
243 if (rc) {
244 GC_FREE;
245 return rc;
246 }
247
248 xs_write(ctx->xsh, t, GCSPRINTF("%s/uuid", vm_path), uuid_string, strlen(uuid_string));
249
250 if (!xs_transaction_end(ctx->xsh, t, 0))
251 if (errno == EAGAIN)
252 goto retry_transaction;
253
254 GC_FREE;
255 return 0;
256 }
257
libxl__xcinfo2xlinfo(libxl_ctx * ctx,const xc_domaininfo_t * xcinfo,libxl_dominfo * xlinfo)258 void libxl__xcinfo2xlinfo(libxl_ctx *ctx,
259 const xc_domaininfo_t *xcinfo,
260 libxl_dominfo *xlinfo)
261 {
262 size_t size;
263
264 memcpy(&(xlinfo->uuid), xcinfo->handle, sizeof(xen_domain_handle_t));
265 xlinfo->domid = xcinfo->domain;
266 xlinfo->ssidref = xcinfo->ssidref;
267 if (libxl_flask_sid_to_context(ctx, xlinfo->ssidref,
268 &xlinfo->ssid_label, &size) < 0)
269 xlinfo->ssid_label = NULL;
270
271 xlinfo->dying = !!(xcinfo->flags&XEN_DOMINF_dying);
272 xlinfo->shutdown = !!(xcinfo->flags&XEN_DOMINF_shutdown);
273 xlinfo->paused = !!(xcinfo->flags&XEN_DOMINF_paused);
274 xlinfo->blocked = !!(xcinfo->flags&XEN_DOMINF_blocked);
275 xlinfo->running = !!(xcinfo->flags&XEN_DOMINF_running);
276 xlinfo->never_stop = !!(xcinfo->flags&XEN_DOMINF_xs_domain);
277
278 if (xlinfo->shutdown)
279 xlinfo->shutdown_reason = (xcinfo->flags>>XEN_DOMINF_shutdownshift) & XEN_DOMINF_shutdownmask;
280 else
281 xlinfo->shutdown_reason = LIBXL_SHUTDOWN_REASON_UNKNOWN;
282
283 xlinfo->outstanding_memkb = PAGE_TO_MEMKB(xcinfo->outstanding_pages);
284 xlinfo->current_memkb = PAGE_TO_MEMKB(xcinfo->tot_pages);
285 xlinfo->shared_memkb = PAGE_TO_MEMKB(xcinfo->shr_pages);
286 xlinfo->paged_memkb = PAGE_TO_MEMKB(xcinfo->paged_pages);
287 xlinfo->max_memkb = PAGE_TO_MEMKB(xcinfo->max_pages);
288 xlinfo->cpu_time = xcinfo->cpu_time;
289 xlinfo->vcpu_max_id = xcinfo->max_vcpu_id;
290 xlinfo->vcpu_online = xcinfo->nr_online_vcpus;
291 xlinfo->cpupool = xcinfo->cpupool;
292 xlinfo->domain_type = (xcinfo->flags & XEN_DOMINF_hvm_guest) ?
293 LIBXL_DOMAIN_TYPE_HVM : LIBXL_DOMAIN_TYPE_PV;
294 }
295
libxl_list_domain(libxl_ctx * ctx,int * nb_domain_out)296 libxl_dominfo * libxl_list_domain(libxl_ctx *ctx, int *nb_domain_out)
297 {
298 libxl_dominfo *ptr = NULL;
299 int i, ret;
300 xc_domaininfo_t info[1024];
301 int size = 0;
302 uint32_t domid = 0;
303 GC_INIT(ctx);
304
305 while ((ret = xc_domain_getinfolist(ctx->xch, domid, 1024, info)) > 0) {
306 ptr = libxl__realloc(NOGC, ptr, (size + ret) * sizeof(libxl_dominfo));
307 for (i = 0; i < ret; i++) {
308 libxl__xcinfo2xlinfo(ctx, &info[i], &ptr[size + i]);
309 }
310 domid = info[ret - 1].domain + 1;
311 size += ret;
312 }
313
314 if (ret < 0) {
315 LOGE(ERROR, "getting domain info list");
316 free(ptr);
317 GC_FREE;
318 return NULL;
319 }
320
321 *nb_domain_out = size;
322 GC_FREE;
323 return ptr;
324 }
325
libxl_domain_info(libxl_ctx * ctx,libxl_dominfo * info_r,uint32_t domid)326 int libxl_domain_info(libxl_ctx *ctx, libxl_dominfo *info_r,
327 uint32_t domid) {
328 xc_domaininfo_t xcinfo;
329 int ret;
330 GC_INIT(ctx);
331
332 ret = xc_domain_getinfolist(ctx->xch, domid, 1, &xcinfo);
333 if (ret<0) {
334 LOGED(ERROR, domid, "Getting domain info list");
335 GC_FREE;
336 return ERROR_FAIL;
337 }
338 if (ret==0 || xcinfo.domain != domid) {
339 GC_FREE;
340 return ERROR_DOMAIN_NOTFOUND;
341 }
342
343 if (info_r)
344 libxl__xcinfo2xlinfo(ctx, &xcinfo, info_r);
345 GC_FREE;
346 return 0;
347 }
348
349 /* this API call only list VM running on this host. A VM can
350 * be an aggregate of multiple domains. */
libxl_list_vm(libxl_ctx * ctx,int * nb_vm_out)351 libxl_vminfo * libxl_list_vm(libxl_ctx *ctx, int *nb_vm_out)
352 {
353 GC_INIT(ctx);
354 libxl_dominfo *info;
355 libxl_vminfo *ptr = NULL;
356 int idx, i, n_doms;
357
358 info = libxl_list_domain(ctx, &n_doms);
359 if (!info)
360 goto out;
361
362 /*
363 * Always make sure to allocate at least one element; if we don't and we
364 * request zero, libxl__calloc (might) think its internal call to calloc
365 * has failed (if it returns null), if so it would kill our process.
366 */
367 ptr = libxl__calloc(NOGC, n_doms ? n_doms : 1, sizeof(libxl_vminfo));
368
369 for (idx = i = 0; i < n_doms; i++) {
370 if (libxl_is_stubdom(ctx, info[i].domid, NULL))
371 continue;
372 ptr[idx].uuid = info[i].uuid;
373 ptr[idx].domid = info[i].domid;
374
375 idx++;
376 }
377 *nb_vm_out = idx;
378 libxl_dominfo_list_free(info, n_doms);
379
380 out:
381 GC_FREE;
382 return ptr;
383 }
384
385 static void remus_failover_cb(libxl__egc *egc,
386 libxl__domain_save_state *dss, int rc);
387
libxl_domain_remus_start(libxl_ctx * ctx,libxl_domain_remus_info * info,uint32_t domid,int send_fd,int recv_fd,const libxl_asyncop_how * ao_how)388 int libxl_domain_remus_start(libxl_ctx *ctx, libxl_domain_remus_info *info,
389 uint32_t domid, int send_fd, int recv_fd,
390 const libxl_asyncop_how *ao_how)
391 {
392 AO_CREATE(ctx, domid, ao_how);
393 libxl__domain_save_state *dss;
394 int rc;
395
396 libxl_domain_type type = libxl__domain_type(gc, domid);
397 if (type == LIBXL_DOMAIN_TYPE_INVALID) {
398 rc = ERROR_FAIL;
399 goto out;
400 }
401
402 /* The caller must set this defbool */
403 if (libxl_defbool_is_default(info->colo)) {
404 LOGD(ERROR, domid, "Colo mode must be enabled/disabled");
405 rc = ERROR_FAIL;
406 goto out;
407 }
408
409 libxl_defbool_setdefault(&info->allow_unsafe, false);
410 libxl_defbool_setdefault(&info->blackhole, false);
411 libxl_defbool_setdefault(&info->compression,
412 !libxl_defbool_val(info->colo));
413 libxl_defbool_setdefault(&info->netbuf, true);
414 libxl_defbool_setdefault(&info->diskbuf, true);
415
416 if (libxl_defbool_val(info->colo) &&
417 libxl_defbool_val(info->compression)) {
418 LOGD(ERROR, domid, "Cannot use memory checkpoint "
419 "compression in COLO mode");
420 rc = ERROR_FAIL;
421 goto out;
422 }
423
424 if (!libxl_defbool_val(info->allow_unsafe) &&
425 (libxl_defbool_val(info->blackhole) ||
426 !libxl_defbool_val(info->netbuf) ||
427 !libxl_defbool_val(info->diskbuf))) {
428 LOGD(ERROR, domid, "Unsafe mode must be enabled to replicate to /dev/null,"
429 "disable network buffering and disk replication");
430 rc = ERROR_FAIL;
431 goto out;
432 }
433
434
435 GCNEW(dss);
436 dss->ao = ao;
437 dss->callback = remus_failover_cb;
438 dss->domid = domid;
439 dss->fd = send_fd;
440 dss->recv_fd = recv_fd;
441 dss->type = type;
442 dss->live = 1;
443 dss->debug = 0;
444 dss->remus = info;
445 if (libxl_defbool_val(info->colo))
446 dss->checkpointed_stream = LIBXL_CHECKPOINTED_STREAM_COLO;
447 else
448 dss->checkpointed_stream = LIBXL_CHECKPOINTED_STREAM_REMUS;
449
450 assert(info);
451
452 /* Point of no return */
453 if (libxl_defbool_val(info->colo))
454 libxl__colo_save_setup(egc, &dss->css);
455 else
456 libxl__remus_setup(egc, &dss->rs);
457 return AO_INPROGRESS;
458
459 out:
460 return AO_CREATE_FAIL(rc);
461 }
462
remus_failover_cb(libxl__egc * egc,libxl__domain_save_state * dss,int rc)463 static void remus_failover_cb(libxl__egc *egc,
464 libxl__domain_save_state *dss, int rc)
465 {
466 STATE_AO_GC(dss->ao);
467 /*
468 * With Remus, if we reach this point, it means either
469 * backup died or some network error occurred preventing us
470 * from sending checkpoints.
471 */
472 libxl__ao_complete(egc, ao, rc);
473 }
474
domain_suspend_cb(libxl__egc * egc,libxl__domain_save_state * dss,int rc)475 static void domain_suspend_cb(libxl__egc *egc,
476 libxl__domain_save_state *dss, int rc)
477 {
478 STATE_AO_GC(dss->ao);
479 int flrc;
480
481 flrc = libxl__fd_flags_restore(gc, dss->fd, dss->fdfl);
482 /* If suspend has failed already then report that error not this one. */
483 if (flrc && !rc) rc = flrc;
484
485 libxl__ao_complete(egc,ao,rc);
486
487 }
488
libxl_domain_suspend(libxl_ctx * ctx,uint32_t domid,int fd,int flags,const libxl_asyncop_how * ao_how)489 int libxl_domain_suspend(libxl_ctx *ctx, uint32_t domid, int fd, int flags,
490 const libxl_asyncop_how *ao_how)
491 {
492 AO_CREATE(ctx, domid, ao_how);
493 int rc;
494
495 libxl_domain_type type = libxl__domain_type(gc, domid);
496 if (type == LIBXL_DOMAIN_TYPE_INVALID) {
497 rc = ERROR_FAIL;
498 goto out_err;
499 }
500
501 libxl__domain_save_state *dss;
502 GCNEW(dss);
503
504 dss->ao = ao;
505 dss->callback = domain_suspend_cb;
506
507 dss->domid = domid;
508 dss->fd = fd;
509 dss->type = type;
510 dss->live = flags & LIBXL_SUSPEND_LIVE;
511 dss->debug = flags & LIBXL_SUSPEND_DEBUG;
512 dss->checkpointed_stream = LIBXL_CHECKPOINTED_STREAM_NONE;
513
514 rc = libxl__fd_flags_modify_save(gc, dss->fd,
515 ~(O_NONBLOCK|O_NDELAY), 0,
516 &dss->fdfl);
517 if (rc < 0) goto out_err;
518
519 libxl__domain_save(egc, dss);
520 return AO_INPROGRESS;
521
522 out_err:
523 return AO_CREATE_FAIL(rc);
524 }
525
libxl_domain_pause(libxl_ctx * ctx,uint32_t domid)526 int libxl_domain_pause(libxl_ctx *ctx, uint32_t domid)
527 {
528 int ret;
529 GC_INIT(ctx);
530 ret = xc_domain_pause(ctx->xch, domid);
531 if (ret<0) {
532 LOGED(ERROR, domid, "Pausing domain");
533 GC_FREE;
534 return ERROR_FAIL;
535 }
536 GC_FREE;
537 return 0;
538 }
539
libxl_domain_core_dump(libxl_ctx * ctx,uint32_t domid,const char * filename,const libxl_asyncop_how * ao_how)540 int libxl_domain_core_dump(libxl_ctx *ctx, uint32_t domid,
541 const char *filename,
542 const libxl_asyncop_how *ao_how)
543 {
544 AO_CREATE(ctx, domid, ao_how);
545 int ret, rc;
546
547 ret = xc_domain_dumpcore(ctx->xch, domid, filename);
548 if (ret<0) {
549 LOGED(ERROR, domid, "Core dumping domain to %s", filename);
550 rc = ERROR_FAIL;
551 goto out;
552 }
553
554 rc = 0;
555 out:
556
557 libxl__ao_complete(egc, ao, rc);
558
559 return AO_INPROGRESS;
560 }
561
libxl_domain_unpause(libxl_ctx * ctx,uint32_t domid)562 int libxl_domain_unpause(libxl_ctx *ctx, uint32_t domid)
563 {
564 GC_INIT(ctx);
565 int ret, rc = 0;
566
567 libxl_domain_type type = libxl__domain_type(gc, domid);
568 if (type == LIBXL_DOMAIN_TYPE_INVALID) {
569 rc = ERROR_FAIL;
570 goto out;
571 }
572
573 if (type == LIBXL_DOMAIN_TYPE_HVM) {
574 rc = libxl__domain_resume_device_model(gc, domid);
575 if (rc < 0) {
576 LOGD(ERROR, domid,
577 "Failed to unpause device model for domain: %d", rc);
578 goto out;
579 }
580 }
581 ret = xc_domain_unpause(ctx->xch, domid);
582 if (ret<0) {
583 LOGED(ERROR, domid, "Unpausing domain");
584 rc = ERROR_FAIL;
585 }
586 out:
587 GC_FREE;
588 return rc;
589 }
590
libxl__domain_pvcontrol_available(libxl__gc * gc,uint32_t domid)591 int libxl__domain_pvcontrol_available(libxl__gc *gc, uint32_t domid)
592 {
593 libxl_ctx *ctx = libxl__gc_owner(gc);
594
595 uint64_t pvdriver = 0;
596 int ret;
597
598 libxl_domain_type domtype = libxl__domain_type(gc, domid);
599 if (domtype == LIBXL_DOMAIN_TYPE_INVALID)
600 return ERROR_FAIL;
601
602 if (domtype == LIBXL_DOMAIN_TYPE_PV)
603 return 1;
604
605 ret = xc_hvm_param_get(ctx->xch, domid, HVM_PARAM_CALLBACK_IRQ, &pvdriver);
606 if (ret<0) {
607 LOGED(ERROR, domid, "Getting HVM callback IRQ");
608 return ERROR_FAIL;
609 }
610 return !!pvdriver;
611 }
612
libxl__domain_pvcontrol_xspath(libxl__gc * gc,uint32_t domid)613 const char *libxl__domain_pvcontrol_xspath(libxl__gc *gc, uint32_t domid)
614 {
615 const char *dom_path;
616
617 dom_path = libxl__xs_get_dompath(gc, domid);
618 if (!dom_path)
619 return NULL;
620
621 return GCSPRINTF("%s/control/shutdown", dom_path);
622 }
623
libxl__domain_pvcontrol_read(libxl__gc * gc,xs_transaction_t t,uint32_t domid)624 char * libxl__domain_pvcontrol_read(libxl__gc *gc, xs_transaction_t t,
625 uint32_t domid)
626 {
627 const char *shutdown_path;
628
629 shutdown_path = libxl__domain_pvcontrol_xspath(gc, domid);
630 if (!shutdown_path)
631 return NULL;
632
633 return libxl__xs_read(gc, t, shutdown_path);
634 }
635
libxl__domain_pvcontrol_write(libxl__gc * gc,xs_transaction_t t,uint32_t domid,const char * cmd)636 int libxl__domain_pvcontrol_write(libxl__gc *gc, xs_transaction_t t,
637 uint32_t domid, const char *cmd)
638 {
639 const char *shutdown_path;
640
641 shutdown_path = libxl__domain_pvcontrol_xspath(gc, domid);
642 if (!shutdown_path)
643 return ERROR_FAIL;
644
645 return libxl__xs_printf(gc, t, shutdown_path, "%s", cmd);
646 }
647
libxl__domain_pvcontrol(libxl__gc * gc,uint32_t domid,const char * cmd)648 static int libxl__domain_pvcontrol(libxl__gc *gc, uint32_t domid,
649 const char *cmd)
650 {
651 int ret;
652
653 ret = libxl__domain_pvcontrol_available(gc, domid);
654 if (ret < 0)
655 return ret;
656
657 if (!ret)
658 return ERROR_NOPARAVIRT;
659
660 return libxl__domain_pvcontrol_write(gc, XBT_NULL, domid, cmd);
661 }
662
libxl_domain_shutdown(libxl_ctx * ctx,uint32_t domid)663 int libxl_domain_shutdown(libxl_ctx *ctx, uint32_t domid)
664 {
665 GC_INIT(ctx);
666 int ret;
667 ret = libxl__domain_pvcontrol(gc, domid, "poweroff");
668 GC_FREE;
669 return ret;
670 }
671
libxl_domain_reboot(libxl_ctx * ctx,uint32_t domid)672 int libxl_domain_reboot(libxl_ctx *ctx, uint32_t domid)
673 {
674 GC_INIT(ctx);
675 int ret;
676 ret = libxl__domain_pvcontrol(gc, domid, "reboot");
677 GC_FREE;
678 return ret;
679 }
680
domain_death_occurred(libxl__egc * egc,libxl_evgen_domain_death ** evg_upd,const char * why)681 static void domain_death_occurred(libxl__egc *egc,
682 libxl_evgen_domain_death **evg_upd,
683 const char *why) {
684 /* Removes **evg_upd from death_list and puts it on death_reported
685 * and advances *evg_upd to the next entry.
686 * Call sites in domain_death_xswatch_callback must use "continue". */
687 EGC_GC;
688 libxl_evgen_domain_death *const evg = *evg_upd;
689
690 LOGD(DEBUG, evg->domid, "%s", why);
691
692 libxl_evgen_domain_death *evg_next = LIBXL_TAILQ_NEXT(evg, entry);
693 *evg_upd = evg_next;
694
695 libxl_event *ev = NEW_EVENT(egc, DOMAIN_DEATH, evg->domid, evg->user);
696
697 libxl__event_occurred(egc, ev);
698
699 evg->death_reported = 1;
700 LIBXL_TAILQ_REMOVE(&CTX->death_list, evg, entry);
701 LIBXL_TAILQ_INSERT_HEAD(&CTX->death_reported, evg, entry);
702 }
703
domain_death_xswatch_callback(libxl__egc * egc,libxl__ev_xswatch * w,const char * wpath,const char * epath)704 static void domain_death_xswatch_callback(libxl__egc *egc, libxl__ev_xswatch *w,
705 const char *wpath, const char *epath) {
706 EGC_GC;
707 libxl_evgen_domain_death *evg;
708 int rc;
709
710 CTX_LOCK;
711
712 evg = LIBXL_TAILQ_FIRST(&CTX->death_list);
713
714 for (;;) {
715 if (!evg) goto out;
716
717 int nentries = LIBXL_TAILQ_NEXT(evg, entry) ? 200 : 1;
718 xc_domaininfo_t domaininfos[nentries];
719 const xc_domaininfo_t *got = domaininfos, *gotend;
720
721 rc = xc_domain_getinfolist(CTX->xch, evg->domid, nentries, domaininfos);
722 if (rc == -1) {
723 LIBXL__EVENT_DISASTER(egc, "xc_domain_getinfolist failed while"
724 " processing @releaseDomain watch event",
725 errno, 0);
726 goto out;
727 }
728 gotend = &domaininfos[rc];
729
730 LOGD(DEBUG, evg->domid, "[evg=%p] nentries=%d rc=%d %ld..%ld",
731 evg, nentries, rc,
732 rc>0 ? (long)domaininfos[0].domain : 0,
733 rc>0 ? (long)domaininfos[rc-1].domain : 0);
734
735 for (;;) {
736 if (!evg) {
737 LOG(DEBUG, "[evg=0] all reported");
738 goto all_reported;
739 }
740
741 LOGD(DEBUG, evg->domid, "[evg=%p]"
742 " got=domaininfos[%d] got->domain=%ld",
743 evg, (int)(got - domaininfos),
744 got < gotend ? (long)got->domain : -1L);
745
746 if (!rc) {
747 domain_death_occurred(egc, &evg, "empty list");
748 continue;
749 }
750
751 if (got == gotend) {
752 LOG(DEBUG, " got==gotend");
753 break;
754 }
755
756 if (got->domain > evg->domid) {
757 /* ie, the list doesn't contain evg->domid any more so
758 * the domain has been destroyed */
759 domain_death_occurred(egc, &evg, "missing from list");
760 continue;
761 }
762
763 if (got->domain < evg->domid) {
764 got++;
765 continue;
766 }
767
768 assert(evg->domid == got->domain);
769 LOGD(DEBUG, evg->domid, "Exists shutdown_reported=%d"" dominf.flags=%x",
770 evg->shutdown_reported, got->flags);
771
772 if (got->flags & XEN_DOMINF_dying) {
773 domain_death_occurred(egc, &evg, "dying");
774 continue;
775 }
776
777 if (!evg->shutdown_reported &&
778 (got->flags & XEN_DOMINF_shutdown)) {
779 libxl_event *ev = NEW_EVENT(egc, DOMAIN_SHUTDOWN,
780 got->domain, evg->user);
781
782 LOG(DEBUG, " shutdown reporting");
783
784 ev->u.domain_shutdown.shutdown_reason =
785 (got->flags >> XEN_DOMINF_shutdownshift) &
786 XEN_DOMINF_shutdownmask;
787 libxl__event_occurred(egc, ev);
788
789 evg->shutdown_reported = 1;
790 }
791 evg = LIBXL_TAILQ_NEXT(evg, entry);
792 }
793
794 assert(rc); /* rc==0 results in us eating all evgs and quitting */
795 }
796 all_reported:
797 out:
798
799 LOG(DEBUG, "domain death search done");
800
801 CTX_UNLOCK;
802 }
803
libxl_evenable_domain_death(libxl_ctx * ctx,uint32_t domid,libxl_ev_user user,libxl_evgen_domain_death ** evgen_out)804 int libxl_evenable_domain_death(libxl_ctx *ctx, uint32_t domid,
805 libxl_ev_user user, libxl_evgen_domain_death **evgen_out) {
806 GC_INIT(ctx);
807 libxl_evgen_domain_death *evg, *evg_search;
808 int rc;
809
810 CTX_LOCK;
811
812 evg = malloc(sizeof(*evg)); if (!evg) { rc = ERROR_NOMEM; goto out; }
813 memset(evg, 0, sizeof(*evg));
814 evg->domid = domid;
815 evg->user = user;
816
817 LIBXL_TAILQ_INSERT_SORTED(&ctx->death_list, entry, evg, evg_search, ,
818 evg->domid > evg_search->domid);
819
820 if (!libxl__ev_xswatch_isregistered(&ctx->death_watch)) {
821 rc = libxl__ev_xswatch_register(gc, &ctx->death_watch,
822 domain_death_xswatch_callback, "@releaseDomain");
823 if (rc) { libxl__evdisable_domain_death(gc, evg); goto out; }
824 }
825
826 *evgen_out = evg;
827 rc = 0;
828
829 out:
830 CTX_UNLOCK;
831 GC_FREE;
832 return rc;
833 };
834
libxl__evdisable_domain_death(libxl__gc * gc,libxl_evgen_domain_death * evg)835 void libxl__evdisable_domain_death(libxl__gc *gc,
836 libxl_evgen_domain_death *evg) {
837 CTX_LOCK;
838
839 if (!evg->death_reported)
840 LIBXL_TAILQ_REMOVE(&CTX->death_list, evg, entry);
841 else
842 LIBXL_TAILQ_REMOVE(&CTX->death_reported, evg, entry);
843
844 free(evg);
845
846 if (!LIBXL_TAILQ_FIRST(&CTX->death_list) &&
847 libxl__ev_xswatch_isregistered(&CTX->death_watch))
848 libxl__ev_xswatch_deregister(gc, &CTX->death_watch);
849
850 CTX_UNLOCK;
851 }
852
libxl_evdisable_domain_death(libxl_ctx * ctx,libxl_evgen_domain_death * evg)853 void libxl_evdisable_domain_death(libxl_ctx *ctx,
854 libxl_evgen_domain_death *evg) {
855 GC_INIT(ctx);
856 libxl__evdisable_domain_death(gc, evg);
857 GC_FREE;
858 }
859
860 /* Callbacks for libxl_domain_destroy */
861
862 static void domain_destroy_cb(libxl__egc *egc, libxl__domain_destroy_state *dds,
863 int rc);
864
libxl_domain_destroy(libxl_ctx * ctx,uint32_t domid,const libxl_asyncop_how * ao_how)865 int libxl_domain_destroy(libxl_ctx *ctx, uint32_t domid,
866 const libxl_asyncop_how *ao_how)
867 {
868 AO_CREATE(ctx, domid, ao_how);
869 libxl__domain_destroy_state *dds;
870
871 GCNEW(dds);
872 dds->ao = ao;
873 dds->domid = domid;
874 dds->callback = domain_destroy_cb;
875 libxl__domain_destroy(egc, dds);
876
877 return AO_INPROGRESS;
878 }
879
domain_destroy_cb(libxl__egc * egc,libxl__domain_destroy_state * dds,int rc)880 static void domain_destroy_cb(libxl__egc *egc, libxl__domain_destroy_state *dds,
881 int rc)
882 {
883 STATE_AO_GC(dds->ao);
884
885 if (rc)
886 LOGD(ERROR, dds->domid, "Destruction of domain failed");
887
888 libxl__ao_complete(egc, ao, rc);
889 }
890
891 /* Callbacks for libxl__domain_destroy */
892
893 static void stubdom_destroy_callback(libxl__egc *egc,
894 libxl__destroy_domid_state *dis,
895 int rc);
896
897 static void domain_destroy_callback(libxl__egc *egc,
898 libxl__destroy_domid_state *dis,
899 int rc);
900
901 static void destroy_finish_check(libxl__egc *egc,
902 libxl__domain_destroy_state *dds);
903
libxl__domain_destroy(libxl__egc * egc,libxl__domain_destroy_state * dds)904 void libxl__domain_destroy(libxl__egc *egc, libxl__domain_destroy_state *dds)
905 {
906 STATE_AO_GC(dds->ao);
907 uint32_t stubdomid = libxl_get_stubdom_id(CTX, dds->domid);
908
909 if (stubdomid) {
910 dds->stubdom.ao = ao;
911 dds->stubdom.domid = stubdomid;
912 dds->stubdom.callback = stubdom_destroy_callback;
913 dds->stubdom.soft_reset = false;
914 libxl__destroy_domid(egc, &dds->stubdom);
915 } else {
916 dds->stubdom_finished = 1;
917 }
918
919 dds->domain.ao = ao;
920 dds->domain.domid = dds->domid;
921 dds->domain.callback = domain_destroy_callback;
922 dds->domain.soft_reset = dds->soft_reset;
923 libxl__destroy_domid(egc, &dds->domain);
924 }
925
stubdom_destroy_callback(libxl__egc * egc,libxl__destroy_domid_state * dis,int rc)926 static void stubdom_destroy_callback(libxl__egc *egc,
927 libxl__destroy_domid_state *dis,
928 int rc)
929 {
930 STATE_AO_GC(dis->ao);
931 libxl__domain_destroy_state *dds = CONTAINER_OF(dis, *dds, stubdom);
932 const char *savefile;
933
934 if (rc) {
935 LOGD(ERROR, dds->domain.domid, "Unable to destroy stubdom with domid %u",
936 dis->domid);
937 dds->rc = rc;
938 }
939
940 dds->stubdom_finished = 1;
941 savefile = libxl__device_model_savefile(gc, dis->domid);
942 rc = libxl__remove_file(gc, savefile);
943 if (rc) {
944 LOGD(ERROR, dds->domain.domid, "Failed to remove device-model savefile %s",
945 savefile);
946 }
947
948 destroy_finish_check(egc, dds);
949 }
950
domain_destroy_callback(libxl__egc * egc,libxl__destroy_domid_state * dis,int rc)951 static void domain_destroy_callback(libxl__egc *egc,
952 libxl__destroy_domid_state *dis,
953 int rc)
954 {
955 STATE_AO_GC(dis->ao);
956 libxl__domain_destroy_state *dds = CONTAINER_OF(dis, *dds, domain);
957
958 if (rc) {
959 LOGD(ERROR, dis->domid, "Unable to destroy guest");
960 dds->rc = rc;
961 }
962
963 dds->domain_finished = 1;
964 destroy_finish_check(egc, dds);
965 }
966
destroy_finish_check(libxl__egc * egc,libxl__domain_destroy_state * dds)967 static void destroy_finish_check(libxl__egc *egc,
968 libxl__domain_destroy_state *dds)
969 {
970 if (!(dds->domain_finished && dds->stubdom_finished))
971 return;
972
973 dds->callback(egc, dds, dds->rc);
974 }
975
976 /* Callbacks for libxl__destroy_domid */
977 static void devices_destroy_cb(libxl__egc *egc,
978 libxl__devices_remove_state *drs,
979 int rc);
980
981 static void domain_destroy_domid_cb(libxl__egc *egc,
982 libxl__ev_child *destroyer,
983 pid_t pid, int status);
984
libxl__destroy_domid(libxl__egc * egc,libxl__destroy_domid_state * dis)985 void libxl__destroy_domid(libxl__egc *egc, libxl__destroy_domid_state *dis)
986 {
987 STATE_AO_GC(dis->ao);
988 libxl_ctx *ctx = CTX;
989 uint32_t domid = dis->domid;
990 char *dom_path;
991 int rc, dm_present;
992
993 libxl__ev_child_init(&dis->destroyer);
994
995 rc = libxl_domain_info(ctx, NULL, domid);
996 switch(rc) {
997 case 0:
998 break;
999 case ERROR_DOMAIN_NOTFOUND:
1000 LOGD(ERROR, domid, "Non-existant domain");
1001 default:
1002 goto out;
1003 }
1004
1005 switch (libxl__domain_type(gc, domid)) {
1006 case LIBXL_DOMAIN_TYPE_HVM:
1007 if (libxl_get_stubdom_id(CTX, domid)) {
1008 dm_present = 0;
1009 break;
1010 }
1011 /* fall through */
1012 case LIBXL_DOMAIN_TYPE_PVH:
1013 case LIBXL_DOMAIN_TYPE_PV:
1014 dm_present = libxl__dm_active(gc, domid);
1015 break;
1016 case LIBXL_DOMAIN_TYPE_INVALID:
1017 rc = ERROR_FAIL;
1018 goto out;
1019 default:
1020 abort();
1021 }
1022
1023 dom_path = libxl__xs_get_dompath(gc, domid);
1024 if (!dom_path) {
1025 rc = ERROR_FAIL;
1026 goto out;
1027 }
1028
1029 if (libxl__device_pci_destroy_all(gc, domid) < 0)
1030 LOGD(ERROR, domid, "Pci shutdown failed");
1031 rc = xc_domain_pause(ctx->xch, domid);
1032 if (rc < 0) {
1033 LOGEVD(ERROR, rc, domid, "xc_domain_pause failed");
1034 }
1035 if (dm_present) {
1036 if (libxl__destroy_device_model(gc, domid) < 0)
1037 LOGD(ERROR, domid, "libxl__destroy_device_model failed");
1038
1039 libxl__qmp_cleanup(gc, domid);
1040 }
1041 dis->drs.ao = ao;
1042 dis->drs.domid = domid;
1043 dis->drs.callback = devices_destroy_cb;
1044 dis->drs.force = 1;
1045 libxl__devices_destroy(egc, &dis->drs);
1046 return;
1047
1048 out:
1049 assert(rc);
1050 dis->callback(egc, dis, rc);
1051 return;
1052 }
1053
devices_destroy_cb(libxl__egc * egc,libxl__devices_remove_state * drs,int rc)1054 static void devices_destroy_cb(libxl__egc *egc,
1055 libxl__devices_remove_state *drs,
1056 int rc)
1057 {
1058 STATE_AO_GC(drs->ao);
1059 libxl__destroy_domid_state *dis = CONTAINER_OF(drs, *dis, drs);
1060 libxl_ctx *ctx = CTX;
1061 uint32_t domid = dis->domid;
1062 char *dom_path;
1063 char *vm_path;
1064 libxl__domain_userdata_lock *lock;
1065
1066 dom_path = libxl__xs_get_dompath(gc, domid);
1067 if (!dom_path) {
1068 rc = ERROR_FAIL;
1069 goto out;
1070 }
1071
1072 if (rc < 0)
1073 LOGD(ERROR, domid, "libxl__devices_destroy failed");
1074
1075 vm_path = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/vm", dom_path));
1076 if (vm_path)
1077 if (!xs_rm(ctx->xsh, XBT_NULL, vm_path))
1078 LOGED(ERROR, domid, "xs_rm failed for %s", vm_path);
1079
1080 if (!xs_rm(ctx->xsh, XBT_NULL, dom_path))
1081 LOGED(ERROR, domid, "xs_rm failed for %s", dom_path);
1082
1083 xs_rm(ctx->xsh, XBT_NULL, libxl__xs_libxl_path(gc, domid));
1084 xs_rm(ctx->xsh, XBT_NULL, GCSPRINTF( "/local/domain/%d/hvmloader", domid));
1085
1086 /* This is async operation, we already hold CTX lock */
1087 lock = libxl__lock_domain_userdata(gc, domid);
1088 if (!lock) {
1089 rc = ERROR_LOCK_FAIL;
1090 goto out;
1091 }
1092 libxl__userdata_destroyall(gc, domid);
1093
1094 libxl__unlock_domain_userdata(lock);
1095
1096 /* Clean up qemu-save and qemu-resume files. They are
1097 * intermediate files created by libxc. Unfortunately they
1098 * don't fit in existing userdata scheme very well. In soft reset
1099 * case we need to keep the file.
1100 */
1101 if (!dis->soft_reset) {
1102 rc = libxl__remove_file(gc,
1103 libxl__device_model_savefile(gc, domid));
1104 if (rc < 0) goto out;
1105 }
1106 rc = libxl__remove_file(gc,
1107 GCSPRINTF(LIBXL_DEVICE_MODEL_RESTORE_FILE".%u", domid));
1108 if (rc < 0) goto out;
1109
1110 rc = libxl__ev_child_fork(gc, &dis->destroyer, domain_destroy_domid_cb);
1111 if (rc < 0) goto out;
1112 if (!rc) { /* child */
1113 ctx->xch = xc_interface_open(ctx->lg,0,0);
1114 if (!ctx->xch) goto badchild;
1115
1116 if (!dis->soft_reset) {
1117 rc = xc_domain_destroy(ctx->xch, domid);
1118 } else {
1119 rc = xc_domain_pause(ctx->xch, domid);
1120 if (rc < 0) goto badchild;
1121 rc = xc_domain_soft_reset(ctx->xch, domid);
1122 if (rc < 0) goto badchild;
1123 rc = xc_domain_unpause(ctx->xch, domid);
1124 }
1125 if (rc < 0) goto badchild;
1126 _exit(0);
1127
1128 badchild:
1129 if (errno > 0 && errno < 126) {
1130 _exit(errno);
1131 } else {
1132 LOGED(ERROR, domid,
1133 "xc_domain_destroy failed (with difficult errno value %d)",
1134 errno);
1135 _exit(-1);
1136 }
1137 }
1138 LOGD(DEBUG, domid, "Forked pid %ld for destroy of domain", (long)rc);
1139
1140 return;
1141
1142 out:
1143 dis->callback(egc, dis, rc);
1144 return;
1145 }
1146
domain_destroy_domid_cb(libxl__egc * egc,libxl__ev_child * destroyer,pid_t pid,int status)1147 static void domain_destroy_domid_cb(libxl__egc *egc,
1148 libxl__ev_child *destroyer,
1149 pid_t pid, int status)
1150 {
1151 libxl__destroy_domid_state *dis = CONTAINER_OF(destroyer, *dis, destroyer);
1152 STATE_AO_GC(dis->ao);
1153 int rc;
1154
1155 if (status) {
1156 if (WIFEXITED(status) && WEXITSTATUS(status)<126) {
1157 LOGEVD(ERROR, WEXITSTATUS(status), dis->domid,
1158 "xc_domain_destroy failed");
1159 } else {
1160 libxl_report_child_exitstatus(CTX, XTL_ERROR,
1161 "async domain destroy", pid, status);
1162 }
1163 rc = ERROR_FAIL;
1164 goto out;
1165 }
1166 rc = 0;
1167
1168 out:
1169 dis->callback(egc, dis, rc);
1170 }
1171
libxl__get_domid(libxl__gc * gc,uint32_t * domid)1172 int libxl__get_domid(libxl__gc *gc, uint32_t *domid)
1173 {
1174 int rc;
1175 const char *xs_domid;
1176
1177 rc = libxl__xs_read_checked(gc, XBT_NULL, DOMID_XS_PATH, &xs_domid);
1178 if (rc) goto out;
1179 if (!xs_domid) {
1180 LOG(ERROR, "failed to get own domid (%s)", DOMID_XS_PATH);
1181 rc = ERROR_FAIL;
1182 goto out;
1183 }
1184
1185 *domid = atoi(xs_domid);
1186
1187 out:
1188 return rc;
1189 }
1190
libxl__resolve_domid(libxl__gc * gc,const char * name,uint32_t * domid)1191 int libxl__resolve_domid(libxl__gc *gc, const char *name, uint32_t *domid)
1192 {
1193 if (!name)
1194 return 0;
1195 return libxl_domain_qualifier_to_domid(CTX, name, domid);
1196 }
1197
libxl_list_vcpu(libxl_ctx * ctx,uint32_t domid,int * nr_vcpus_out,int * nr_cpus_out)1198 libxl_vcpuinfo *libxl_list_vcpu(libxl_ctx *ctx, uint32_t domid,
1199 int *nr_vcpus_out, int *nr_cpus_out)
1200 {
1201 GC_INIT(ctx);
1202 libxl_vcpuinfo *ptr, *ret;
1203 xc_domaininfo_t domaininfo;
1204 xc_vcpuinfo_t vcpuinfo;
1205
1206 if (xc_domain_getinfolist(ctx->xch, domid, 1, &domaininfo) != 1) {
1207 LOGED(ERROR, domid, "Getting infolist");
1208 GC_FREE;
1209 return NULL;
1210 }
1211
1212 if (domaininfo.max_vcpu_id == XEN_INVALID_MAX_VCPU_ID) {
1213 GC_FREE;
1214 return NULL;
1215 }
1216
1217 *nr_cpus_out = libxl_get_max_cpus(ctx);
1218 ret = ptr = libxl__calloc(NOGC, domaininfo.max_vcpu_id + 1,
1219 sizeof(libxl_vcpuinfo));
1220
1221 for (*nr_vcpus_out = 0;
1222 *nr_vcpus_out <= domaininfo.max_vcpu_id;
1223 ++*nr_vcpus_out, ++ptr) {
1224 libxl_bitmap_init(&ptr->cpumap);
1225 if (libxl_cpu_bitmap_alloc(ctx, &ptr->cpumap, 0))
1226 goto err;
1227 libxl_bitmap_init(&ptr->cpumap_soft);
1228 if (libxl_cpu_bitmap_alloc(ctx, &ptr->cpumap_soft, 0))
1229 goto err;
1230 if (xc_vcpu_getinfo(ctx->xch, domid, *nr_vcpus_out, &vcpuinfo) == -1) {
1231 LOGED(ERROR, domid, "Getting vcpu info");
1232 goto err;
1233 }
1234
1235 if (xc_vcpu_getaffinity(ctx->xch, domid, *nr_vcpus_out,
1236 ptr->cpumap.map, ptr->cpumap_soft.map,
1237 XEN_VCPUAFFINITY_SOFT|XEN_VCPUAFFINITY_HARD) == -1) {
1238 LOGED(ERROR, domid, "Getting vcpu affinity");
1239 goto err;
1240 }
1241 ptr->vcpuid = *nr_vcpus_out;
1242 ptr->cpu = vcpuinfo.cpu;
1243 ptr->online = !!vcpuinfo.online;
1244 ptr->blocked = !!vcpuinfo.blocked;
1245 ptr->running = !!vcpuinfo.running;
1246 ptr->vcpu_time = vcpuinfo.cpu_time;
1247 }
1248 GC_FREE;
1249 return ret;
1250
1251 err:
1252 libxl_bitmap_dispose(&ptr->cpumap);
1253 libxl_bitmap_dispose(&ptr->cpumap_soft);
1254 free(ret);
1255 GC_FREE;
1256 return NULL;
1257 }
1258
libxl__set_vcpuonline_xenstore(libxl__gc * gc,uint32_t domid,libxl_bitmap * cpumap,const libxl_dominfo * info)1259 static int libxl__set_vcpuonline_xenstore(libxl__gc *gc, uint32_t domid,
1260 libxl_bitmap *cpumap,
1261 const libxl_dominfo *info)
1262 {
1263 char *dompath;
1264 xs_transaction_t t;
1265 int i, rc = ERROR_FAIL;
1266
1267 if (!(dompath = libxl__xs_get_dompath(gc, domid)))
1268 goto out;
1269
1270 retry_transaction:
1271 t = xs_transaction_start(CTX->xsh);
1272 for (i = 0; i <= info->vcpu_max_id; i++)
1273 libxl__xs_printf(gc, t,
1274 GCSPRINTF("%s/cpu/%u/availability", dompath, i),
1275 "%s", libxl_bitmap_test(cpumap, i) ? "online" : "offline");
1276 if (!xs_transaction_end(CTX->xsh, t, 0)) {
1277 if (errno == EAGAIN)
1278 goto retry_transaction;
1279 } else
1280 rc = 0;
1281 out:
1282 return rc;
1283 }
1284
libxl__set_vcpuonline_qmp(libxl__gc * gc,uint32_t domid,libxl_bitmap * cpumap,const libxl_dominfo * info)1285 static int libxl__set_vcpuonline_qmp(libxl__gc *gc, uint32_t domid,
1286 libxl_bitmap *cpumap,
1287 const libxl_dominfo *info)
1288 {
1289 int i, rc;
1290 libxl_bitmap current_map, final_map;
1291
1292 libxl_bitmap_init(¤t_map);
1293 libxl_bitmap_init(&final_map);
1294
1295 libxl_bitmap_alloc(CTX, ¤t_map, info->vcpu_max_id + 1);
1296 libxl_bitmap_set_none(¤t_map);
1297 rc = libxl__qmp_query_cpus(gc, domid, ¤t_map);
1298 if (rc) {
1299 LOGD(ERROR, domid, "Failed to query cpus");
1300 goto out;
1301 }
1302
1303 libxl_bitmap_copy_alloc(CTX, &final_map, cpumap);
1304
1305 libxl_for_each_set_bit(i, current_map)
1306 libxl_bitmap_reset(&final_map, i);
1307
1308 libxl_for_each_set_bit(i, final_map) {
1309 rc = libxl__qmp_cpu_add(gc, domid, i);
1310 if (rc) {
1311 LOGD(ERROR, domid, "Failed to add cpu %d", i);
1312 goto out;
1313 }
1314 }
1315
1316 rc = 0;
1317 out:
1318 libxl_bitmap_dispose(¤t_map);
1319 libxl_bitmap_dispose(&final_map);
1320 return rc;
1321 }
1322
libxl_set_vcpuonline(libxl_ctx * ctx,uint32_t domid,libxl_bitmap * cpumap)1323 int libxl_set_vcpuonline(libxl_ctx *ctx, uint32_t domid, libxl_bitmap *cpumap)
1324 {
1325 GC_INIT(ctx);
1326 int rc, maxcpus;
1327 libxl_dominfo info;
1328
1329 libxl_dominfo_init(&info);
1330
1331 rc = libxl_domain_info(CTX, &info, domid);
1332 if (rc < 0) {
1333 LOGED(ERROR, domid, "Getting domain info list");
1334 goto out;
1335 }
1336
1337 maxcpus = libxl_bitmap_count_set(cpumap);
1338 if (maxcpus > info.vcpu_max_id + 1)
1339 {
1340 LOGED(ERROR, domid, "Requested %d VCPUs, however maxcpus is %d!",
1341 maxcpus, info.vcpu_max_id + 1);
1342 rc = ERROR_FAIL;
1343 goto out;
1344 }
1345
1346 switch (libxl__domain_type(gc, domid)) {
1347 case LIBXL_DOMAIN_TYPE_HVM:
1348 switch (libxl__device_model_version_running(gc, domid)) {
1349 case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
1350 break;
1351 case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
1352 rc = libxl__set_vcpuonline_qmp(gc, domid, cpumap, &info);
1353 break;
1354 default:
1355 rc = ERROR_INVAL;
1356 }
1357 break;
1358 case LIBXL_DOMAIN_TYPE_PVH:
1359 case LIBXL_DOMAIN_TYPE_PV:
1360 break;
1361 default:
1362 rc = ERROR_INVAL;
1363 }
1364
1365 if (!rc)
1366 rc = libxl__set_vcpuonline_xenstore(gc, domid, cpumap, &info);
1367
1368 out:
1369 libxl_dominfo_dispose(&info);
1370 GC_FREE;
1371 return rc;
1372 }
1373
libxl__domain_s3_resume(libxl__gc * gc,int domid)1374 static int libxl__domain_s3_resume(libxl__gc *gc, int domid)
1375 {
1376 int rc = 0;
1377
1378 switch (libxl__domain_type(gc, domid)) {
1379 case LIBXL_DOMAIN_TYPE_HVM:
1380 switch (libxl__device_model_version_running(gc, domid)) {
1381 case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
1382 rc = xc_hvm_param_set(CTX->xch, domid, HVM_PARAM_ACPI_S_STATE, 0);
1383 break;
1384 case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
1385 rc = libxl__qmp_system_wakeup(gc, domid);
1386 break;
1387 default:
1388 rc = ERROR_INVAL;
1389 break;
1390 }
1391 break;
1392 default:
1393 rc = ERROR_INVAL;
1394 break;
1395 }
1396
1397 return rc;
1398 }
1399
libxl_send_trigger(libxl_ctx * ctx,uint32_t domid,libxl_trigger trigger,uint32_t vcpuid)1400 int libxl_send_trigger(libxl_ctx *ctx, uint32_t domid,
1401 libxl_trigger trigger, uint32_t vcpuid)
1402 {
1403 int rc;
1404 GC_INIT(ctx);
1405
1406 switch (trigger) {
1407 case LIBXL_TRIGGER_POWER:
1408 rc = xc_domain_send_trigger(ctx->xch, domid,
1409 XEN_DOMCTL_SENDTRIGGER_POWER, vcpuid);
1410 break;
1411 case LIBXL_TRIGGER_SLEEP:
1412 rc = xc_domain_send_trigger(ctx->xch, domid,
1413 XEN_DOMCTL_SENDTRIGGER_SLEEP, vcpuid);
1414 break;
1415 case LIBXL_TRIGGER_NMI:
1416 rc = xc_domain_send_trigger(ctx->xch, domid,
1417 XEN_DOMCTL_SENDTRIGGER_NMI, vcpuid);
1418 break;
1419 case LIBXL_TRIGGER_INIT:
1420 rc = xc_domain_send_trigger(ctx->xch, domid,
1421 XEN_DOMCTL_SENDTRIGGER_INIT, vcpuid);
1422 break;
1423 case LIBXL_TRIGGER_RESET:
1424 rc = xc_domain_send_trigger(ctx->xch, domid,
1425 XEN_DOMCTL_SENDTRIGGER_RESET, vcpuid);
1426 break;
1427 case LIBXL_TRIGGER_S3RESUME:
1428 rc = libxl__domain_s3_resume(gc, domid);
1429 break;
1430 default:
1431 rc = -1;
1432 errno = EINVAL;
1433 break;
1434 }
1435
1436 if (rc != 0) {
1437 LOGED(ERROR, domid, "Send trigger '%s' failed",
1438 libxl_trigger_to_string(trigger));
1439 rc = ERROR_FAIL;
1440 }
1441
1442 GC_FREE;
1443 return rc;
1444 }
1445
libxl_vm_get_start_time(libxl_ctx * ctx,uint32_t domid)1446 uint32_t libxl_vm_get_start_time(libxl_ctx *ctx, uint32_t domid)
1447 {
1448 GC_INIT(ctx);
1449 char *dompath = libxl__xs_get_dompath(gc, domid);
1450 char *vm_path, *start_time;
1451 uint32_t ret;
1452
1453 vm_path = libxl__xs_read(
1454 gc, XBT_NULL, GCSPRINTF("%s/vm", dompath));
1455 start_time = libxl__xs_read(
1456 gc, XBT_NULL, GCSPRINTF("%s/start_time", vm_path));
1457 if (start_time == NULL) {
1458 LOGEVD(ERROR, -1, domid, "Can't get start time of domain");
1459 ret = -1;
1460 }else{
1461 ret = strtoul(start_time, NULL, 10);
1462 }
1463 GC_FREE;
1464 return ret;
1465 }
1466
1467 /* For QEMU upstream we always need to provide the number of cpus present to
1468 * QEMU whether they are online or not; otherwise QEMU won't accept the saved
1469 * state. See implementation of libxl__qmp_query_cpus.
1470 */
libxl__update_avail_vcpus_qmp(libxl__gc * gc,uint32_t domid,unsigned int max_vcpus,libxl_bitmap * map)1471 static int libxl__update_avail_vcpus_qmp(libxl__gc *gc, uint32_t domid,
1472 unsigned int max_vcpus,
1473 libxl_bitmap *map)
1474 {
1475 int rc;
1476
1477 rc = libxl__qmp_query_cpus(gc, domid, map);
1478 if (rc) {
1479 LOGD(ERROR, domid, "Fail to get number of cpus");
1480 goto out;
1481 }
1482
1483 rc = 0;
1484 out:
1485 return rc;
1486 }
1487
libxl__update_avail_vcpus_xenstore(libxl__gc * gc,uint32_t domid,unsigned int max_vcpus,libxl_bitmap * map)1488 static int libxl__update_avail_vcpus_xenstore(libxl__gc *gc, uint32_t domid,
1489 unsigned int max_vcpus,
1490 libxl_bitmap *map)
1491 {
1492 int rc;
1493 unsigned int i;
1494 const char *dompath;
1495
1496 dompath = libxl__xs_get_dompath(gc, domid);
1497 if (!dompath) {
1498 rc = ERROR_FAIL;
1499 goto out;
1500 }
1501
1502 for (i = 0; i < max_vcpus; i++) {
1503 const char *path = GCSPRINTF("%s/cpu/%u/availability", dompath, i);
1504 const char *content;
1505 rc = libxl__xs_read_checked(gc, XBT_NULL, path, &content);
1506 if (rc) goto out;
1507 if (content && !strcmp(content, "online"))
1508 libxl_bitmap_set(map, i);
1509 }
1510
1511 rc = 0;
1512 out:
1513 return rc;
1514 }
1515
libxl_retrieve_domain_configuration(libxl_ctx * ctx,uint32_t domid,libxl_domain_config * d_config)1516 int libxl_retrieve_domain_configuration(libxl_ctx *ctx, uint32_t domid,
1517 libxl_domain_config *d_config)
1518 {
1519 GC_INIT(ctx);
1520 int rc;
1521 libxl__domain_userdata_lock *lock = NULL;
1522
1523 CTX_LOCK;
1524
1525 lock = libxl__lock_domain_userdata(gc, domid);
1526 if (!lock) {
1527 rc = ERROR_LOCK_FAIL;
1528 goto out;
1529 }
1530
1531 rc = libxl__get_domain_configuration(gc, domid, d_config);
1532 if (rc) {
1533 LOGD(ERROR, domid, "Fail to get domain configuration");
1534 rc = ERROR_FAIL;
1535 goto out;
1536 }
1537
1538 /* Domain name */
1539 {
1540 char *domname;
1541 domname = libxl_domid_to_name(ctx, domid);
1542 if (!domname) {
1543 LOGD(ERROR, domid, "Fail to get domain name");
1544 goto out;
1545 }
1546 free(d_config->c_info.name);
1547 d_config->c_info.name = domname; /* steals allocation */
1548 }
1549
1550 /* Domain UUID */
1551 {
1552 libxl_dominfo info;
1553 libxl_dominfo_init(&info);
1554 rc = libxl_domain_info(ctx, &info, domid);
1555 if (rc) {
1556 LOGD(ERROR, domid, "Fail to get domain info");
1557 libxl_dominfo_dispose(&info);
1558 goto out;
1559 }
1560 libxl_uuid_copy(ctx, &d_config->c_info.uuid, &info.uuid);
1561 libxl_dominfo_dispose(&info);
1562 }
1563
1564 /* VCPUs */
1565 {
1566 libxl_bitmap *map = &d_config->b_info.avail_vcpus;
1567 unsigned int max_vcpus = d_config->b_info.max_vcpus;
1568 libxl_device_model_version version;
1569
1570 libxl_bitmap_dispose(map);
1571 libxl_bitmap_init(map);
1572 libxl_bitmap_alloc(CTX, map, max_vcpus);
1573 libxl_bitmap_set_none(map);
1574
1575 switch (d_config->b_info.type) {
1576 case LIBXL_DOMAIN_TYPE_HVM:
1577 version = libxl__device_model_version_running(gc, domid);
1578 assert(version != LIBXL_DEVICE_MODEL_VERSION_UNKNOWN);
1579 switch (version) {
1580 case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN:
1581 rc = libxl__update_avail_vcpus_qmp(gc, domid,
1582 max_vcpus, map);
1583 break;
1584 case LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL:
1585 rc = libxl__update_avail_vcpus_xenstore(gc, domid,
1586 max_vcpus, map);
1587 break;
1588 default:
1589 abort();
1590 }
1591 break;
1592 case LIBXL_DOMAIN_TYPE_PVH:
1593 case LIBXL_DOMAIN_TYPE_PV:
1594 rc = libxl__update_avail_vcpus_xenstore(gc, domid,
1595 max_vcpus, map);
1596 break;
1597 default:
1598 abort();
1599 }
1600
1601 if (rc) {
1602 LOGD(ERROR, domid, "Fail to update available cpu map");
1603 goto out;
1604 }
1605 }
1606
1607 /* Memory limits:
1608 *
1609 * Currently there are three memory limits:
1610 * 1. "target" in xenstore (originally memory= in config file)
1611 * 2. "static-max" in xenstore (originally maxmem= in config file)
1612 * 3. "max_memkb" in hypervisor
1613 *
1614 * The third one is not visible and currently managed by
1615 * toolstack. In order to rebuild a domain we only need to have
1616 * "target" and "static-max".
1617 */
1618 {
1619 uint64_t target_memkb = 0, max_memkb = 0;
1620
1621 /* "target" */
1622 rc = libxl__get_memory_target(gc, domid, &target_memkb, &max_memkb);
1623 if (rc) {
1624 LOGD(ERROR, domid, "Fail to get memory target");
1625 goto out;
1626 }
1627
1628 /* libxl__get_targetmem_fudge() calculates the difference from
1629 * what is in xenstore to what we have in the domain build info.
1630 */
1631 d_config->b_info.target_memkb = target_memkb +
1632 libxl__get_targetmem_fudge(gc, &d_config->b_info);
1633
1634 d_config->b_info.max_memkb = max_memkb;
1635 }
1636
1637 /* Scheduler params */
1638 {
1639 libxl_domain_sched_params_dispose(&d_config->b_info.sched_params);
1640 rc = libxl_domain_sched_params_get(ctx, domid,
1641 &d_config->b_info.sched_params);
1642 if (rc) {
1643 LOGD(ERROR, domid, "Fail to get scheduler parameters");
1644 goto out;
1645 }
1646 }
1647
1648 /* Devices: disk, nic, vtpm, pcidev etc. */
1649
1650 /* The MERGE macro implements following logic:
1651 * 0. retrieve JSON (done by now)
1652 * 1. retrieve list of device from xenstore
1653 * 2. use xenstore entries as primary reference and compare JSON
1654 * entries with them.
1655 * a. if a device is present in xenstore and in JSON, merge the
1656 * two views.
1657 * b. if a device is not present in xenstore but in JSON, delete
1658 * it from the result.
1659 * c. it's impossible to have an entry present in xenstore but
1660 * not in JSON, because we maintain an invariant that every
1661 * entry in xenstore must have a corresponding entry in JSON.
1662 * 3. "merge" operates on "src" and "dst". "src" points to the
1663 * entry retrieved from xenstore while "dst" points to the entry
1664 * retrieve from JSON.
1665 */
1666 {
1667 const struct libxl_device_type *dt;
1668 int idx;
1669
1670 for (idx = 0;; idx++) {
1671 void *p = NULL;
1672 void **devs;
1673 int i, j, num;
1674 int *num_dev;
1675
1676 dt = device_type_tbl[idx];
1677 if (!dt)
1678 break;
1679
1680 if (!dt->compare)
1681 continue;
1682
1683 num_dev = libxl__device_type_get_num(dt, d_config);
1684 p = libxl__device_list(gc, dt, domid, &num);
1685 if (p == NULL) {
1686 LOGD(DEBUG, domid, "No %s from xenstore",
1687 dt->type);
1688 }
1689 devs = libxl__device_type_get_ptr(dt, d_config);
1690
1691 for (i = 0; i < *num_dev; i++) {
1692 void *q;
1693
1694 q = libxl__device_type_get_elem(dt, d_config, i);
1695 for (j = 0; j < num; j++) {
1696 if (dt->compare(p + dt->dev_elem_size * j, q))
1697 break;
1698 }
1699
1700 if (j < num) { /* found in xenstore */
1701 if (dt->merge)
1702 dt->merge(ctx, p + dt->dev_elem_size * j, q);
1703 } else { /* not found in xenstore */
1704 LOGD(WARN, domid,
1705 "Device present in JSON but not in xenstore, ignored");
1706
1707 dt->dispose(q);
1708
1709 for (j = i; j < *num_dev - 1; j++)
1710 memcpy(libxl__device_type_get_elem(dt, d_config, j),
1711 libxl__device_type_get_elem(dt, d_config, j+1),
1712 dt->dev_elem_size);
1713
1714 /* rewind counters */
1715 (*num_dev)--;
1716 i--;
1717
1718 *devs = libxl__realloc(NOGC, *devs,
1719 dt->dev_elem_size * *num_dev);
1720 }
1721 }
1722
1723 for (i = 0; i < num; i++)
1724 dt->dispose(p + dt->dev_elem_size * i);
1725 free(p);
1726 }
1727 }
1728
1729 out:
1730 if (lock) libxl__unlock_domain_userdata(lock);
1731 CTX_UNLOCK;
1732 GC_FREE;
1733 return rc;
1734 }
1735
1736 /*
1737 * Local variables:
1738 * mode: C
1739 * c-basic-offset: 4
1740 * indent-tabs-mode: nil
1741 * End:
1742 */
1743