1 /*
2 * libxl_domain.c: libxl domain object private state
3 *
4 * Copyright (C) 2011-2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22
23 #include <fcntl.h>
24
25 #include "libxl_api_wrapper.h"
26 #include "libxl_domain.h"
27 #include "libxl_capabilities.h"
28
29 #include "datatypes.h"
30 #include "viralloc.h"
31 #include "virfile.h"
32 #include "virerror.h"
33 #include "virhook.h"
34 #include "virlog.h"
35 #include "virstring.h"
36 #include "virtime.h"
37 #include "locking/domain_lock.h"
38 #include "xen_common.h"
39 #include "driver.h"
40 #include "domain_validate.h"
41
42 #define VIR_FROM_THIS VIR_FROM_LIBXL
43
44 VIR_LOG_INIT("libxl.libxl_domain");
45
46 VIR_ENUM_IMPL(libxlDomainJob,
47 LIBXL_JOB_LAST,
48 "none",
49 "query",
50 "destroy",
51 "modify",
52 );
53
54
55 static int
libxlDomainObjInitJob(libxlDomainObjPrivate * priv)56 libxlDomainObjInitJob(libxlDomainObjPrivate *priv)
57 {
58 memset(&priv->job, 0, sizeof(priv->job));
59
60 if (virCondInit(&priv->job.cond) < 0)
61 return -1;
62
63 priv->job.current = g_new0(virDomainJobInfo, 1);
64
65 return 0;
66 }
67
68 static void
libxlDomainObjResetJob(libxlDomainObjPrivate * priv)69 libxlDomainObjResetJob(libxlDomainObjPrivate *priv)
70 {
71 struct libxlDomainJobObj *job = &priv->job;
72
73 job->active = LIBXL_JOB_NONE;
74 job->owner = 0;
75 }
76
77 static void
libxlDomainObjFreeJob(libxlDomainObjPrivate * priv)78 libxlDomainObjFreeJob(libxlDomainObjPrivate *priv)
79 {
80 ignore_value(virCondDestroy(&priv->job.cond));
81 VIR_FREE(priv->job.current);
82 }
83
84 /* Give up waiting for mutex after 30 seconds */
85 #define LIBXL_JOB_WAIT_TIME (1000ull * 30)
86
87 /*
88 * obj must be locked before calling, libxlDriverPrivate *must NOT be locked
89 *
90 * This must be called by anything that will change the VM state
91 * in any way
92 *
93 * Upon successful return, the object will have its ref count increased,
94 * successful calls must be followed by EndJob eventually
95 */
96 int
libxlDomainObjBeginJob(libxlDriverPrivate * driver G_GNUC_UNUSED,virDomainObj * obj,enum libxlDomainJob job)97 libxlDomainObjBeginJob(libxlDriverPrivate *driver G_GNUC_UNUSED,
98 virDomainObj *obj,
99 enum libxlDomainJob job)
100 {
101 libxlDomainObjPrivate *priv = obj->privateData;
102 unsigned long long now;
103 unsigned long long then;
104
105 if (virTimeMillisNow(&now) < 0)
106 return -1;
107 then = now + LIBXL_JOB_WAIT_TIME;
108
109 while (priv->job.active) {
110 VIR_DEBUG("Wait normal job condition for starting job: %s",
111 libxlDomainJobTypeToString(job));
112 if (virCondWaitUntil(&priv->job.cond, &obj->parent.lock, then) < 0)
113 goto error;
114 }
115
116 libxlDomainObjResetJob(priv);
117
118 VIR_DEBUG("Starting job: %s", libxlDomainJobTypeToString(job));
119 priv->job.active = job;
120 priv->job.owner = virThreadSelfID();
121 priv->job.started = now;
122 priv->job.current->type = VIR_DOMAIN_JOB_UNBOUNDED;
123
124 return 0;
125
126 error:
127 VIR_WARN("Cannot start job (%s) for domain %s;"
128 " current job is (%s) owned by (%d)",
129 libxlDomainJobTypeToString(job),
130 obj->def->name,
131 libxlDomainJobTypeToString(priv->job.active),
132 priv->job.owner);
133
134 if (errno == ETIMEDOUT)
135 virReportError(VIR_ERR_OPERATION_TIMEOUT,
136 "%s", _("cannot acquire state change lock"));
137 else
138 virReportSystemError(errno,
139 "%s", _("cannot acquire job mutex"));
140
141 return -1;
142 }
143
144 /*
145 * obj must be locked before calling
146 *
147 * To be called after completing the work associated with the
148 * earlier libxlDomainBeginJob() call
149 *
150 * Returns true if the remaining reference count on obj is
151 * non-zero, false if the reference count has dropped to zero
152 * and obj is disposed.
153 */
154 void
libxlDomainObjEndJob(libxlDriverPrivate * driver G_GNUC_UNUSED,virDomainObj * obj)155 libxlDomainObjEndJob(libxlDriverPrivate *driver G_GNUC_UNUSED,
156 virDomainObj *obj)
157 {
158 libxlDomainObjPrivate *priv = obj->privateData;
159 enum libxlDomainJob job = priv->job.active;
160
161 VIR_DEBUG("Stopping job: %s",
162 libxlDomainJobTypeToString(job));
163
164 libxlDomainObjResetJob(priv);
165 virCondSignal(&priv->job.cond);
166 }
167
168 int
libxlDomainJobUpdateTime(struct libxlDomainJobObj * job)169 libxlDomainJobUpdateTime(struct libxlDomainJobObj *job)
170 {
171 virDomainJobInfoPtr jobInfo = job->current;
172 unsigned long long now;
173
174 if (!job->started)
175 return 0;
176
177 if (virTimeMillisNow(&now) < 0)
178 return -1;
179
180 if (now < job->started) {
181 job->started = 0;
182 return 0;
183 }
184
185 jobInfo->timeElapsed = now - job->started;
186 return 0;
187 }
188
189 static void *
libxlDomainObjPrivateAlloc(void * opaque G_GNUC_UNUSED)190 libxlDomainObjPrivateAlloc(void *opaque G_GNUC_UNUSED)
191 {
192 libxlDomainObjPrivate *priv;
193
194 priv = g_new0(libxlDomainObjPrivate, 1);
195
196 if (!(priv->devs = virChrdevAlloc())) {
197 g_free(priv);
198 return NULL;
199 }
200
201 if (libxlDomainObjInitJob(priv) < 0) {
202 virChrdevFree(priv->devs);
203 g_free(priv);
204 return NULL;
205 }
206
207 return priv;
208 }
209
210 static void
libxlDomainObjPrivateFree(void * data)211 libxlDomainObjPrivateFree(void *data)
212 {
213 libxlDomainObjPrivate *priv = data;
214
215 g_free(priv->lockState);
216 libxlDomainObjFreeJob(priv);
217 virChrdevFree(priv->devs);
218 g_free(priv);
219 }
220
221 static int
libxlDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt,virDomainObj * vm,virDomainDefParserConfig * config G_GNUC_UNUSED)222 libxlDomainObjPrivateXMLParse(xmlXPathContextPtr ctxt,
223 virDomainObj *vm,
224 virDomainDefParserConfig *config G_GNUC_UNUSED)
225 {
226 libxlDomainObjPrivate *priv = vm->privateData;
227
228 priv->lockState = virXPathString("string(./lockstate)", ctxt);
229
230 return 0;
231 }
232
233 static int
libxlDomainObjPrivateXMLFormat(virBuffer * buf,virDomainObj * vm)234 libxlDomainObjPrivateXMLFormat(virBuffer *buf,
235 virDomainObj *vm)
236 {
237 libxlDomainObjPrivate *priv = vm->privateData;
238
239 if (priv->lockState)
240 virBufferAsprintf(buf, "<lockstate>%s</lockstate>\n", priv->lockState);
241
242 return 0;
243 }
244
245 virDomainXMLPrivateDataCallbacks libxlDomainXMLPrivateDataCallbacks = {
246 .alloc = libxlDomainObjPrivateAlloc,
247 .free = libxlDomainObjPrivateFree,
248 .parse = libxlDomainObjPrivateXMLParse,
249 .format = libxlDomainObjPrivateXMLFormat,
250 };
251
252
253 static int
libxlDomainDeviceDefPostParse(virDomainDeviceDef * dev,const virDomainDef * def,unsigned int parseFlags G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED,void * parseOpaque G_GNUC_UNUSED)254 libxlDomainDeviceDefPostParse(virDomainDeviceDef *dev,
255 const virDomainDef *def,
256 unsigned int parseFlags G_GNUC_UNUSED,
257 void *opaque G_GNUC_UNUSED,
258 void *parseOpaque G_GNUC_UNUSED)
259 {
260 if (dev->type == VIR_DOMAIN_DEVICE_CHR &&
261 dev->data.chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE &&
262 dev->data.chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_NONE &&
263 def->os.type != VIR_DOMAIN_OSTYPE_HVM)
264 dev->data.chr->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
265
266 if (dev->type == VIR_DOMAIN_DEVICE_HOSTDEV ||
267 (dev->type == VIR_DOMAIN_DEVICE_NET &&
268 dev->data.net->type == VIR_DOMAIN_NET_TYPE_HOSTDEV)) {
269
270 virDomainHostdevDef *hostdev;
271 virDomainHostdevSubsysPCI *pcisrc;
272
273 if (dev->type == VIR_DOMAIN_DEVICE_NET)
274 hostdev = &dev->data.net->data.hostdev.def;
275 else
276 hostdev = dev->data.hostdev;
277 pcisrc = &hostdev->source.subsys.u.pci;
278
279 /* forbid capabilities mode hostdev in this kind of hypervisor */
280 if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_CAPABILITIES) {
281 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
282 _("hostdev mode 'capabilities' is not "
283 "supported in %s"),
284 virDomainVirtTypeToString(def->virtType));
285 return -1;
286 }
287
288 if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
289 hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI &&
290 pcisrc->backend == VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT)
291 pcisrc->backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN;
292 }
293
294 if (dev->type == VIR_DOMAIN_DEVICE_VIDEO) {
295 if (dev->data.video->type == VIR_DOMAIN_VIDEO_TYPE_DEFAULT) {
296 if (def->os.type == VIR_DOMAIN_OSTYPE_XEN ||
297 def->os.type == VIR_DOMAIN_OSTYPE_LINUX)
298 dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_XEN;
299 else if (ARCH_IS_PPC64(def->os.arch))
300 dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_VGA;
301 else
302 dev->data.video->type = VIR_DOMAIN_VIDEO_TYPE_CIRRUS;
303 }
304
305 if (def->os.type == VIR_DOMAIN_OSTYPE_HVM) {
306 int dm_type = libxlDomainGetEmulatorType(def);
307
308 switch (dev->data.video->type) {
309 case VIR_DOMAIN_VIDEO_TYPE_VGA:
310 case VIR_DOMAIN_VIDEO_TYPE_XEN:
311 if (dev->data.video->vram == 0) {
312 if (dm_type == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN)
313 dev->data.video->vram = 16 * 1024;
314 else
315 dev->data.video->vram = 8 * 1024;
316 }
317 break;
318 case VIR_DOMAIN_VIDEO_TYPE_CIRRUS:
319 if (dev->data.video->vram == 0) {
320 if (dm_type == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN)
321 dev->data.video->vram = 8 * 1024;
322 else
323 dev->data.video->vram = 4 * 1024;
324 }
325 break;
326 case VIR_DOMAIN_VIDEO_TYPE_QXL:
327 if (dev->data.video->vram == 0)
328 dev->data.video->vram = 128 * 1024;
329 break;
330 }
331 }
332 }
333
334 if (dev->type == VIR_DOMAIN_DEVICE_DISK) {
335 virDomainDiskDef *disk = dev->data.disk;
336 int actual_type = virStorageSourceGetActualType(disk->src);
337 int format = virDomainDiskGetFormat(disk);
338
339 /* for network-based disks, set 'qemu' as the default driver */
340 if (actual_type == VIR_STORAGE_TYPE_NETWORK) {
341 if (!virDomainDiskGetDriver(disk))
342 virDomainDiskSetDriver(disk, "qemu");
343 }
344
345 /* xl.cfg default format is raw. See xl-disk-configuration(5) */
346 if (format == VIR_STORAGE_FILE_NONE)
347 virDomainDiskSetFormat(disk, VIR_STORAGE_FILE_RAW);
348 }
349
350 return 0;
351 }
352
353 static int
libxlDomainDefPostParse(virDomainDef * def,unsigned int parseFlags G_GNUC_UNUSED,void * opaque G_GNUC_UNUSED,void * parseOpaque G_GNUC_UNUSED)354 libxlDomainDefPostParse(virDomainDef *def,
355 unsigned int parseFlags G_GNUC_UNUSED,
356 void *opaque G_GNUC_UNUSED,
357 void *parseOpaque G_GNUC_UNUSED)
358 {
359 /* Xen PV domains always have a PV console, so add one to the domain config
360 * via post-parse callback if not explicitly specified in the XML. */
361 if (def->os.type != VIR_DOMAIN_OSTYPE_HVM && def->nconsoles == 0) {
362 virDomainChrDef *chrdef;
363
364 if (!(chrdef = virDomainChrDefNew(NULL)))
365 return -1;
366
367 chrdef->source->type = VIR_DOMAIN_CHR_TYPE_PTY;
368 chrdef->deviceType = VIR_DOMAIN_CHR_DEVICE_TYPE_CONSOLE;
369 chrdef->target.port = 0;
370 chrdef->targetType = VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_XEN;
371
372 def->consoles = g_new0(virDomainChrDef *, 1);
373 def->nconsoles = 1;
374 def->consoles[0] = chrdef;
375 }
376
377 /* add implicit input devices */
378 if (xenDomainDefAddImplicitInputDevice(def) < 0)
379 return -1;
380
381 /* For x86_64 HVM */
382 if (def->os.type == VIR_DOMAIN_OSTYPE_HVM &&
383 def->os.arch == VIR_ARCH_X86_64) {
384 /* always enable pae */
385 def->features[VIR_DOMAIN_FEATURE_PAE] = VIR_TRISTATE_SWITCH_ON;
386
387 /* if vnuma is effective enable acpi */
388 if (virDomainNumaGetNodeCount(def->numa) > 0)
389 def->features[VIR_DOMAIN_FEATURE_ACPI] = VIR_TRISTATE_SWITCH_ON;
390 }
391
392 /* add implicit balloon device */
393 if (def->memballoon == NULL) {
394 virDomainMemballoonDef *memballoon;
395 memballoon = g_new0(virDomainMemballoonDef,
396 1);
397
398 memballoon->model = VIR_DOMAIN_MEMBALLOON_MODEL_XEN;
399 def->memballoon = memballoon;
400 }
401
402 /* add implicit xenbus device */
403 if (virDomainControllerFindByType(def, VIR_DOMAIN_CONTROLLER_TYPE_XENBUS) == -1)
404 if (virDomainDefAddController(def, VIR_DOMAIN_CONTROLLER_TYPE_XENBUS, -1, -1) == NULL)
405 return -1;
406
407 return 0;
408 }
409
410 static int
libxlDomainDefValidate(const virDomainDef * def,void * opaque,void * parseOpaque G_GNUC_UNUSED)411 libxlDomainDefValidate(const virDomainDef *def,
412 void *opaque,
413 void *parseOpaque G_GNUC_UNUSED)
414 {
415 libxlDriverPrivate *driver = opaque;
416 g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
417 bool reqSecureBoot = false;
418
419 if (!virCapabilitiesDomainSupported(cfg->caps, def->os.type,
420 def->os.arch,
421 def->virtType))
422 return -1;
423
424 /* Xen+ovmf does not support secure boot */
425 if (def->os.firmware == VIR_DOMAIN_OS_DEF_FIRMWARE_EFI) {
426 if (def->os.firmwareFeatures &&
427 def->os.firmwareFeatures[VIR_DOMAIN_OS_DEF_FIRMWARE_FEATURE_SECURE_BOOT])
428 reqSecureBoot = true;
429 }
430 if (virDomainDefHasOldStyleUEFI(def)) {
431 if (def->os.loader &&
432 def->os.loader->secure == VIR_TRISTATE_BOOL_YES)
433 reqSecureBoot = true;
434 }
435 if (reqSecureBoot) {
436 virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
437 _("Secure boot is not supported on Xen"));
438 return -1;
439 }
440
441 return 0;
442 }
443
444 virDomainDefParserConfig libxlDomainDefParserConfig = {
445 .macPrefix = { 0x00, 0x16, 0x3e },
446 .netPrefix = LIBXL_GENERATED_PREFIX_XEN,
447 .devicesPostParseCallback = libxlDomainDeviceDefPostParse,
448 .domainPostParseCallback = libxlDomainDefPostParse,
449 .domainValidateCallback = libxlDomainDefValidate,
450
451 .features = VIR_DOMAIN_DEF_FEATURE_FW_AUTOSELECT |
452 VIR_DOMAIN_DEF_FEATURE_NET_MODEL_STRING,
453 };
454
455
456 static void
libxlDomainShutdownHandleDestroy(libxlDriverPrivate * driver,virDomainObj * vm)457 libxlDomainShutdownHandleDestroy(libxlDriverPrivate *driver,
458 virDomainObj *vm)
459 {
460 libxlDomainDestroyInternal(driver, vm);
461 libxlDomainCleanup(driver, vm);
462 if (!vm->persistent)
463 virDomainObjListRemove(driver->domains, vm);
464 }
465
466
467 static void
libxlDomainShutdownHandleRestart(libxlDriverPrivate * driver,virDomainObj * vm)468 libxlDomainShutdownHandleRestart(libxlDriverPrivate *driver,
469 virDomainObj *vm)
470 {
471 libxlDomainDestroyInternal(driver, vm);
472 libxlDomainCleanup(driver, vm);
473 if (libxlDomainStartNew(driver, vm, false) < 0) {
474 VIR_ERROR(_("Failed to restart VM '%s': %s"),
475 vm->def->name, virGetLastErrorMessage());
476 }
477 }
478
479
480 struct libxlShutdownThreadInfo
481 {
482 libxlDriverPrivate *driver;
483 virDomainObj *vm;
484 libxl_event *event;
485 };
486
487
488 static void
libxlDomainShutdownThread(void * opaque)489 libxlDomainShutdownThread(void *opaque)
490 {
491 struct libxlShutdownThreadInfo *shutdown_info = opaque;
492 virDomainObj *vm = shutdown_info->vm;
493 libxl_event *ev = shutdown_info->event;
494 libxlDriverPrivate *driver = shutdown_info->driver;
495 virObjectEvent *dom_event = NULL;
496 libxl_shutdown_reason xl_reason = ev->u.domain_shutdown.shutdown_reason;
497 g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
498 libxl_domain_config d_config;
499
500 libxl_domain_config_init(&d_config);
501
502 if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
503 goto cleanup;
504
505 if (xl_reason == LIBXL_SHUTDOWN_REASON_POWEROFF) {
506 virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
507 VIR_DOMAIN_SHUTOFF_SHUTDOWN);
508
509 dom_event = virDomainEventLifecycleNewFromObj(vm,
510 VIR_DOMAIN_EVENT_STOPPED,
511 VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
512 switch ((virDomainLifecycleAction) vm->def->onPoweroff) {
513 case VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY:
514 libxlDomainShutdownHandleDestroy(driver, vm);
515 goto endjob;
516 case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART:
517 case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
518 libxlDomainShutdownHandleRestart(driver, vm);
519 goto endjob;
520 case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
521 case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
522 case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
523 case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
524 goto endjob;
525 }
526 } else if (xl_reason == LIBXL_SHUTDOWN_REASON_CRASH) {
527 virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
528 VIR_DOMAIN_SHUTOFF_CRASHED);
529
530 dom_event = virDomainEventLifecycleNewFromObj(vm,
531 VIR_DOMAIN_EVENT_STOPPED,
532 VIR_DOMAIN_EVENT_STOPPED_CRASHED);
533 switch ((virDomainLifecycleAction) vm->def->onCrash) {
534 case VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY:
535 libxlDomainShutdownHandleDestroy(driver, vm);
536 goto endjob;
537 case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART:
538 case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
539 libxlDomainShutdownHandleRestart(driver, vm);
540 goto endjob;
541 case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
542 case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
543 goto endjob;
544 case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
545 libxlDomainAutoCoreDump(driver, vm);
546 libxlDomainShutdownHandleDestroy(driver, vm);
547 goto endjob;
548 case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
549 libxlDomainAutoCoreDump(driver, vm);
550 libxlDomainShutdownHandleRestart(driver, vm);
551 goto endjob;
552 }
553 } else if (xl_reason == LIBXL_SHUTDOWN_REASON_REBOOT) {
554 virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
555 VIR_DOMAIN_SHUTOFF_SHUTDOWN);
556
557 dom_event = virDomainEventLifecycleNewFromObj(vm,
558 VIR_DOMAIN_EVENT_STOPPED,
559 VIR_DOMAIN_EVENT_STOPPED_SHUTDOWN);
560 switch ((virDomainLifecycleAction) vm->def->onReboot) {
561 case VIR_DOMAIN_LIFECYCLE_ACTION_DESTROY:
562 libxlDomainShutdownHandleDestroy(driver, vm);
563 goto endjob;
564 case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART:
565 case VIR_DOMAIN_LIFECYCLE_ACTION_RESTART_RENAME:
566 libxlDomainShutdownHandleRestart(driver, vm);
567 goto endjob;
568 case VIR_DOMAIN_LIFECYCLE_ACTION_PRESERVE:
569 case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_DESTROY:
570 case VIR_DOMAIN_LIFECYCLE_ACTION_COREDUMP_RESTART:
571 case VIR_DOMAIN_LIFECYCLE_ACTION_LAST:
572 goto endjob;
573 }
574 } else if (xl_reason == LIBXL_SHUTDOWN_REASON_SOFT_RESET) {
575 libxlDomainObjPrivate *priv = vm->privateData;
576
577 if (libxlRetrieveDomainConfigurationWrapper(cfg->ctx, vm->def->id,
578 &d_config) != 0) {
579 VIR_ERROR(_("Failed to retrieve config for VM '%s'. "
580 "Unable to perform soft reset. Destroying VM"),
581 vm->def->name);
582 libxlDomainShutdownHandleDestroy(driver, vm);
583 goto endjob;
584 }
585
586 if (priv->deathW) {
587 libxl_evdisable_domain_death(cfg->ctx, priv->deathW);
588 priv->deathW = NULL;
589 }
590
591 if (libxl_domain_soft_reset(cfg->ctx, &d_config, vm->def->id,
592 NULL, NULL) != 0) {
593 VIR_ERROR(_("Failed to soft reset VM '%s'. Destroying VM"),
594 vm->def->name);
595 libxlDomainShutdownHandleDestroy(driver, vm);
596 goto endjob;
597 }
598 libxl_evenable_domain_death(cfg->ctx, vm->def->id, 0, &priv->deathW);
599 libxlDomainUnpauseWrapper(cfg->ctx, vm->def->id);
600 } else {
601 VIR_INFO("Unhandled shutdown_reason %d", xl_reason);
602 }
603
604 endjob:
605 libxlDomainObjEndJob(driver, vm);
606
607 cleanup:
608 virDomainObjEndAPI(&vm);
609 virObjectEventStateQueue(driver->domainEventState, dom_event);
610 libxl_event_free(cfg->ctx, ev);
611 VIR_FREE(shutdown_info);
612 libxl_domain_config_dispose(&d_config);
613 }
614
615 static void
libxlDomainHandleDeath(libxlDriverPrivate * driver,virDomainObj * vm)616 libxlDomainHandleDeath(libxlDriverPrivate *driver, virDomainObj *vm)
617 {
618 virObjectEvent *dom_event = NULL;
619 libxlDomainObjPrivate *priv = vm->privateData;
620
621 if (priv->ignoreDeathEvent) {
622 priv->ignoreDeathEvent = false;
623 return;
624 }
625
626 if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
627 return;
628
629 virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_DESTROYED);
630 dom_event = virDomainEventLifecycleNewFromObj(vm,
631 VIR_DOMAIN_EVENT_STOPPED,
632 VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
633 libxlDomainCleanup(driver, vm);
634 if (!vm->persistent)
635 virDomainObjListRemove(driver->domains, vm);
636 libxlDomainObjEndJob(driver, vm);
637 virObjectEventStateQueue(driver->domainEventState, dom_event);
638 }
639
640
641 /*
642 * Handle previously registered domain event notification from libxenlight.
643 */
644 void
libxlDomainEventHandler(void * data,libxl_event * event)645 libxlDomainEventHandler(void *data, libxl_event *event)
646 {
647 libxlDriverPrivate *driver = data;
648 libxl_shutdown_reason xl_reason = event->u.domain_shutdown.shutdown_reason;
649 virDomainObj *vm = NULL;
650 g_autoptr(libxlDriverConfig) cfg = NULL;
651
652 VIR_DEBUG("Received libxl event '%d' for domid '%d'", event->type, event->domid);
653
654 if (event->type != LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN &&
655 event->type != LIBXL_EVENT_TYPE_DOMAIN_DEATH) {
656 VIR_INFO("Unhandled event type %d", event->type);
657 goto cleanup;
658 }
659
660 /*
661 * Similar to the xl implementation, ignore SUSPEND. Any actions needed
662 * after calling libxl_domain_suspend() are handled by its callers.
663 */
664 if (xl_reason == LIBXL_SHUTDOWN_REASON_SUSPEND)
665 goto cleanup;
666
667 vm = virDomainObjListFindByID(driver->domains, event->domid);
668 if (!vm) {
669 /* Nothing to do if we can't find the virDomainObj */
670 goto cleanup;
671 }
672
673 if (event->type == LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN) {
674 libxlDomainObjPrivate *priv = vm->privateData;
675 struct libxlShutdownThreadInfo *shutdown_info = NULL;
676 virThread thread;
677 g_autofree char *name = NULL;
678
679 /*
680 * Start a thread to handle shutdown. We don't want to be tying up
681 * libxl's event machinery by doing a potentially lengthy shutdown.
682 */
683 shutdown_info = g_new0(struct libxlShutdownThreadInfo, 1);
684
685 shutdown_info->driver = driver;
686 shutdown_info->vm = vm;
687 shutdown_info->event = (libxl_event *)event;
688 name = g_strdup_printf("ev-%d", event->domid);
689 /*
690 * Cleanup will be handled by the shutdown thread.
691 * Ignore the forthcoming death event from libxl
692 */
693 priv->ignoreDeathEvent = true;
694 if (virThreadCreateFull(&thread, false, libxlDomainShutdownThread,
695 name, false, shutdown_info) < 0) {
696 priv->ignoreDeathEvent = false;
697 /*
698 * Not much we can do on error here except log it.
699 */
700 VIR_ERROR(_("Failed to create thread to handle domain shutdown"));
701 VIR_FREE(shutdown_info);
702 goto cleanup;
703 }
704 /*
705 * virDomainObjEndAPI is called in the shutdown thread, where
706 * libxlShutdownThreadInfo and libxl_event are also freed.
707 */
708 return;
709 } else if (event->type == LIBXL_EVENT_TYPE_DOMAIN_DEATH) {
710 /*
711 * On death the domain is cleaned up from Xen's perspective.
712 * Cleanup on the libvirt side can be done synchronously.
713 */
714 libxlDomainHandleDeath(driver, vm);
715 }
716
717 cleanup:
718 virDomainObjEndAPI(&vm);
719 cfg = libxlDriverConfigGet(driver);
720 /* Cast away any const */
721 libxl_event_free(cfg->ctx, (libxl_event *)event);
722 }
723
724 char *
libxlDomainManagedSavePath(libxlDriverPrivate * driver,virDomainObj * vm)725 libxlDomainManagedSavePath(libxlDriverPrivate *driver, virDomainObj *vm)
726 {
727 char *ret;
728 g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
729
730 ret = g_strdup_printf("%s/%s.save", cfg->saveDir, vm->def->name);
731 return ret;
732 }
733
734 /*
735 * Open a saved image file and initialize domain definition from the header.
736 *
737 * Returns the opened fd on success, -1 on failure.
738 */
739 int
libxlDomainSaveImageOpen(libxlDriverPrivate * driver,const char * from,virDomainDef ** ret_def,libxlSavefileHeader * ret_hdr)740 libxlDomainSaveImageOpen(libxlDriverPrivate *driver,
741 const char *from,
742 virDomainDef **ret_def,
743 libxlSavefileHeader *ret_hdr)
744 {
745 int fd;
746 virDomainDef *def = NULL;
747 libxlSavefileHeader hdr;
748 g_autofree char *xml = NULL;
749
750 if ((fd = virFileOpenAs(from, O_RDONLY, 0, -1, -1, 0)) < 0) {
751 virReportSystemError(-fd,
752 _("Failed to open domain image file '%s'"), from);
753 goto error;
754 }
755
756 if (saferead(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
757 virReportError(VIR_ERR_OPERATION_FAILED,
758 "%s", _("failed to read libxl header"));
759 goto error;
760 }
761
762 if (memcmp(hdr.magic, LIBXL_SAVE_MAGIC, sizeof(hdr.magic))) {
763 virReportError(VIR_ERR_INVALID_ARG, "%s", _("image magic is incorrect"));
764 goto error;
765 }
766
767 if (hdr.version > LIBXL_SAVE_VERSION) {
768 virReportError(VIR_ERR_OPERATION_FAILED,
769 _("image version is not supported (%d > %d)"),
770 hdr.version, LIBXL_SAVE_VERSION);
771 goto error;
772 }
773
774 if (hdr.xmlLen <= 0) {
775 virReportError(VIR_ERR_OPERATION_FAILED,
776 _("invalid XML length: %d"), hdr.xmlLen);
777 goto error;
778 }
779
780 xml = g_new0(char, hdr.xmlLen);
781
782 if (saferead(fd, xml, hdr.xmlLen) != hdr.xmlLen) {
783 virReportError(VIR_ERR_OPERATION_FAILED, "%s", _("failed to read XML"));
784 goto error;
785 }
786
787 if (!(def = virDomainDefParseString(xml, driver->xmlopt, NULL,
788 VIR_DOMAIN_DEF_PARSE_INACTIVE |
789 VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
790 goto error;
791
792 *ret_def = def;
793 *ret_hdr = hdr;
794
795 return fd;
796
797 error:
798 virDomainDefFree(def);
799 VIR_FORCE_CLOSE(fd);
800 return -1;
801 }
802
803 static void
libxlNetworkUnwindDevices(virDomainDef * def)804 libxlNetworkUnwindDevices(virDomainDef *def)
805 {
806 if (def->nnets) {
807 size_t i;
808
809 for (i = 0; i < def->nnets; i++) {
810 virDomainNetDef *net = def->nets[i];
811
812 if (net->ifname &&
813 STRPREFIX(net->ifname, LIBXL_GENERATED_PREFIX_XEN))
814 VIR_FREE(net->ifname);
815
816 /* cleanup actual device */
817 virDomainNetRemoveHostdev(def, net);
818 if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
819 g_autoptr(virConnect) conn = virGetConnectNetwork();
820
821 if (conn)
822 virDomainNetReleaseActualDevice(conn, def, net);
823 else
824 VIR_WARN("Unable to release network device '%s'", NULLSTR(net->ifname));
825 }
826 }
827 }
828 }
829
830 int
libxlDomainHookRun(libxlDriverPrivate * driver,virDomainDef * def,unsigned int def_fmtflags,int hookop,int hooksubop,char ** output)831 libxlDomainHookRun(libxlDriverPrivate *driver,
832 virDomainDef *def,
833 unsigned int def_fmtflags,
834 int hookop,
835 int hooksubop,
836 char **output)
837 {
838 g_autofree char *xml = NULL;
839
840 if (!virHookPresent(VIR_HOOK_DRIVER_LIBXL))
841 return 0;
842
843 xml = virDomainDefFormat(def, driver->xmlopt, def_fmtflags);
844 return virHookCall(VIR_HOOK_DRIVER_LIBXL, def->name,
845 hookop, hooksubop,
846 NULL, xml, output);
847 }
848
849 /*
850 * Internal domain destroy function.
851 *
852 * virDomainObj *must be locked on invocation
853 */
854 int
libxlDomainDestroyInternal(libxlDriverPrivate * driver,virDomainObj * vm)855 libxlDomainDestroyInternal(libxlDriverPrivate *driver,
856 virDomainObj *vm)
857 {
858 g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
859 libxlDomainObjPrivate *priv = vm->privateData;
860 int ret = -1;
861
862 /* Ignore next LIBXL_EVENT_TYPE_DOMAIN_DEATH as the caller will handle
863 * domain death appropriately already (having more info, like the reason).
864 */
865 priv->ignoreDeathEvent = true;
866 /* Unlock virDomainObj during destroy, which can take considerable
867 * time on large memory domains.
868 */
869 virObjectUnlock(vm);
870 ret = libxl_domain_destroy(cfg->ctx, vm->def->id, NULL);
871 virObjectLock(vm);
872 if (ret)
873 priv->ignoreDeathEvent = false;
874
875 return ret;
876 }
877
878 /*
879 * Cleanup function for domain that has reached shutoff state.
880 *
881 * virDomainObj *must be locked on invocation
882 */
883 void
libxlDomainCleanup(libxlDriverPrivate * driver,virDomainObj * vm)884 libxlDomainCleanup(libxlDriverPrivate *driver,
885 virDomainObj *vm)
886 {
887 libxlDomainObjPrivate *priv = vm->privateData;
888 g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
889 int vnc_port;
890 char *file;
891 virHostdevManager *hostdev_mgr = driver->hostdevMgr;
892 unsigned int hostdev_flags = VIR_HOSTDEV_SP_PCI;
893
894 VIR_DEBUG("Cleaning up domain with id '%d' and name '%s'",
895 vm->def->id, vm->def->name);
896
897 hostdev_flags |= VIR_HOSTDEV_SP_USB;
898
899 /* Call hook with stopped operation. Ignore error and continue with cleanup */
900 ignore_value(libxlDomainHookRun(driver, vm->def, 0,
901 VIR_HOOK_LIBXL_OP_STOPPED,
902 VIR_HOOK_SUBOP_END, NULL));
903
904 virHostdevReAttachDomainDevices(hostdev_mgr, LIBXL_DRIVER_INTERNAL_NAME,
905 vm->def, hostdev_flags);
906
907 if (priv->lockProcessRunning) {
908 VIR_FREE(priv->lockState);
909 if (virDomainLockProcessPause(driver->lockManager, vm, &priv->lockState) < 0)
910 VIR_WARN("Unable to release lease on %s", vm->def->name);
911 else
912 priv->lockProcessRunning = false;
913 VIR_DEBUG("Preserving lock state '%s'", NULLSTR(priv->lockState));
914 }
915
916 libxlLoggerCloseFile(cfg->logger, vm->def->id);
917 vm->def->id = -1;
918
919 if (priv->deathW) {
920 libxl_evdisable_domain_death(cfg->ctx, priv->deathW);
921 priv->deathW = NULL;
922 }
923
924 priv->ignoreDeathEvent = false;
925
926 if (!!g_atomic_int_dec_and_test(&driver->nactive) && driver->inhibitCallback)
927 driver->inhibitCallback(false, driver->inhibitOpaque);
928
929 if ((vm->def->ngraphics == 1) &&
930 vm->def->graphics[0]->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
931 vm->def->graphics[0]->data.vnc.autoport) {
932 vnc_port = vm->def->graphics[0]->data.vnc.port;
933 if (vnc_port >= LIBXL_VNC_PORT_MIN) {
934 if (virPortAllocatorRelease(vnc_port) < 0)
935 VIR_DEBUG("Could not mark port %d as unused", vnc_port);
936 }
937 }
938
939 libxlNetworkUnwindDevices(vm->def);
940
941 file = g_strdup_printf("%s/%s.xml", cfg->stateDir, vm->def->name);
942 if (unlink(file) < 0 && errno != ENOENT && errno != ENOTDIR)
943 VIR_DEBUG("Failed to remove domain XML for %s", vm->def->name);
944 VIR_FREE(file);
945
946 /* Call hook with release operation. Ignore error and continue with cleanup */
947 ignore_value(libxlDomainHookRun(driver, vm->def, 0,
948 VIR_HOOK_LIBXL_OP_RELEASE,
949 VIR_HOOK_SUBOP_END, NULL));
950
951 virDomainObjRemoveTransientDef(vm);
952 }
953
954 /*
955 * Core dump domain to default dump path.
956 *
957 * virDomainObj *must be locked on invocation
958 */
959 int
libxlDomainAutoCoreDump(libxlDriverPrivate * driver,virDomainObj * vm)960 libxlDomainAutoCoreDump(libxlDriverPrivate *driver,
961 virDomainObj *vm)
962 {
963 g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
964 g_autoptr(GDateTime) now = g_date_time_new_now_local();
965 g_autofree char *nowstr = NULL;
966 g_autofree char *dumpfile = NULL;
967
968 nowstr = g_date_time_format(now, "%Y-%m-%d-%H:%M:%S");
969
970 dumpfile = g_strdup_printf("%s/%s-%s", cfg->autoDumpDir, vm->def->name,
971 nowstr);
972
973 /* Unlock virDomainObj while dumping core */
974 virObjectUnlock(vm);
975 libxl_domain_core_dump(cfg->ctx, vm->def->id, dumpfile, NULL);
976 virObjectLock(vm);
977
978 return 0;
979 }
980
981 static int
libxlDomainFreeMem(libxl_ctx * ctx,libxl_domain_config * d_config)982 libxlDomainFreeMem(libxl_ctx *ctx, libxl_domain_config *d_config)
983 {
984 uint64_t needed_mem;
985 uint64_t free_mem;
986 uint64_t target_mem;
987 int tries = 3;
988 int wait_secs = 10;
989
990 if (libxlDomainNeedMemoryWrapper(ctx, d_config, &needed_mem) < 0)
991 goto error;
992
993 do {
994 if (libxlGetFreeMemoryWrapper(ctx, &free_mem) < 0)
995 goto error;
996
997 if (free_mem >= needed_mem)
998 return 0;
999
1000 target_mem = free_mem - needed_mem;
1001 if (libxlSetMemoryTargetWrapper(ctx, 0, target_mem,
1002 /* relative */ 1, 0) < 0)
1003 goto error;
1004
1005 if (libxl_wait_for_memory_target(ctx, 0, wait_secs) < 0)
1006 goto error;
1007
1008 tries--;
1009 } while (tries > 0);
1010
1011 error:
1012 virReportError(VIR_ERR_OPERATION_FAILED, "%s",
1013 _("Failed to balloon domain0 memory"));
1014 return -1;
1015 }
1016
1017 static int
libxlNetworkPrepareDevices(virDomainDef * def)1018 libxlNetworkPrepareDevices(virDomainDef *def)
1019 {
1020 size_t i;
1021 g_autoptr(virConnect) conn = NULL;
1022
1023 for (i = 0; i < def->nnets; i++) {
1024 virDomainNetDef *net = def->nets[i];
1025 virDomainNetType actualType;
1026
1027 /* If appropriate, grab a physical device from the configured
1028 * network's pool of devices, or resolve bridge device name
1029 * to the one defined in the network definition.
1030 */
1031 if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
1032 if (!conn && !(conn = virGetConnectNetwork()))
1033 return -1;
1034 if (virDomainNetAllocateActualDevice(conn, def, net) < 0)
1035 return -1;
1036 }
1037
1038 /* final validation now that actual type is known */
1039 if (virDomainActualNetDefValidate(net) < 0)
1040 return -1;
1041
1042 actualType = virDomainNetGetActualType(net);
1043 if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV &&
1044 net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
1045 /* Each type='hostdev' network device must also have a
1046 * corresponding entry in the hostdevs array. For netdevs
1047 * that are hardcoded as type='hostdev', this is already
1048 * done by the parser, but for those allocated from a
1049 * network / determined at runtime, we need to do it
1050 * separately.
1051 */
1052 virDomainHostdevDef *hostdev = virDomainNetGetActualHostdev(net);
1053 virDomainHostdevSubsysPCI *pcisrc = &hostdev->source.subsys.u.pci;
1054
1055 if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
1056 hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
1057 pcisrc->backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN;
1058
1059 if (virDomainHostdevInsert(def, hostdev) < 0)
1060 return -1;
1061 }
1062 }
1063
1064 return 0;
1065 }
1066
1067 static void
libxlConsoleCallback(libxl_ctx * ctx,libxl_event * ev,void * for_callback)1068 libxlConsoleCallback(libxl_ctx *ctx, libxl_event *ev, void *for_callback)
1069 {
1070 virDomainObj *vm = for_callback;
1071 size_t i;
1072 virDomainChrDef *chr;
1073 char *console = NULL;
1074 int ret;
1075
1076 virObjectLock(vm);
1077 for (i = 0; i < vm->def->nconsoles; i++) {
1078 chr = vm->def->consoles[i];
1079
1080 if (i == 0 &&
1081 chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
1082 chr = vm->def->serials[0];
1083
1084 if (chr->source->type == VIR_DOMAIN_CHR_TYPE_PTY) {
1085 libxl_console_type console_type;
1086
1087 console_type =
1088 (chr->deviceType == VIR_DOMAIN_CHR_DEVICE_TYPE_SERIAL ?
1089 LIBXL_CONSOLE_TYPE_SERIAL : LIBXL_CONSOLE_TYPE_PV);
1090 ret = libxl_console_get_tty(ctx, ev->domid,
1091 chr->target.port, console_type,
1092 &console);
1093 if (!ret) {
1094 VIR_FREE(chr->source->data.file.path);
1095 if (console && console[0] != '\0')
1096 chr->source->data.file.path = g_strdup(console);
1097 }
1098 VIR_FREE(console);
1099 }
1100 }
1101 for (i = 0; i < vm->def->nserials; i++) {
1102 chr = vm->def->serials[i];
1103
1104 chr->info.alias = g_strdup_printf("serial%zd", i);
1105 if (chr->source->type == VIR_DOMAIN_CHR_TYPE_PTY) {
1106 if (chr->source->data.file.path)
1107 continue;
1108 ret = libxl_console_get_tty(ctx, ev->domid,
1109 chr->target.port,
1110 LIBXL_CONSOLE_TYPE_SERIAL,
1111 &console);
1112 if (!ret) {
1113 VIR_FREE(chr->source->data.file.path);
1114 if (console && console[0] != '\0')
1115 chr->source->data.file.path = g_strdup(console);
1116 }
1117 VIR_FREE(console);
1118 }
1119 }
1120 virObjectUnlock(vm);
1121 libxl_event_free(ctx, ev);
1122 }
1123
1124 /*
1125 * Create interface names for the network devices in parameter def.
1126 * Names are created with the pattern 'vif<domid>.<devid><suffix>'.
1127 * devid is extracted from the network devices in the d_config
1128 * parameter. User-provided interface names are skipped.
1129 */
1130 static void
libxlDomainCreateIfaceNames(virDomainDef * def,libxl_domain_config * d_config)1131 libxlDomainCreateIfaceNames(virDomainDef *def, libxl_domain_config *d_config)
1132 {
1133 size_t i;
1134
1135 for (i = 0; i < def->nnets && i < d_config->num_nics; i++) {
1136 virDomainNetDef *net = def->nets[i];
1137 libxl_device_nic *x_nic = &d_config->nics[i];
1138 const char *suffix =
1139 x_nic->nictype != LIBXL_NIC_TYPE_VIF ? "-emu" : "";
1140
1141 if (net->ifname)
1142 continue;
1143
1144 net->ifname = g_strdup_printf(LIBXL_GENERATED_PREFIX_XEN "%d.%d%s",
1145 def->id, x_nic->devid, suffix);
1146 }
1147 }
1148
1149 static void
libxlDomainUpdateDiskParams(virDomainDef * def,libxl_ctx * ctx)1150 libxlDomainUpdateDiskParams(virDomainDef *def, libxl_ctx *ctx)
1151 {
1152 libxl_device_disk *disks;
1153 int num_disks = 0;
1154 size_t i;
1155 int idx;
1156
1157 disks = libxl_device_disk_list(ctx, def->id, &num_disks);
1158 if (!disks)
1159 return;
1160
1161 for (i = 0; i < num_disks; i++) {
1162 if ((idx = virDomainDiskIndexByName(def, disks[i].vdev, false)) < 0)
1163 continue;
1164
1165 libxlUpdateDiskDef(def->disks[idx], &disks[i]);
1166 }
1167
1168 for (i = 0; i < num_disks; i++)
1169 libxl_device_disk_dispose(&disks[i]);
1170 VIR_FREE(disks);
1171 }
1172
1173 static void
libxlDomainCreateChannelPTY(virDomainDef * def,libxl_ctx * ctx)1174 libxlDomainCreateChannelPTY(virDomainDef *def, libxl_ctx *ctx)
1175 {
1176 libxl_device_channel *x_channels;
1177 virDomainChrDef *chr;
1178 size_t i;
1179 int nchannels;
1180
1181 x_channels = libxl_device_channel_list(ctx, def->id, &nchannels);
1182 if (!x_channels)
1183 return;
1184
1185 for (i = 0; i < def->nchannels; i++) {
1186 libxl_channelinfo channelinfo;
1187 int ret;
1188
1189 chr = def->channels[i];
1190 if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY)
1191 continue;
1192
1193 ret = libxl_device_channel_getinfo(ctx, def->id, &x_channels[i],
1194 &channelinfo);
1195
1196 if (!ret && channelinfo.u.pty.path &&
1197 *channelinfo.u.pty.path != '\0') {
1198 VIR_FREE(chr->source->data.file.path);
1199 chr->source->data.file.path = g_strdup(channelinfo.u.pty.path);
1200 }
1201 }
1202
1203 for (i = 0; i < nchannels; i++)
1204 libxl_device_channel_dispose(&x_channels[i]);
1205 }
1206
1207 static int
libxlDomainStartPrepare(libxlDriverPrivate * driver,virDomainObj * vm)1208 libxlDomainStartPrepare(libxlDriverPrivate *driver,
1209 virDomainObj *vm)
1210 {
1211 virHostdevManager *hostdev_mgr = driver->hostdevMgr;
1212 unsigned int hostdev_flags = VIR_HOSTDEV_SP_PCI | VIR_HOSTDEV_SP_USB;
1213
1214 if (virDomainObjSetDefTransient(driver->xmlopt, vm, NULL) < 0)
1215 return -1;
1216
1217 /* Run an early hook to set-up missing devices */
1218 if (libxlDomainHookRun(driver, vm->def, 0,
1219 VIR_HOOK_LIBXL_OP_PREPARE,
1220 VIR_HOOK_SUBOP_BEGIN, NULL) < 0)
1221 goto error;
1222
1223 if (virDomainLockProcessStart(driver->lockManager,
1224 "xen:///system",
1225 vm,
1226 true,
1227 NULL) < 0)
1228 goto error;
1229
1230 if (libxlNetworkPrepareDevices(vm->def) < 0)
1231 goto error;
1232
1233 if (virHostdevPrepareDomainDevices(hostdev_mgr, LIBXL_DRIVER_INTERNAL_NAME,
1234 vm->def, hostdev_flags) < 0)
1235 goto error;
1236
1237 return 0;
1238
1239 error:
1240 libxlNetworkUnwindDevices(vm->def);
1241 virHostdevReAttachDomainDevices(hostdev_mgr, LIBXL_DRIVER_INTERNAL_NAME,
1242 vm->def, hostdev_flags);
1243 virDomainObjRemoveTransientDef(vm);
1244 return -1;
1245 }
1246
1247 static int
libxlDomainStartPerform(libxlDriverPrivate * driver,virDomainObj * vm,bool start_paused,int restore_fd,uint32_t restore_ver)1248 libxlDomainStartPerform(libxlDriverPrivate *driver,
1249 virDomainObj *vm,
1250 bool start_paused,
1251 int restore_fd,
1252 uint32_t restore_ver)
1253 {
1254 libxl_domain_config d_config;
1255 int ret = -1;
1256 int libxlret = -1;
1257 uint32_t domid = 0;
1258 g_autofree char *dom_xml = NULL;
1259 libxlDomainObjPrivate *priv = vm->privateData;
1260 g_autoptr(libxlDriverConfig) cfg = libxlDriverConfigGet(driver);
1261 libxl_asyncprogress_how aop_console_how;
1262 libxl_domain_restore_params params;
1263 g_autofree char *config_json = NULL;
1264
1265 libxl_domain_config_init(&d_config);
1266
1267 if (libxlBuildDomainConfig(driver->reservedGraphicsPorts, vm->def,
1268 cfg, &d_config) < 0)
1269 goto cleanup;
1270
1271 if (cfg->autoballoon && libxlDomainFreeMem(cfg->ctx, &d_config) < 0)
1272 goto cleanup;
1273
1274 /* now that we know it is about to start call the hook if present */
1275 if (libxlDomainHookRun(driver, vm->def, 0,
1276 VIR_HOOK_LIBXL_OP_START,
1277 VIR_HOOK_SUBOP_BEGIN, NULL) < 0)
1278 goto cleanup;
1279
1280 if (priv->hookRun) {
1281 char uuidstr[VIR_UUID_STRING_BUFLEN];
1282 virUUIDFormat(vm->def->uuid, uuidstr);
1283
1284 VIR_WARN("Domain id='%d' name='%s' uuid='%s' is tainted: hook",
1285 vm->def->id,
1286 vm->def->name,
1287 uuidstr);
1288 }
1289
1290 /* Unlock virDomainObj while creating the domain */
1291 virObjectUnlock(vm);
1292
1293 aop_console_how.for_callback = vm;
1294 aop_console_how.callback = libxlConsoleCallback;
1295 if (restore_fd < 0) {
1296 libxlret = libxl_domain_create_new(cfg->ctx, &d_config,
1297 &domid, NULL, &aop_console_how);
1298 } else {
1299 libxl_domain_restore_params_init(¶ms);
1300 params.stream_version = restore_ver;
1301 libxlret = libxlDomainCreateRestoreWrapper(cfg->ctx, &d_config, &domid,
1302 restore_fd, ¶ms,
1303 &aop_console_how);
1304 libxl_domain_restore_params_dispose(¶ms);
1305 }
1306 virObjectLock(vm);
1307
1308 if (libxlret) {
1309 if (restore_fd < 0)
1310 virReportError(VIR_ERR_INTERNAL_ERROR,
1311 _("libxenlight failed to create new domain '%s'"),
1312 d_config.c_info.name);
1313 else
1314 virReportError(VIR_ERR_INTERNAL_ERROR,
1315 _("libxenlight failed to restore domain '%s'"),
1316 d_config.c_info.name);
1317 goto cleanup;
1318 }
1319
1320 /*
1321 * The domain has been successfully created with libxl, so it should
1322 * be cleaned up if there are any subsequent failures.
1323 */
1324 vm->def->id = domid;
1325 config_json = libxl_domain_config_to_json(cfg->ctx, &d_config);
1326
1327 libxlLoggerOpenFile(cfg->logger, domid, vm->def->name, config_json);
1328
1329 if (virDomainLockProcessResume(driver->lockManager,
1330 "xen:///system",
1331 vm,
1332 priv->lockState) < 0)
1333 goto destroy_dom;
1334 VIR_FREE(priv->lockState);
1335 priv->lockProcessRunning = true;
1336
1337 /* Always enable domain death events */
1338 if (libxl_evenable_domain_death(cfg->ctx, vm->def->id, 0, &priv->deathW))
1339 goto destroy_dom;
1340
1341 libxlDomainCreateIfaceNames(vm->def, &d_config);
1342 libxlDomainUpdateDiskParams(vm->def, cfg->ctx);
1343
1344 if (vm->def->nchannels > 0)
1345 libxlDomainCreateChannelPTY(vm->def, cfg->ctx);
1346
1347 if ((dom_xml = virDomainDefFormat(vm->def, driver->xmlopt, 0)) == NULL)
1348 goto destroy_dom;
1349
1350 if (libxl_userdata_store(cfg->ctx, domid, "libvirt-xml",
1351 (uint8_t *)dom_xml, strlen(dom_xml) + 1)) {
1352 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1353 _("libxenlight failed to store userdata"));
1354 goto destroy_dom;
1355 }
1356
1357 if (!start_paused) {
1358 libxlDomainUnpauseWrapper(cfg->ctx, domid);
1359 virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
1360 } else {
1361 virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
1362 }
1363
1364 if (virDomainObjSave(vm, driver->xmlopt, cfg->stateDir) < 0)
1365 goto destroy_dom;
1366
1367 /* finally we can call the 'started' hook script if any */
1368 if (libxlDomainHookRun(driver, vm->def, 0,
1369 VIR_HOOK_LIBXL_OP_STARTED,
1370 VIR_HOOK_SUBOP_BEGIN, NULL) < 0)
1371 goto destroy_dom;
1372
1373 ret = 0;
1374 goto cleanup;
1375
1376 destroy_dom:
1377 libxlDomainDestroyInternal(driver, vm);
1378 vm->def->id = -1;
1379 virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_FAILED);
1380
1381 cleanup:
1382 libxl_domain_config_dispose(&d_config);
1383 return ret;
1384 }
1385
1386 /*
1387 * Start a domain through libxenlight.
1388 *
1389 * virDomainObj must be locked and a job acquired on invocation
1390 */
1391 static int
libxlDomainStart(libxlDriverPrivate * driver,virDomainObj * vm,bool start_paused,int restore_fd,uint32_t restore_ver)1392 libxlDomainStart(libxlDriverPrivate *driver,
1393 virDomainObj *vm,
1394 bool start_paused,
1395 int restore_fd,
1396 uint32_t restore_ver)
1397 {
1398 virObjectEvent *event = NULL;
1399
1400 if (libxlDomainStartPrepare(driver, vm) < 0)
1401 return -1;
1402
1403 if (libxlDomainStartPerform(driver, vm, start_paused,
1404 restore_fd, restore_ver) < 0) {
1405 libxlDomainCleanup(driver, vm);
1406 return -1;
1407 }
1408
1409 if (g_atomic_int_add(&driver->nactive, 1) == 0 && driver->inhibitCallback)
1410 driver->inhibitCallback(true, driver->inhibitOpaque);
1411
1412 event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STARTED,
1413 restore_fd < 0 ?
1414 VIR_DOMAIN_EVENT_STARTED_BOOTED :
1415 VIR_DOMAIN_EVENT_STARTED_RESTORED);
1416 virObjectEventStateQueue(driver->domainEventState, event);
1417
1418 return 0;
1419 }
1420
1421 int
libxlDomainStartNew(libxlDriverPrivate * driver,virDomainObj * vm,bool start_paused)1422 libxlDomainStartNew(libxlDriverPrivate *driver,
1423 virDomainObj *vm,
1424 bool start_paused)
1425 {
1426 g_autofree char *managed_save_path = NULL;
1427 int restore_fd = -1;
1428 virDomainDef *def = NULL;
1429 libxlSavefileHeader hdr;
1430 uint32_t restore_ver = LIBXL_SAVE_VERSION;
1431 int ret = -1;
1432
1433 /* If there is a managed saved state restore it instead of starting
1434 * from scratch. The old state is removed once the restoring succeeded. */
1435 managed_save_path = libxlDomainManagedSavePath(driver, vm);
1436 if (managed_save_path == NULL)
1437 return -1;
1438
1439 if (virFileExists(managed_save_path)) {
1440 restore_fd = libxlDomainSaveImageOpen(driver, managed_save_path,
1441 &def, &hdr);
1442 if (restore_fd < 0)
1443 goto cleanup;
1444
1445 restore_ver = hdr.version;
1446
1447 if (STRNEQ(vm->def->name, def->name) ||
1448 memcmp(vm->def->uuid, def->uuid, VIR_UUID_BUFLEN)) {
1449 char vm_uuidstr[VIR_UUID_STRING_BUFLEN];
1450 char def_uuidstr[VIR_UUID_STRING_BUFLEN];
1451 virUUIDFormat(vm->def->uuid, vm_uuidstr);
1452 virUUIDFormat(def->uuid, def_uuidstr);
1453 virReportError(VIR_ERR_OPERATION_FAILED,
1454 _("cannot restore domain '%s' uuid %s from a file which belongs to domain '%s' uuid %s"),
1455 vm->def->name, vm_uuidstr, def->name, def_uuidstr);
1456 goto cleanup;
1457 }
1458
1459 virDomainObjAssignDef(vm, &def, true, NULL);
1460
1461 if (unlink(managed_save_path) < 0)
1462 VIR_WARN("Failed to remove the managed state %s",
1463 managed_save_path);
1464
1465 vm->hasManagedSave = false;
1466 }
1467
1468 ret = libxlDomainStart(driver, vm, start_paused, restore_fd, restore_ver);
1469
1470 cleanup:
1471 virDomainDefFree(def);
1472 VIR_FORCE_CLOSE(restore_fd);
1473 return ret;
1474 }
1475
1476 int
libxlDomainStartRestore(libxlDriverPrivate * driver,virDomainObj * vm,bool start_paused,int restore_fd,uint32_t restore_ver)1477 libxlDomainStartRestore(libxlDriverPrivate *driver,
1478 virDomainObj *vm,
1479 bool start_paused,
1480 int restore_fd,
1481 uint32_t restore_ver)
1482 {
1483 return libxlDomainStart(driver, vm, start_paused,
1484 restore_fd, restore_ver);
1485 }
1486
1487 bool
libxlDomainDefCheckABIStability(libxlDriverPrivate * driver,virDomainDef * src,virDomainDef * dst)1488 libxlDomainDefCheckABIStability(libxlDriverPrivate *driver,
1489 virDomainDef *src,
1490 virDomainDef *dst)
1491 {
1492 virDomainDef *migratableDefSrc = NULL;
1493 virDomainDef *migratableDefDst = NULL;
1494 bool ret = false;
1495
1496 if (!(migratableDefSrc = virDomainDefCopy(src, driver->xmlopt, NULL, true)) ||
1497 !(migratableDefDst = virDomainDefCopy(dst, driver->xmlopt, NULL, true)))
1498 goto cleanup;
1499
1500 ret = virDomainDefCheckABIStability(migratableDefSrc,
1501 migratableDefDst,
1502 driver->xmlopt);
1503
1504 cleanup:
1505 virDomainDefFree(migratableDefSrc);
1506 virDomainDefFree(migratableDefDst);
1507 return ret;
1508 }
1509
1510
1511 static void
libxlDomainDefNamespaceFree(void * nsdata)1512 libxlDomainDefNamespaceFree(void *nsdata)
1513 {
1514 libxlDomainXmlNsDef *def = nsdata;
1515
1516 if (!def)
1517 return;
1518
1519 g_strfreev(def->args);
1520 g_free(def);
1521 }
1522
1523
1524 static int
libxlDomainDefNamespaceParse(xmlXPathContextPtr ctxt,void ** data)1525 libxlDomainDefNamespaceParse(xmlXPathContextPtr ctxt,
1526 void **data)
1527 {
1528 libxlDomainXmlNsDef *nsdata = NULL;
1529 g_autofree xmlNodePtr *nodes = NULL;
1530 ssize_t nnodes;
1531 size_t i;
1532 int ret = -1;
1533
1534 if ((nnodes = virXPathNodeSet("./xen:commandline/xen:arg", ctxt, &nodes)) < 0)
1535 return -1;
1536
1537 if (nnodes == 0)
1538 return 0;
1539
1540 nsdata = g_new0(libxlDomainXmlNsDef, 1);
1541 nsdata->args = g_new0(char *, nnodes + 1);
1542
1543 for (i = 0; i < nnodes; i++) {
1544 if (!(nsdata->args[nsdata->num_args++] = virXMLPropString(nodes[i], "value"))) {
1545 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1546 _("No device model command-line argument specified"));
1547 goto cleanup;
1548 }
1549 }
1550
1551 *data = g_steal_pointer(&nsdata);
1552 ret = 0;
1553
1554 cleanup:
1555 libxlDomainDefNamespaceFree(nsdata);
1556 return ret;
1557 }
1558
1559
1560 static int
libxlDomainDefNamespaceFormatXML(virBuffer * buf,void * nsdata)1561 libxlDomainDefNamespaceFormatXML(virBuffer *buf,
1562 void *nsdata)
1563 {
1564 libxlDomainXmlNsDef *cmd = nsdata;
1565 size_t i;
1566
1567 if (!cmd->num_args)
1568 return 0;
1569
1570 virBufferAddLit(buf, "<xen:commandline>\n");
1571 virBufferAdjustIndent(buf, 2);
1572
1573 for (i = 0; i < cmd->num_args; i++)
1574 virBufferEscapeString(buf, "<xen:arg value='%s'/>\n",
1575 cmd->args[i]);
1576
1577 virBufferAdjustIndent(buf, -2);
1578 virBufferAddLit(buf, "</xen:commandline>\n");
1579
1580 return 0;
1581 }
1582
1583
1584 virXMLNamespace libxlDriverDomainXMLNamespace = {
1585 .parse = libxlDomainDefNamespaceParse,
1586 .free = libxlDomainDefNamespaceFree,
1587 .format = libxlDomainDefNamespaceFormatXML,
1588 .prefix = "xen",
1589 .uri = "http://libvirt.org/schemas/domain/xen/1.0",
1590 };
1591