libxl_driver.c 148.6 KB
Newer Older
1 2 3
/*
 * libxl_driver.c: core driver methods for managing libxenlight domains
 *
4
 * Copyright (C) 2006-2014 Red Hat, Inc.
5
 * Copyright (C) 2011-2015 SUSE LINUX Products GmbH, Nuernberg, Germany.
6
 * Copyright (C) 2011 Univention GmbH.
J
Jim Fehlig 已提交
7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
19
 * License along with this library.  If not, see
O
Osier Yang 已提交
20
 * <http://www.gnu.org/licenses/>.
M
Markus Groß 已提交
21 22 23 24 25
 *
 * Authors:
 *     Jim Fehlig <jfehlig@novell.com>
 *     Markus Groß <gross@univention.de>
 *     Daniel P. Berrange <berrange@redhat.com>
J
Jim Fehlig 已提交
26 27 28 29
 */

#include <config.h>

30
#include <math.h>
J
Jim Fehlig 已提交
31
#include <libxl.h>
32
#include <libxl_utils.h>
33
#include <fcntl.h>
34
#include <regex.h>
J
Jim Fehlig 已提交
35 36

#include "internal.h"
37
#include "virlog.h"
38
#include "virerror.h"
39
#include "virconf.h"
J
Jim Fehlig 已提交
40
#include "datatypes.h"
E
Eric Blake 已提交
41
#include "virfile.h"
42
#include "viralloc.h"
43
#include "viruuid.h"
44
#include "vircommand.h"
J
Jim Fehlig 已提交
45
#include "libxl_domain.h"
J
Jim Fehlig 已提交
46 47
#include "libxl_driver.h"
#include "libxl_conf.h"
J
Jim Fehlig 已提交
48
#include "libxl_migration.h"
49
#include "xen_xm.h"
50
#include "xen_sxpr.h"
51
#include "xen_xl.h"
52
#include "virtypedparam.h"
M
Martin Kletzander 已提交
53
#include "viruri.h"
54
#include "virstring.h"
55
#include "virsysinfo.h"
56
#include "viraccessapicheck.h"
57
#include "viratomic.h"
58
#include "virhostdev.h"
59
#include "network/bridge_driver.h"
J
Jim Fehlig 已提交
60 61 62

#define VIR_FROM_THIS VIR_FROM_LIBXL

63 64
VIR_LOG_INIT("libxl.libxl_driver");

J
Jim Fehlig 已提交
65 66 67 68 69 70
#define LIBXL_DOM_REQ_POWEROFF 0
#define LIBXL_DOM_REQ_REBOOT   1
#define LIBXL_DOM_REQ_SUSPEND  2
#define LIBXL_DOM_REQ_CRASH    3
#define LIBXL_DOM_REQ_HALT     4

71
#define LIBXL_CONFIG_FORMAT_XL "xen-xl"
72
#define LIBXL_CONFIG_FORMAT_XM "xen-xm"
73
#define LIBXL_CONFIG_FORMAT_SEXPR "xen-sxpr"
74

75 76
#define HYPERVISOR_CAPABILITIES "/proc/xen/capabilities"

77 78 79
/* Number of Xen scheduler parameters */
#define XEN_SCHED_CREDIT_NPARAM   2

80

81
static libxlDriverPrivatePtr libxl_driver;
J
Jim Fehlig 已提交
82

83 84 85 86 87 88 89 90 91
/* Object used to store info related to libxl event registrations */
typedef struct _libxlOSEventHookInfo libxlOSEventHookInfo;
typedef libxlOSEventHookInfo *libxlOSEventHookInfoPtr;
struct _libxlOSEventHookInfo {
    libxl_ctx *ctx;
    void *xl_priv;
    int id;
};

J
Jim Fehlig 已提交
92
/* Function declarations */
93 94
static int
libxlDomainManagedSaveLoad(virDomainObjPtr vm,
95 96
                           void *opaque);

J
Jim Fehlig 已提交
97 98

/* Function definitions */
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
static void
libxlOSEventHookInfoFree(void *obj)
{
    VIR_FREE(obj);
}

static void
libxlFDEventCallback(int watch ATTRIBUTE_UNUSED,
                     int fd,
                     int vir_events,
                     void *fd_info)
{
    libxlOSEventHookInfoPtr info = fd_info;
    int events = 0;

    if (vir_events & VIR_EVENT_HANDLE_READABLE)
        events |= POLLIN;
    if (vir_events & VIR_EVENT_HANDLE_WRITABLE)
        events |= POLLOUT;
    if (vir_events & VIR_EVENT_HANDLE_ERROR)
        events |= POLLERR;
    if (vir_events & VIR_EVENT_HANDLE_HANGUP)
        events |= POLLHUP;

    libxl_osevent_occurred_fd(info->ctx, info->xl_priv, fd, 0, events);
}

static int
libxlFDRegisterEventHook(void *priv,
                         int fd,
                         void **hndp,
                         short events,
                         void *xl_priv)
{
    int vir_events = VIR_EVENT_HANDLE_ERROR;
    libxlOSEventHookInfoPtr info;

    if (VIR_ALLOC(info) < 0)
        return -1;

    info->ctx = priv;
    info->xl_priv = xl_priv;

    if (events & POLLIN)
        vir_events |= VIR_EVENT_HANDLE_READABLE;
    if (events & POLLOUT)
        vir_events |= VIR_EVENT_HANDLE_WRITABLE;

    info->id = virEventAddHandle(fd, vir_events, libxlFDEventCallback,
                                 info, libxlOSEventHookInfoFree);
    if (info->id < 0) {
        VIR_FREE(info);
        return -1;
    }

    *hndp = info;

    return 0;
}

static int
libxlFDModifyEventHook(void *priv ATTRIBUTE_UNUSED,
                       int fd ATTRIBUTE_UNUSED,
                       void **hndp,
                       short events)
{
    libxlOSEventHookInfoPtr info = *hndp;
    int vir_events = VIR_EVENT_HANDLE_ERROR;

    if (events & POLLIN)
        vir_events |= VIR_EVENT_HANDLE_READABLE;
    if (events & POLLOUT)
        vir_events |= VIR_EVENT_HANDLE_WRITABLE;

    virEventUpdateHandle(info->id, vir_events);

    return 0;
}

static void
libxlFDDeregisterEventHook(void *priv ATTRIBUTE_UNUSED,
                           int fd ATTRIBUTE_UNUSED,
                           void *hnd)
{
    libxlOSEventHookInfoPtr info = hnd;

    virEventRemoveHandle(info->id);
}

static void
libxlTimerCallback(int timer ATTRIBUTE_UNUSED, void *timer_info)
{
    libxlOSEventHookInfoPtr info = timer_info;

    /*
     * libxl expects the event to be deregistered when calling
     * libxl_osevent_occurred_timeout, but we dont want the event info
     * destroyed.  Disable the timeout and only remove it after returning
     * from libxl.
     */
    virEventUpdateTimeout(info->id, -1);
    libxl_osevent_occurred_timeout(info->ctx, info->xl_priv);
    virEventRemoveTimeout(info->id);
}

static int
libxlTimeoutRegisterEventHook(void *priv,
                              void **hndp,
                              struct timeval abs_t,
                              void *xl_priv)
{
    libxlOSEventHookInfoPtr info;
    struct timeval now;
    struct timeval res;
    static struct timeval zero;
    int timeout;

    if (VIR_ALLOC(info) < 0)
        return -1;

    info->ctx = priv;
    info->xl_priv = xl_priv;

    gettimeofday(&now, NULL);
    timersub(&abs_t, &now, &res);
    /* Ensure timeout is not overflowed */
    if (timercmp(&res, &zero, <)) {
        timeout = 0;
    } else if (res.tv_sec > INT_MAX / 1000) {
        timeout = INT_MAX;
    } else {
        timeout = res.tv_sec * 1000 + (res.tv_usec + 999) / 1000;
    }
    info->id = virEventAddTimeout(timeout, libxlTimerCallback,
                                  info, libxlOSEventHookInfoFree);
    if (info->id < 0) {
        VIR_FREE(info);
        return -1;
    }

    *hndp = info;

    return 0;
}

/*
 * Note:  There are two changes wrt timeouts starting with xen-unstable
 * changeset 26469:
 *
 * 1. Timeout modify callbacks will only be invoked with an abs_t of {0,0},
 * i.e. make the timeout fire immediately.  Prior to this commit, timeout
 * modify callbacks were never invoked.
 *
 * 2. Timeout deregister hooks will no longer be called.
 */
static int
libxlTimeoutModifyEventHook(void *priv ATTRIBUTE_UNUSED,
                            void **hndp,
                            struct timeval abs_t ATTRIBUTE_UNUSED)
{
    libxlOSEventHookInfoPtr info = *hndp;

    /* Make the timeout fire */
    virEventUpdateTimeout(info->id, 0);

    return 0;
}

static void
libxlTimeoutDeregisterEventHook(void *priv ATTRIBUTE_UNUSED,
                                void *hnd)
{
    libxlOSEventHookInfoPtr info = hnd;

    virEventRemoveTimeout(info->id);
}

J
Jim Fehlig 已提交
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
static virDomainObjPtr
libxlDomObjFromDomain(virDomainPtr dom)
{
    virDomainObjPtr vm;
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

    vm = virDomainObjListFindByUUID(driver->domains, dom->uuid);
    if (!vm) {
        virUUIDFormat(dom->uuid, uuidstr);
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s' (%s)"),
                       uuidstr, dom->name);
        return NULL;
    }

    return vm;
}

295 296
static int
libxlAutostartDomain(virDomainObjPtr vm,
297 298 299 300
                     void *opaque)
{
    libxlDriverPrivatePtr driver = opaque;
    virErrorPtr err;
301
    int ret = -1;
302

303
    virObjectLock(vm);
304 305 306
    virResetLastError();

    if (vm->autostart && !virDomainObjIsActive(vm) &&
307
        libxlDomainStart(driver, vm, false, -1) < 0) {
308 309 310 311
        err = virGetLastError();
        VIR_ERROR(_("Failed to autostart VM '%s': %s"),
                  vm->def->name,
                  err ? err->message : _("unknown error"));
312
        goto cleanup;
313 314
    }

315
    ret = 0;
316
 cleanup:
317
    virObjectUnlock(vm);
318
    return ret;
319 320
}

J
Jim Fehlig 已提交
321 322 323 324
/*
 * Reconnect to running domains that were previously started/created
 * with libxenlight driver.
 */
325 326
static int
libxlReconnectDomain(virDomainObjPtr vm,
J
Jim Fehlig 已提交
327 328 329
                     void *opaque)
{
    libxlDriverPrivatePtr driver = opaque;
330
    libxlDomainObjPrivatePtr priv = vm->privateData;
J
Jim Fehlig 已提交
331 332 333 334
    int rc;
    libxl_dominfo d_info;
    int len;
    uint8_t *data = NULL;
335
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
J
Jim Fehlig 已提交
336

337
    virObjectLock(vm);
J
Jim Fehlig 已提交
338

339
    libxlDomainObjPrivateInitCtx(vm);
J
Jim Fehlig 已提交
340
    /* Does domain still exist? */
341
    rc = libxl_domain_info(priv->ctx, &d_info, vm->def->id);
J
Jim Fehlig 已提交
342 343 344 345 346 347 348 349 350
    if (rc == ERROR_INVAL) {
        goto out;
    } else if (rc != 0) {
        VIR_DEBUG("libxl_domain_info failed (code %d), ignoring domain %d",
                  rc, vm->def->id);
        goto out;
    }

    /* Is this a domain that was under libvirt control? */
351
    if (libxl_userdata_retrieve(priv->ctx, vm->def->id,
J
Jim Fehlig 已提交
352 353 354 355 356 357 358
                                "libvirt-xml", &data, &len)) {
        VIR_DEBUG("libxl_userdata_retrieve failed, ignoring domain %d", vm->def->id);
        goto out;
    }

    /* Update domid in case it changed (e.g. reboot) while we were gone? */
    vm->def->id = d_info.domid;
359 360 361 362 363 364

    /* Update hostdev state */
    if (virHostdevUpdateDomainActiveDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                            vm->def, VIR_HOSTDEV_SP_PCI) < 0)
        goto out;

J
Jiri Denemark 已提交
365
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_UNKNOWN);
J
Jim Fehlig 已提交
366

367
    if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback)
368 369
        driver->inhibitCallback(true, driver->inhibitOpaque);

370
    /* Re-register domain death et. al. events */
371
    libxlDomainEventsRegister(driver, vm);
372
    virObjectUnlock(vm);
373
    return 0;
J
Jim Fehlig 已提交
374

375
 out:
376
    libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_UNKNOWN);
J
Jim Fehlig 已提交
377
    if (!vm->persistent)
378
        virDomainObjListRemoveLocked(driver->domains, vm);
J
Jim Fehlig 已提交
379
    else
380
        virObjectUnlock(vm);
381 382

    return -1;
J
Jim Fehlig 已提交
383 384 385 386 387
}

static void
libxlReconnectDomains(libxlDriverPrivatePtr driver)
{
388
    virDomainObjListForEach(driver->domains, libxlReconnectDomain, driver);
J
Jim Fehlig 已提交
389 390 391
}

static int
392
libxlStateCleanup(void)
J
Jim Fehlig 已提交
393 394 395 396
{
    if (!libxl_driver)
        return -1;

397
    virObjectUnref(libxl_driver->hostdevMgr);
398
    virObjectUnref(libxl_driver->config);
399
    virObjectUnref(libxl_driver->xmlopt);
400
    virObjectUnref(libxl_driver->domains);
401
    virObjectUnref(libxl_driver->reservedVNCPorts);
J
Jim Fehlig 已提交
402
    virObjectUnref(libxl_driver->migrationPorts);
J
Jim Fehlig 已提交
403

404
    virObjectEventStateFree(libxl_driver->domainEventState);
405
    virSysinfoDefFree(libxl_driver->hostsysinfo);
406

J
Jim Fehlig 已提交
407 408 409 410 411 412
    virMutexDestroy(&libxl_driver->lock);
    VIR_FREE(libxl_driver);

    return 0;
}

413 414
static bool
libxlDriverShouldLoad(bool privileged)
415
{
416 417
    bool ret = false;
    int status;
418
    char *output = NULL;
J
Jim Fehlig 已提交
419

420
    /* Don't load if non-root */
J
Jim Fehlig 已提交
421
    if (!privileged) {
422
        VIR_INFO("Not running privileged, disabling libxenlight driver");
423
        return ret;
J
Jim Fehlig 已提交
424 425
    }

426 427 428
    if (!virFileExists(HYPERVISOR_CAPABILITIES)) {
        VIR_INFO("Disabling driver as " HYPERVISOR_CAPABILITIES
                 " does not exist");
429
        return ret;
430
    }
431 432 433 434 435
    /*
     * Don't load if not running on a Xen control domain (dom0). It is not
     * sufficient to check for the file to exist as any guest can mount
     * xenfs to /proc/xen.
     */
436
    status = virFileReadAll(HYPERVISOR_CAPABILITIES, 10, &output);
437
    if (status >= 0)
438 439 440
        status = strncmp(output, "control_d", 9);
    VIR_FREE(output);
    if (status) {
441 442 443 444 445 446 447
        VIR_INFO("No Xen capabilities detected, probably not running "
                 "in a Xen Dom0.  Disabling libxenlight driver");

        return ret;
    }

    /* Don't load if legacy xen toolstack (xend) is in use */
448 449 450 451 452 453 454 455 456 457 458
    if (virFileExists("/usr/sbin/xend")) {
        virCommandPtr cmd;

        cmd = virCommandNewArgList("/usr/sbin/xend", "status", NULL);
        if (virCommandRun(cmd, NULL) == 0) {
            VIR_INFO("Legacy xen tool stack seems to be in use, disabling "
                     "libxenlight driver.");
        } else {
            ret = true;
        }
        virCommandFree(cmd);
459 460
    } else {
        ret = true;
J
Jim Fehlig 已提交
461 462
    }

463 464 465
    return ret;
}

466 467 468 469 470 471 472 473 474 475
/* Callbacks wrapping libvirt's event loop interface */
static const libxl_osevent_hooks libxl_osevent_callbacks = {
    .fd_register = libxlFDRegisterEventHook,
    .fd_modify = libxlFDModifyEventHook,
    .fd_deregister = libxlFDDeregisterEventHook,
    .timeout_register = libxlTimeoutRegisterEventHook,
    .timeout_modify = libxlTimeoutModifyEventHook,
    .timeout_deregister = libxlTimeoutDeregisterEventHook,
};

476 477 478 479 480 481 482 483
static const libxl_childproc_hooks libxl_child_hooks = {
#ifdef LIBXL_HAVE_SIGCHLD_OWNER_SELECTIVE_REAP
    .chldowner = libxl_sigchld_owner_libxl_always_selective_reap,
#else
    .chldowner = libxl_sigchld_owner_libxl,
#endif
};

484 485 486 487 488 489
const struct libxl_event_hooks ev_hooks = {
    .event_occurs_mask = LIBXL_EVENTMASK_ALL,
    .event_occurs = libxlDomainEventHandler,
    .disaster = NULL,
};

490 491 492 493 494
static int
libxlStateInitialize(bool privileged,
                     virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                     void *opaque ATTRIBUTE_UNUSED)
{
495
    libxlDriverConfigPtr cfg;
496 497 498 499 500
    char ebuf[1024];

    if (!libxlDriverShouldLoad(privileged))
        return 0;

J
Jim Fehlig 已提交
501 502 503 504
    if (VIR_ALLOC(libxl_driver) < 0)
        return -1;

    if (virMutexInit(&libxl_driver->lock) < 0) {
505 506
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot initialize mutex"));
J
Jim Fehlig 已提交
507 508 509 510 511
        VIR_FREE(libxl_driver);
        return -1;
    }

    /* Allocate bitmap for vnc port reservation */
512
    if (!(libxl_driver->reservedVNCPorts =
J
Ján Tomko 已提交
513 514
          virPortAllocatorNew(_("VNC"),
                              LIBXL_VNC_PORT_MIN,
515 516
                              LIBXL_VNC_PORT_MAX,
                              0)))
517
        goto error;
J
Jim Fehlig 已提交
518

J
Jim Fehlig 已提交
519 520 521 522
    /* Allocate bitmap for migration port reservation */
    if (!(libxl_driver->migrationPorts =
          virPortAllocatorNew(_("migration"),
                              LIBXL_MIGRATION_PORT_MIN,
523
                              LIBXL_MIGRATION_PORT_MAX, 0)))
J
Jim Fehlig 已提交
524 525
        goto error;

526 527
    if (!(libxl_driver->domains = virDomainObjListNew()))
        goto error;
J
Jim Fehlig 已提交
528

529 530 531
    if (!(libxl_driver->hostdevMgr = virHostdevManagerGetDefault()))
        goto error;

532
    if (!(cfg = libxlDriverConfigNew()))
533
        goto error;
J
Jim Fehlig 已提交
534

535 536 537
    /* Register the callbacks providing access to libvirt's event loop */
    libxl_osevent_register_hooks(cfg->ctx, &libxl_osevent_callbacks, cfg->ctx);

538 539 540
    /* Setup child process handling.  See $xen-src/tools/libxl/libxl_event.h */
    libxl_childproc_setmode(cfg->ctx, &libxl_child_hooks, cfg->ctx);

541 542 543
    /* Register callback to handle domain events */
    libxl_event_register_callbacks(cfg->ctx, &ev_hooks, libxl_driver);

544 545
    libxl_driver->config = cfg;
    if (virFileMakePath(cfg->stateDir) < 0) {
546 547
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create state dir '%s': %s"),
548
                       cfg->stateDir,
549
                       virStrerror(errno, ebuf, sizeof(ebuf)));
J
Jim Fehlig 已提交
550 551
        goto error;
    }
552
    if (virFileMakePath(cfg->libDir) < 0) {
553 554
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create lib dir '%s': %s"),
555
                       cfg->libDir,
556
                       virStrerror(errno, ebuf, sizeof(ebuf)));
J
Jim Fehlig 已提交
557 558
        goto error;
    }
559
    if (virFileMakePath(cfg->saveDir) < 0) {
560 561
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create save dir '%s': %s"),
562
                       cfg->saveDir,
563
                       virStrerror(errno, ebuf, sizeof(ebuf)));
J
Jim Fehlig 已提交
564 565
        goto error;
    }
566 567 568 569 570 571 572
    if (virFileMakePath(cfg->autoDumpDir) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create dump dir '%s': %s"),
                       cfg->autoDumpDir,
                       virStrerror(errno, ebuf, sizeof(ebuf)));
        goto error;
    }
J
Jim Fehlig 已提交
573

574
    /* read the host sysinfo */
575
    libxl_driver->hostsysinfo = virSysinfoRead();
576

577
    libxl_driver->domainEventState = virObjectEventStateNew();
E
Eric Blake 已提交
578
    if (!libxl_driver->domainEventState)
579 580
        goto error;

581
    if ((cfg->caps = libxlMakeCapabilities(cfg->ctx)) == NULL) {
582 583
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot create capabilities for libxenlight"));
J
Jim Fehlig 已提交
584 585 586
        goto error;
    }

587
    if (!(libxl_driver->xmlopt = libxlCreateXMLConf()))
588
        goto error;
J
Jim Fehlig 已提交
589 590

    /* Load running domains first. */
591
    if (virDomainObjListLoadAllConfigs(libxl_driver->domains,
592 593
                                       cfg->stateDir,
                                       cfg->autostartDir,
594
                                       1,
595
                                       cfg->caps,
596 597
                                       libxl_driver->xmlopt,
                                       1 << VIR_DOMAIN_VIRT_XEN,
598
                                       NULL, NULL) < 0)
J
Jim Fehlig 已提交
599 600 601 602 603
        goto error;

    libxlReconnectDomains(libxl_driver);

    /* Then inactive persistent configs */
604
    if (virDomainObjListLoadAllConfigs(libxl_driver->domains,
605 606
                                       cfg->configDir,
                                       cfg->autostartDir,
607
                                       0,
608
                                       cfg->caps,
609 610
                                       libxl_driver->xmlopt,
                                       1 << VIR_DOMAIN_VIRT_XEN,
611
                                       NULL, NULL) < 0)
J
Jim Fehlig 已提交
612 613
        goto error;

614 615
    virDomainObjListForEach(libxl_driver->domains, libxlDomainManagedSaveLoad,
                            libxl_driver);
616

J
Jim Fehlig 已提交
617 618
    return 0;

619
 error:
620
    libxlStateCleanup();
621
    return -1;
J
Jim Fehlig 已提交
622 623
}

624 625 626 627 628 629 630 631 632 633
static void
libxlStateAutoStart(void)
{
    if (!libxl_driver)
        return;

    virDomainObjListForEach(libxl_driver->domains, libxlAutostartDomain,
                            libxl_driver);
}

J
Jim Fehlig 已提交
634
static int
635
libxlStateReload(void)
J
Jim Fehlig 已提交
636
{
637 638
    libxlDriverConfigPtr cfg;

J
Jim Fehlig 已提交
639 640 641
    if (!libxl_driver)
        return 0;

642 643
    cfg = libxlDriverConfigGet(libxl_driver);

644
    virDomainObjListLoadAllConfigs(libxl_driver->domains,
645 646
                                   cfg->configDir,
                                   cfg->autostartDir,
647
                                   1,
648
                                   cfg->caps,
649 650
                                   libxl_driver->xmlopt,
                                   1 << VIR_DOMAIN_VIRT_XEN,
651 652
                                   NULL, libxl_driver);

653 654
    virDomainObjListForEach(libxl_driver->domains, libxlAutostartDomain,
                            libxl_driver);
655

656
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
657 658 659 660 661
    return 0;
}


static virDrvOpenStatus
662 663 664
libxlConnectOpen(virConnectPtr conn,
                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                 unsigned int flags)
J
Jim Fehlig 已提交
665
{
E
Eric Blake 已提交
666 667
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

J
Jim Fehlig 已提交
668 669 670 671
    if (conn->uri == NULL) {
        if (libxl_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;

672
        if (!(conn->uri = virURIParse("xen:///")))
J
Jim Fehlig 已提交
673 674 675 676 677 678 679 680 681 682 683 684
            return VIR_DRV_OPEN_ERROR;
    } else {
        /* Only xen scheme */
        if (conn->uri->scheme == NULL || STRNEQ(conn->uri->scheme, "xen"))
            return VIR_DRV_OPEN_DECLINED;

        /* If server name is given, its for remote driver */
        if (conn->uri->server != NULL)
            return VIR_DRV_OPEN_DECLINED;

        /* Error if xen or libxl scheme specified but driver not started. */
        if (libxl_driver == NULL) {
685 686
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("libxenlight state driver is not active"));
J
Jim Fehlig 已提交
687 688 689 690 691 692 693 694
            return VIR_DRV_OPEN_ERROR;
        }

        /* /session isn't supported in libxenlight */
        if (conn->uri->path &&
            STRNEQ(conn->uri->path, "") &&
            STRNEQ(conn->uri->path, "/") &&
            STRNEQ(conn->uri->path, "/system")) {
695 696 697
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected Xen URI path '%s', try xen:///"),
                           NULLSTR(conn->uri->path));
J
Jim Fehlig 已提交
698 699 700 701
            return VIR_DRV_OPEN_ERROR;
        }
    }

702 703 704
    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

J
Jim Fehlig 已提交
705 706 707 708 709 710
    conn->privateData = libxl_driver;

    return VIR_DRV_OPEN_SUCCESS;
};

static int
711
libxlConnectClose(virConnectPtr conn ATTRIBUTE_UNUSED)
J
Jim Fehlig 已提交
712 713 714 715 716 717
{
    conn->privateData = NULL;
    return 0;
}

static const char *
718
libxlConnectGetType(virConnectPtr conn)
J
Jim Fehlig 已提交
719
{
720 721 722
    if (virConnectGetTypeEnsureACL(conn) < 0)
        return NULL;

J
Jim Fehlig 已提交
723
    return "Xen";
J
Jim Fehlig 已提交
724 725 726
}

static int
727
libxlConnectGetVersion(virConnectPtr conn, unsigned long *version)
J
Jim Fehlig 已提交
728 729
{
    libxlDriverPrivatePtr driver = conn->privateData;
730
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
731

732 733 734
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return 0;

735 736 737
    cfg = libxlDriverConfigGet(driver);
    *version = cfg->version;
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
738 739 740
    return 0;
}

741

742
static char *libxlConnectGetHostname(virConnectPtr conn)
743
{
744 745 746
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

747 748 749
    return virGetHostname();
}

750 751 752 753 754 755 756 757
static char *
libxlConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virCheckFlags(0, NULL);

758 759 760
    if (virConnectGetSysinfoEnsureACL(conn) < 0)
        return NULL;

761 762 763 764 765 766 767 768
    if (!driver->hostsysinfo) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Host SMBIOS information is not available"));
        return NULL;
    }

    if (virSysinfoFormat(&buf, driver->hostsysinfo) < 0)
        return NULL;
769
    if (virBufferCheckError(&buf) < 0)
770 771 772
        return NULL;
    return virBufferContentAndReset(&buf);
}
773

J
Jim Fehlig 已提交
774
static int
775
libxlConnectGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED)
J
Jim Fehlig 已提交
776 777 778
{
    int ret;
    libxlDriverPrivatePtr driver = conn->privateData;
779
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
780

781 782 783
    if (virConnectGetMaxVcpusEnsureACL(conn) < 0)
        return -1;

784 785
    cfg = libxlDriverConfigGet(driver);
    ret = libxl_get_max_cpus(cfg->ctx);
786 787 788 789 790
    /* On failure, libxl_get_max_cpus() will return ERROR_FAIL from Xen 4.4
     * onward, but it ever returning 0 is obviously wrong too (and it is
     * what happens, on failure, on Xen 4.3 and earlier). Therefore, a 'less
     * or equal' is the catchall we want. */
    if (ret <= 0)
791
        ret = -1;
J
Jim Fehlig 已提交
792

793
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
794 795 796 797 798 799
    return ret;
}

static int
libxlNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
{
800 801 802
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

803
    return libxlDriverNodeGetInfo(conn->privateData, info);
J
Jim Fehlig 已提交
804 805 806
}

static char *
807
libxlConnectGetCapabilities(virConnectPtr conn)
J
Jim Fehlig 已提交
808 809 810
{
    libxlDriverPrivatePtr driver = conn->privateData;
    char *xml;
811
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
812

813 814 815
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

816
    cfg = libxlDriverConfigGet(driver);
817
    xml = virCapabilitiesFormatXML(cfg->caps);
J
Jim Fehlig 已提交
818

819
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
820 821 822 823
    return xml;
}

static int
824
libxlConnectListDomains(virConnectPtr conn, int *ids, int nids)
J
Jim Fehlig 已提交
825 826 827 828
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

829 830 831
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

832 833
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                     virConnectListDomainsCheckACL, conn);
J
Jim Fehlig 已提交
834 835 836 837 838

    return n;
}

static int
839
libxlConnectNumOfDomains(virConnectPtr conn)
J
Jim Fehlig 已提交
840 841 842 843
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

844 845 846
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

847 848
    n = virDomainObjListNumOfDomains(driver->domains, true,
                                     virConnectNumOfDomainsCheckACL, conn);
J
Jim Fehlig 已提交
849 850 851 852 853 854 855 856 857 858 859 860

    return n;
}

static virDomainPtr
libxlDomainCreateXML(virConnectPtr conn, const char *xml,
                     unsigned int flags)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    virDomainDefPtr def;
    virDomainObjPtr vm = NULL;
    virDomainPtr dom = NULL;
861
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
862
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
J
Jim Fehlig 已提交
863

864 865 866 867 868
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
                  VIR_DOMAIN_START_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_START_VALIDATE)
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE;
J
Jim Fehlig 已提交
869

870
    if (!(def = virDomainDefParseString(xml, cfg->caps, driver->xmlopt,
871
                                        1 << VIR_DOMAIN_VIRT_XEN,
872
                                        parse_flags)))
J
Jim Fehlig 已提交
873 874
        goto cleanup;

875 876 877
    if (virDomainCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

878
    if (!(vm = virDomainObjListAdd(driver->domains, def,
879
                                   driver->xmlopt,
880 881
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
J
Jim Fehlig 已提交
882 883 884
        goto cleanup;
    def = NULL;

885
    if (libxlDomainStart(driver, vm, (flags & VIR_DOMAIN_START_PAUSED) != 0,
886
                     -1) < 0) {
887
        virDomainObjListRemove(driver->domains, vm);
J
Jim Fehlig 已提交
888 889 890 891 892 893 894 895
        vm = NULL;
        goto cleanup;
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = vm->def->id;

896
 cleanup:
J
Jim Fehlig 已提交
897 898
    virDomainDefFree(def);
    if (vm)
899
        virObjectUnlock(vm);
900
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
901 902 903 904 905 906 907 908 909 910
    return dom;
}

static virDomainPtr
libxlDomainLookupByID(virConnectPtr conn, int id)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

911
    vm = virDomainObjListFindByID(driver->domains, id);
J
Jim Fehlig 已提交
912
    if (!vm) {
913
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
914 915 916
        goto cleanup;
    }

917 918 919
    if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
920 921 922 923
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = vm->def->id;

924
 cleanup:
J
Jim Fehlig 已提交
925
    if (vm)
926
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
927 928 929 930 931 932 933 934 935 936
    return dom;
}

static virDomainPtr
libxlDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

937
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
J
Jim Fehlig 已提交
938
    if (!vm) {
939
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
940 941 942
        goto cleanup;
    }

943 944 945
    if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
946 947 948 949
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = vm->def->id;

950
 cleanup:
J
Jim Fehlig 已提交
951
    if (vm)
952
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
953 954 955 956 957 958 959 960 961 962
    return dom;
}

static virDomainPtr
libxlDomainLookupByName(virConnectPtr conn, const char *name)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

963
    vm = virDomainObjListFindByName(driver->domains, name);
J
Jim Fehlig 已提交
964
    if (!vm) {
965
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
966 967 968
        goto cleanup;
    }

969 970 971
    if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
972 973 974 975
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = vm->def->id;

976
 cleanup:
J
Jim Fehlig 已提交
977
    if (vm)
978
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
979 980 981
    return dom;
}

982 983 984 985
static int
libxlDomainSuspend(virDomainPtr dom)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
986
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
987 988
    virDomainObjPtr vm;
    libxlDomainObjPrivatePtr priv;
989
    virObjectEventPtr event = NULL;
990 991
    int ret = -1;

J
Jim Fehlig 已提交
992
    if (!(vm = libxlDomObjFromDomain(dom)))
993
        goto cleanup;
994 995 996 997

    if (virDomainSuspendEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

998 999 1000
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1001
    if (!virDomainObjIsActive(vm)) {
1002
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
1003
        goto endjob;
1004 1005 1006 1007
    }

    priv = vm->privateData;

J
Jiri Denemark 已提交
1008
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
1009
        if (libxl_domain_pause(priv->ctx, vm->def->id) != 0) {
1010 1011
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to suspend domain '%d' with libxenlight"),
1012
                           vm->def->id);
1013
            goto endjob;
1014 1015
        }

J
Jiri Denemark 已提交
1016
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
1017

1018
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
1019 1020 1021
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }

1022
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
1023
        goto endjob;
1024 1025 1026

    ret = 0;

1027
 endjob:
1028 1029 1030
    if (!libxlDomainObjEndJob(driver, vm))
        vm = NULL;

1031
 cleanup:
1032
    if (vm)
1033
        virObjectUnlock(vm);
1034
    if (event)
1035
        libxlDomainEventQueue(driver, event);
1036
    virObjectUnref(cfg);
1037 1038 1039 1040 1041 1042 1043 1044
    return ret;
}


static int
libxlDomainResume(virDomainPtr dom)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1045
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1046 1047
    virDomainObjPtr vm;
    libxlDomainObjPrivatePtr priv;
1048
    virObjectEventPtr event = NULL;
1049 1050
    int ret = -1;

J
Jim Fehlig 已提交
1051
    if (!(vm = libxlDomObjFromDomain(dom)))
1052 1053
        goto cleanup;

1054 1055 1056
    if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1057 1058 1059
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1060
    if (!virDomainObjIsActive(vm)) {
1061
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
1062
        goto endjob;
1063 1064 1065 1066
    }

    priv = vm->privateData;

J
Jiri Denemark 已提交
1067
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
1068
        if (libxl_domain_unpause(priv->ctx, vm->def->id) != 0) {
1069 1070
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to resume domain '%d' with libxenlight"),
1071
                           vm->def->id);
1072
            goto endjob;
1073 1074
        }

J
Jiri Denemark 已提交
1075 1076
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
1077

1078
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_RESUMED,
1079 1080 1081
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
    }

1082
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
1083
        goto endjob;
1084 1085 1086

    ret = 0;

1087
 endjob:
1088 1089 1090
    if (!libxlDomainObjEndJob(driver, vm))
        vm = NULL;

1091
 cleanup:
1092
    if (vm)
1093
        virObjectUnlock(vm);
1094
    if (event)
1095
        libxlDomainEventQueue(driver, event);
1096
    virObjectUnref(cfg);
1097 1098 1099
    return ret;
}

J
Jim Fehlig 已提交
1100
static int
1101
libxlDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
1102 1103 1104 1105 1106
{
    virDomainObjPtr vm;
    int ret = -1;
    libxlDomainObjPrivatePtr priv;

1107 1108 1109 1110 1111
    virCheckFlags(VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN |
                  VIR_DOMAIN_SHUTDOWN_PARAVIRT, -1);
    if (flags == 0)
        flags = VIR_DOMAIN_SHUTDOWN_PARAVIRT |
            VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN;
1112

J
Jim Fehlig 已提交
1113
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1114 1115
        goto cleanup;

1116
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
1117 1118
        goto cleanup;

J
Jim Fehlig 已提交
1119
    if (!virDomainObjIsActive(vm)) {
1120 1121
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
J
Jim Fehlig 已提交
1122 1123 1124 1125
        goto cleanup;
    }

    priv = vm->privateData;
1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146
    if (flags & VIR_DOMAIN_SHUTDOWN_PARAVIRT) {
        ret = libxl_domain_shutdown(priv->ctx, vm->def->id);
        if (ret == 0)
            goto cleanup;

        if (ret != ERROR_NOPARAVIRT) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to shutdown domain '%d' with libxenlight"),
                           vm->def->id);
            ret = -1;
            goto cleanup;
        }
        ret = -1;
    }

    if (flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN) {
        ret = libxl_send_trigger(priv->ctx, vm->def->id,
                                 LIBXL_TRIGGER_POWER, 0);
        if (ret == 0)
            goto cleanup;

1147 1148
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to shutdown domain '%d' with libxenlight"),
1149
                       vm->def->id);
1150
        ret = -1;
J
Jim Fehlig 已提交
1151 1152
    }

1153
 cleanup:
J
Jim Fehlig 已提交
1154
    if (vm)
1155
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
1156 1157 1158
    return ret;
}

1159 1160 1161 1162 1163 1164 1165
static int
libxlDomainShutdown(virDomainPtr dom)
{
    return libxlDomainShutdownFlags(dom, 0);
}


J
Jim Fehlig 已提交
1166
static int
E
Eric Blake 已提交
1167
libxlDomainReboot(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
1168 1169 1170 1171 1172
{
    virDomainObjPtr vm;
    int ret = -1;
    libxlDomainObjPrivatePtr priv;

J
Jim Fehlig 已提交
1173 1174 1175
    virCheckFlags(VIR_DOMAIN_REBOOT_PARAVIRT, -1);
    if (flags == 0)
        flags = VIR_DOMAIN_REBOOT_PARAVIRT;
E
Eric Blake 已提交
1176

J
Jim Fehlig 已提交
1177
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1178 1179
        goto cleanup;

1180
    if (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
1181 1182
        goto cleanup;

J
Jim Fehlig 已提交
1183
    if (!virDomainObjIsActive(vm)) {
1184 1185
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
J
Jim Fehlig 已提交
1186 1187 1188 1189
        goto cleanup;
    }

    priv = vm->privateData;
J
Jim Fehlig 已提交
1190 1191 1192 1193 1194
    if (flags & VIR_DOMAIN_REBOOT_PARAVIRT) {
        ret = libxl_domain_reboot(priv->ctx, vm->def->id);
        if (ret == 0)
            goto cleanup;

1195 1196
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to reboot domain '%d' with libxenlight"),
1197
                       vm->def->id);
J
Jim Fehlig 已提交
1198
        ret = -1;
J
Jim Fehlig 已提交
1199 1200
    }

1201
 cleanup:
J
Jim Fehlig 已提交
1202
    if (vm)
1203
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
1204 1205 1206 1207
    return ret;
}

static int
1208 1209
libxlDomainDestroyFlags(virDomainPtr dom,
                        unsigned int flags)
J
Jim Fehlig 已提交
1210 1211 1212 1213
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1214
    virObjectEventPtr event = NULL;
J
Jim Fehlig 已提交
1215
    libxlDomainObjPrivatePtr priv;
J
Jim Fehlig 已提交
1216

1217 1218
    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
1219
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1220 1221
        goto cleanup;

1222 1223 1224
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
1225
    if (!virDomainObjIsActive(vm)) {
1226 1227
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
J
Jim Fehlig 已提交
1228 1229 1230
        goto cleanup;
    }

1231
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
1232 1233
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);

J
Jim Fehlig 已提交
1234 1235
    priv = vm->privateData;
    if (libxl_domain_destroy(priv->ctx, vm->def->id, NULL) < 0) {
1236
        virReportError(VIR_ERR_INTERNAL_ERROR,
1237
                       _("Failed to destroy domain '%d'"), vm->def->id);
J
Jim Fehlig 已提交
1238 1239 1240
        goto cleanup;
    }

1241
    if (libxlDomainCleanupJob(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED)) {
1242 1243 1244 1245
        if (!vm->persistent) {
            virDomainObjListRemove(driver->domains, vm);
            vm = NULL;
        }
J
Jim Fehlig 已提交
1246 1247 1248 1249
    }

    ret = 0;

1250
 cleanup:
J
Jim Fehlig 已提交
1251
    if (vm)
1252
        virObjectUnlock(vm);
1253 1254
    if (event)
        libxlDomainEventQueue(driver, event);
J
Jim Fehlig 已提交
1255 1256 1257
    return ret;
}

1258 1259 1260 1261 1262 1263
static int
libxlDomainDestroy(virDomainPtr dom)
{
    return libxlDomainDestroyFlags(dom, 0);
}

1264 1265 1266 1267 1268 1269
static char *
libxlDomainGetOSType(virDomainPtr dom)
{
    virDomainObjPtr vm;
    char *type = NULL;

J
Jim Fehlig 已提交
1270
    if (!(vm = libxlDomObjFromDomain(dom)))
1271 1272
        goto cleanup;

1273 1274 1275 1276 1277
    if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (VIR_STRDUP(type, vm->def->os.type) < 0)
        goto cleanup;
1278

1279
 cleanup:
1280
    if (vm)
1281
        virObjectUnlock(vm);
1282 1283 1284
    return type;
}

1285
static unsigned long long
1286 1287 1288
libxlDomainGetMaxMemory(virDomainPtr dom)
{
    virDomainObjPtr vm;
1289
    unsigned long long ret = 0;
1290

J
Jim Fehlig 已提交
1291
    if (!(vm = libxlDomObjFromDomain(dom)))
1292
        goto cleanup;
1293 1294 1295 1296

    if (virDomainGetMaxMemoryEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1297
    ret = virDomainDefGetMemoryActual(vm->def);
1298

1299
 cleanup:
1300
    if (vm)
1301
        virObjectUnlock(vm);
1302 1303 1304 1305
    return ret;
}

static int
1306
libxlDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
1307 1308 1309
                          unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1310
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1311 1312
    libxlDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
1313 1314
    virDomainDefPtr persistentDef = NULL;
    bool isActive;
1315 1316 1317
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_MEM_LIVE |
1318 1319
                  VIR_DOMAIN_MEM_CONFIG |
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
1320

J
Jim Fehlig 已提交
1321
    if (!(vm = libxlDomObjFromDomain(dom)))
1322 1323
        goto cleanup;

1324 1325 1326
    if (virDomainSetMemoryFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

1327 1328 1329
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342
    isActive = virDomainObjIsActive(vm);

    if (flags == VIR_DOMAIN_MEM_CURRENT) {
        if (isActive)
            flags = VIR_DOMAIN_MEM_LIVE;
        else
            flags = VIR_DOMAIN_MEM_CONFIG;
    }
    if (flags == VIR_DOMAIN_MEM_MAXIMUM) {
        if (isActive)
            flags = VIR_DOMAIN_MEM_LIVE | VIR_DOMAIN_MEM_MAXIMUM;
        else
            flags = VIR_DOMAIN_MEM_CONFIG | VIR_DOMAIN_MEM_MAXIMUM;
1343 1344
    }

1345
    if (!isActive && (flags & VIR_DOMAIN_MEM_LIVE)) {
1346 1347
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot set memory on an inactive domain"));
1348
        goto endjob;
1349 1350 1351 1352
    }

    if (flags & VIR_DOMAIN_MEM_CONFIG) {
        if (!vm->persistent) {
1353 1354
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot change persistent config of a transient domain"));
1355
            goto endjob;
1356
        }
1357
        if (!(persistentDef = virDomainObjGetPersistentDef(cfg->caps,
1358
                                                           driver->xmlopt,
1359
                                                           vm)))
1360
            goto endjob;
1361 1362
    }

1363 1364
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
        /* resize the maximum memory */
1365

1366 1367
        if (flags & VIR_DOMAIN_MEM_LIVE) {
            priv = vm->privateData;
1368
            if (libxl_domain_setmaxmem(priv->ctx, vm->def->id, newmem) < 0) {
1369 1370
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to set maximum memory for domain '%d'"
1371
                                 " with libxenlight"), vm->def->id);
1372
                goto endjob;
1373 1374 1375 1376 1377 1378
            }
        }

        if (flags & VIR_DOMAIN_MEM_CONFIG) {
            /* Help clang 2.8 decipher the logic flow.  */
            sa_assert(persistentDef);
1379
            virDomainDefSetMemoryInitial(persistentDef, newmem);
1380 1381
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
1382
            ret = virDomainSaveConfig(cfg->configDir, persistentDef);
1383
            goto endjob;
1384 1385
        }

1386 1387
    } else {
        /* resize the current memory */
1388

1389
        if (newmem > virDomainDefGetMemoryActual(vm->def)) {
1390 1391
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("cannot set memory higher than max memory"));
1392
            goto endjob;
1393 1394 1395
        }

        if (flags & VIR_DOMAIN_MEM_LIVE) {
1396 1397
            int res;

1398
            priv = vm->privateData;
1399 1400
            /* Unlock virDomainObj while ballooning memory */
            virObjectUnlock(vm);
1401
            res = libxl_set_memory_target(priv->ctx, vm->def->id, newmem, 0,
1402 1403 1404
                                          /* force */ 1);
            virObjectLock(vm);
            if (res < 0) {
1405 1406
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to set memory for domain '%d'"
1407
                                 " with libxenlight"), vm->def->id);
1408
                goto endjob;
1409 1410 1411 1412 1413 1414
            }
        }

        if (flags & VIR_DOMAIN_MEM_CONFIG) {
            sa_assert(persistentDef);
            persistentDef->mem.cur_balloon = newmem;
1415
            ret = virDomainSaveConfig(cfg->configDir, persistentDef);
1416
            goto endjob;
1417
        }
1418 1419
    }

1420 1421
    ret = 0;

1422
 endjob:
1423 1424 1425
    if (!libxlDomainObjEndJob(driver, vm))
        vm = NULL;

1426
 cleanup:
1427
    if (vm)
1428
        virObjectUnlock(vm);
1429
    virObjectUnref(cfg);
1430 1431 1432 1433 1434 1435 1436 1437 1438
    return ret;
}

static int
libxlDomainSetMemory(virDomainPtr dom, unsigned long memory)
{
    return libxlDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_LIVE);
}

1439 1440 1441 1442 1443 1444
static int
libxlDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
{
    return libxlDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
}

J
Jim Fehlig 已提交
1445 1446 1447 1448
static int
libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
{
    virDomainObjPtr vm;
1449
    libxl_dominfo d_info;
1450
    libxlDomainObjPrivatePtr priv;
J
Jim Fehlig 已提交
1451 1452
    int ret = -1;

J
Jim Fehlig 已提交
1453
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1454 1455
        goto cleanup;

1456 1457 1458
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1459
    priv = vm->privateData;
1460 1461 1462
    if (!virDomainObjIsActive(vm)) {
        info->cpuTime = 0;
        info->memory = vm->def->mem.cur_balloon;
1463
        info->maxMem = virDomainDefGetMemoryActual(vm->def);
1464
    } else {
1465
        if (libxl_domain_info(priv->ctx, &d_info, vm->def->id) != 0) {
1466
            virReportError(VIR_ERR_INTERNAL_ERROR,
1467 1468
                           _("libxl_domain_info failed for domain '%d'"),
                           vm->def->id);
1469 1470 1471 1472
            goto cleanup;
        }
        info->cpuTime = d_info.cpu_time;
        info->memory = d_info.current_memkb;
1473
        info->maxMem = d_info.max_memkb;
1474 1475
    }

J
Jiri Denemark 已提交
1476
    info->state = virDomainObjGetState(vm, NULL);
J
Jim Fehlig 已提交
1477 1478 1479
    info->nrVirtCpu = vm->def->vcpus;
    ret = 0;

1480
 cleanup:
J
Jim Fehlig 已提交
1481
    if (vm)
1482
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
1483 1484 1485
    return ret;
}

1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496
static int
libxlDomainGetState(virDomainPtr dom,
                    int *state,
                    int *reason,
                    unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
1497
    if (!(vm = libxlDomObjFromDomain(dom)))
1498 1499
        goto cleanup;

1500 1501 1502
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1503
    *state = virDomainObjGetState(vm, reason);
1504 1505
    ret = 0;

1506
 cleanup:
1507
    if (vm)
1508
        virObjectUnlock(vm);
1509 1510 1511
    return ret;
}

1512 1513 1514
/*
 * virDomainObjPtr must be locked on invocation
 */
1515
static int
1516 1517
libxlDoDomainSave(libxlDriverPrivatePtr driver, virDomainObjPtr vm,
                  const char *to)
1518
{
1519
    libxlDomainObjPrivatePtr priv = vm->privateData;
1520
    libxlSavefileHeader hdr;
1521
    virObjectEventPtr event = NULL;
1522 1523
    char *xml = NULL;
    uint32_t xml_len;
1524
    int fd = -1;
1525 1526 1527
    int ret = -1;

    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
1528 1529 1530
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Domain '%d' has to be running because libxenlight will"
                         " suspend it"), vm->def->id);
1531 1532 1533 1534
        goto cleanup;
    }

    if ((fd = virFileOpenAs(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR,
L
Laine Stump 已提交
1535
                            -1, -1, 0)) < 0) {
1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550
        virReportSystemError(-fd,
                             _("Failed to create domain save file '%s'"), to);
        goto cleanup;
    }

    if ((xml = virDomainDefFormat(vm->def, 0)) == NULL)
        goto cleanup;
    xml_len = strlen(xml) + 1;

    memset(&hdr, 0, sizeof(hdr));
    memcpy(hdr.magic, LIBXL_SAVE_MAGIC, sizeof(hdr.magic));
    hdr.version = LIBXL_SAVE_VERSION;
    hdr.xmlLen = xml_len;

    if (safewrite(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
1551 1552
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Failed to write save file header"));
1553 1554 1555 1556
        goto cleanup;
    }

    if (safewrite(fd, xml, xml_len) != xml_len) {
1557 1558
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Failed to write xml description"));
1559 1560 1561
        goto cleanup;
    }

1562 1563 1564 1565 1566 1567
    /* Unlock virDomainObj while saving domain */
    virObjectUnlock(vm);
    ret = libxl_domain_suspend(priv->ctx, vm->def->id, fd, 0, NULL);
    virObjectLock(vm);

    if (ret != 0) {
1568 1569 1570
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to save domain '%d' with libxenlight"),
                       vm->def->id);
1571
        ret = -1;
1572 1573 1574
        goto cleanup;
    }

1575
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
1576 1577
                                         VIR_DOMAIN_EVENT_STOPPED_SAVED);

J
Jim Fehlig 已提交
1578
    if (libxl_domain_destroy(priv->ctx, vm->def->id, NULL) < 0) {
1579 1580
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to destroy domain '%d'"), vm->def->id);
1581 1582 1583
        goto cleanup;
    }

1584
    libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_SAVED);
1585
    vm->hasManagedSave = true;
1586 1587
    ret = 0;

1588
 cleanup:
1589 1590 1591 1592 1593 1594 1595 1596 1597
    VIR_FREE(xml);
    if (VIR_CLOSE(fd) < 0)
        virReportSystemError(errno, "%s", _("cannot close file"));
    if (event)
        libxlDomainEventQueue(driver, event);
    return ret;
}

static int
1598 1599
libxlDomainSaveFlags(virDomainPtr dom, const char *to, const char *dxml,
                     unsigned int flags)
1600
{
1601 1602
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
1603
    int ret = -1;
1604
    bool remove_dom = false;
1605

1606 1607 1608 1609 1610
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

1611 1612
    virCheckFlags(0, -1);
    if (dxml) {
1613 1614
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("xml modification unsupported"));
1615 1616 1617
        return -1;
    }

J
Jim Fehlig 已提交
1618
    if (!(vm = libxlDomObjFromDomain(dom)))
1619 1620
        goto cleanup;

1621 1622 1623
    if (virDomainSaveFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1624 1625 1626
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1627
    if (!virDomainObjIsActive(vm)) {
1628
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
1629
        goto endjob;
1630 1631
    }

1632
    if (libxlDoDomainSave(driver, vm, to) < 0)
1633
        goto endjob;
1634

1635 1636
    if (!vm->persistent)
        remove_dom = true;
1637 1638

    ret = 0;
1639

1640
 endjob:
1641 1642 1643
    if (!libxlDomainObjEndJob(driver, vm))
        vm = NULL;

1644
 cleanup:
1645 1646 1647 1648
    if (remove_dom && vm) {
        virDomainObjListRemove(driver->domains, vm);
        vm = NULL;
    }
1649
    if (vm)
1650
        virObjectUnlock(vm);
1651 1652
    return ret;
}
1653

1654
static int
1655 1656 1657 1658 1659 1660 1661 1662
libxlDomainSave(virDomainPtr dom, const char *to)
{
    return libxlDomainSaveFlags(dom, to, NULL, 0);
}

static int
libxlDomainRestoreFlags(virConnectPtr conn, const char *from,
                        const char *dxml, unsigned int flags)
1663 1664
{
    libxlDriverPrivatePtr driver = conn->privateData;
1665
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1666 1667 1668 1669 1670
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    libxlSavefileHeader hdr;
    int fd = -1;
    int ret = -1;
1671

1672 1673 1674 1675 1676
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

1677
    virCheckFlags(VIR_DOMAIN_SAVE_PAUSED, -1);
1678
    if (dxml) {
1679 1680
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("xml modification unsupported"));
1681 1682 1683
        return -1;
    }

1684
    fd = libxlDomainSaveImageOpen(driver, cfg, from, &def, &hdr);
1685
    if (fd < 0)
1686
        return -1;
1687

1688
    if (virDomainRestoreFlagsEnsureACL(conn, def) < 0)
1689
        goto cleanup;
1690

1691
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1692
                                   driver->xmlopt,
1693 1694 1695
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1696
        goto cleanup;
1697 1698 1699

    def = NULL;

1700
    ret = libxlDomainStart(driver, vm, (flags & VIR_DOMAIN_SAVE_PAUSED) != 0, fd);
1701
    if (ret < 0 && !vm->persistent) {
1702
        virDomainObjListRemove(driver->domains, vm);
1703 1704 1705
        vm = NULL;
    }

1706
 cleanup:
1707 1708
    if (VIR_CLOSE(fd) < 0)
        virReportSystemError(errno, "%s", _("cannot close file"));
1709 1710
    virDomainDefFree(def);
    if (vm)
1711
        virObjectUnlock(vm);
1712
    virObjectUnref(cfg);
1713 1714 1715
    return ret;
}

1716 1717 1718 1719 1720 1721
static int
libxlDomainRestore(virConnectPtr conn, const char *from)
{
    return libxlDomainRestoreFlags(conn, from, NULL, 0);
}

1722
static int
1723
libxlDomainCoreDump(virDomainPtr dom, const char *to, unsigned int flags)
1724 1725 1726 1727
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
1728
    virObjectEventPtr event = NULL;
1729
    bool remove_dom = false;
1730 1731 1732 1733 1734
    bool paused = false;
    int ret = -1;

    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH, -1);

J
Jim Fehlig 已提交
1735
    if (!(vm = libxlDomObjFromDomain(dom)))
1736 1737
        goto cleanup;

1738 1739 1740
    if (virDomainCoreDumpEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1741 1742 1743
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1744
    if (!virDomainObjIsActive(vm)) {
1745
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
1746
        goto endjob;
1747 1748 1749 1750 1751 1752
    }

    priv = vm->privateData;

    if (!(flags & VIR_DUMP_LIVE) &&
        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
1753
        if (libxl_domain_pause(priv->ctx, vm->def->id) != 0) {
1754 1755 1756
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Before dumping core, failed to suspend domain '%d'"
                             " with libxenlight"),
1757
                           vm->def->id);
1758
            goto endjob;
1759 1760 1761 1762 1763
        }
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_DUMP);
        paused = true;
    }

1764 1765
    /* Unlock virDomainObj while dumping core */
    virObjectUnlock(vm);
1766
    ret = libxl_domain_core_dump(priv->ctx, vm->def->id, to, NULL);
1767 1768
    virObjectLock(vm);
    if (ret != 0) {
1769 1770
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to dump core of domain '%d' with libxenlight"),
1771
                       vm->def->id);
1772 1773
        ret = -1;
        goto unpause;
1774 1775 1776
    }

    if (flags & VIR_DUMP_CRASH) {
1777
        if (libxl_domain_destroy(priv->ctx, vm->def->id, NULL) < 0) {
1778
            virReportError(VIR_ERR_INTERNAL_ERROR,
1779
                           _("Failed to destroy domain '%d'"), vm->def->id);
1780
            goto unpause;
1781 1782
        }

1783
        libxlDomainCleanup(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED);
1784
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
1785
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
1786 1787
        if (!vm->persistent)
            remove_dom = true;
1788 1789 1790 1791
    }

    ret = 0;

1792
 unpause:
1793
    if (virDomainObjIsActive(vm) && paused) {
1794
        if (libxl_domain_unpause(priv->ctx, vm->def->id) != 0) {
1795 1796
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("After dumping core, failed to resume domain '%d' with"
1797
                             " libxenlight"), vm->def->id);
1798 1799 1800 1801 1802
        } else {
            virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                                 VIR_DOMAIN_RUNNING_UNPAUSED);
        }
    }
1803

1804
 endjob:
1805 1806 1807
    if (!libxlDomainObjEndJob(driver, vm))
        vm = NULL;

1808
 cleanup:
1809 1810 1811 1812
    if (remove_dom && vm) {
        virDomainObjListRemove(driver->domains, vm);
        vm = NULL;
    }
1813
    if (vm)
1814
        virObjectUnlock(vm);
1815
    if (event)
1816 1817 1818 1819
        libxlDomainEventQueue(driver, event);
    return ret;
}

1820 1821 1822 1823 1824 1825 1826
static int
libxlDomainManagedSave(virDomainPtr dom, unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    char *name = NULL;
    int ret = -1;
1827
    bool remove_dom = false;
1828 1829 1830

    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
1831
    if (!(vm = libxlDomObjFromDomain(dom)))
1832 1833
        goto cleanup;

1834 1835 1836
    if (virDomainManagedSaveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1837 1838 1839
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1840
    if (!virDomainObjIsActive(vm)) {
1841
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
1842
        goto endjob;
1843
    }
1844
    if (!vm->persistent) {
1845 1846
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot do managed save for transient domain"));
1847
        goto endjob;
1848
    }
1849 1850 1851

    name = libxlDomainManagedSavePath(driver, vm);
    if (name == NULL)
1852
        goto endjob;
1853 1854 1855

    VIR_INFO("Saving state to %s", name);

1856
    if (libxlDoDomainSave(driver, vm, name) < 0)
1857
        goto endjob;
1858

1859 1860
    if (!vm->persistent)
        remove_dom = true;
1861 1862

    ret = 0;
1863

1864
 endjob:
1865 1866 1867
    if (!libxlDomainObjEndJob(driver, vm))
        vm = NULL;

1868
 cleanup:
1869 1870 1871 1872
    if (remove_dom && vm) {
        virDomainObjListRemove(driver->domains, vm);
        vm = NULL;
    }
1873
    if (vm)
1874
        virObjectUnlock(vm);
1875 1876 1877 1878
    VIR_FREE(name);
    return ret;
}

1879 1880
static int
libxlDomainManagedSaveLoad(virDomainObjPtr vm,
1881 1882 1883 1884
                           void *opaque)
{
    libxlDriverPrivatePtr driver = opaque;
    char *name;
1885
    int ret = -1;
1886

1887
    virObjectLock(vm);
1888 1889 1890 1891 1892 1893

    if (!(name = libxlDomainManagedSavePath(driver, vm)))
        goto cleanup;

    vm->hasManagedSave = virFileExists(name);

1894
    ret = 0;
1895
 cleanup:
1896
    virObjectUnlock(vm);
1897
    VIR_FREE(name);
1898
    return ret;
1899 1900
}

1901 1902 1903 1904 1905 1906 1907 1908
static int
libxlDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
1909
    if (!(vm = libxlDomObjFromDomain(dom)))
1910 1911
        goto cleanup;

1912 1913 1914
    if (virDomainHasManagedSaveImageEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1915
    ret = vm->hasManagedSave;
1916

1917
 cleanup:
1918
    if (vm)
1919
        virObjectUnlock(vm);
1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932
    return ret;
}

static int
libxlDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    char *name = NULL;

    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
1933
    if (!(vm = libxlDomObjFromDomain(dom)))
1934 1935
        goto cleanup;

1936 1937 1938
    if (virDomainManagedSaveRemoveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1939 1940 1941 1942 1943
    name = libxlDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    ret = unlink(name);
1944
    vm->hasManagedSave = false;
1945

1946
 cleanup:
1947 1948
    VIR_FREE(name);
    if (vm)
1949
        virObjectUnlock(vm);
1950 1951 1952
    return ret;
}

1953 1954 1955 1956 1957
static int
libxlDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                         unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1958
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1959 1960 1961
    libxlDomainObjPrivatePtr priv;
    virDomainDefPtr def;
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
1962
    libxl_bitmap map;
1963 1964
    uint8_t *bitmask = NULL;
    unsigned int maplen;
1965 1966
    size_t i;
    unsigned int pos;
1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978
    int max;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

    /* At least one of LIVE or CONFIG must be set.  MAXIMUM cannot be
     * mixed with LIVE.  */
    if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0 ||
        (flags & (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) ==
         (VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_LIVE)) {
1979 1980
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid flag combination: (0x%x)"), flags);
1981 1982 1983 1984
        return -1;
    }

    if (!nvcpus) {
1985
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("nvcpus is zero"));
1986 1987 1988
        return -1;
    }

J
Jim Fehlig 已提交
1989
    if (!(vm = libxlDomObjFromDomain(dom)))
1990 1991
        goto cleanup;

1992 1993 1994
    if (virDomainSetVcpusFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

1995 1996 1997
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1998
    if (!virDomainObjIsActive(vm) && (flags & VIR_DOMAIN_VCPU_LIVE)) {
1999 2000
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot set vcpus on an inactive domain"));
2001
        goto endjob;
2002 2003 2004
    }

    if (!vm->persistent && (flags & VIR_DOMAIN_VCPU_CONFIG)) {
2005 2006
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot change persistent config of a transient domain"));
2007
        goto endjob;
2008 2009
    }

2010
    if ((max = libxlConnectGetMaxVcpus(dom->conn, NULL)) < 0) {
2011 2012
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not determine max vcpus for the domain"));
2013
        goto endjob;
2014 2015
    }

2016
    if (!(flags & VIR_DOMAIN_VCPU_MAXIMUM) && vm->def->maxvcpus < max)
2017 2018 2019
        max = vm->def->maxvcpus;

    if (nvcpus > max) {
2020 2021 2022
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the domain: %d > %d"), nvcpus, max);
2023
        goto endjob;
2024 2025 2026 2027
    }

    priv = vm->privateData;

2028
    if (!(def = virDomainObjGetPersistentDef(cfg->caps, driver->xmlopt, vm)))
2029
        goto endjob;
2030

E
Eric Blake 已提交
2031
    maplen = VIR_CPU_MAPLEN(nvcpus);
2032
    if (VIR_ALLOC_N(bitmask, maplen) < 0)
2033
        goto endjob;
2034 2035

    for (i = 0; i < nvcpus; ++i) {
E
Eric Blake 已提交
2036
        pos = i / 8;
2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054
        bitmask[pos] |= 1 << (i % 8);
    }

    map.size = maplen;
    map.map = bitmask;

    switch (flags) {
    case VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_CONFIG:
        def->maxvcpus = nvcpus;
        if (nvcpus < def->vcpus)
            def->vcpus = nvcpus;
        break;

    case VIR_DOMAIN_VCPU_CONFIG:
        def->vcpus = nvcpus;
        break;

    case VIR_DOMAIN_VCPU_LIVE:
2055
        if (libxl_set_vcpuonline(priv->ctx, vm->def->id, &map) != 0) {
2056 2057
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to set vcpus for domain '%d'"
2058
                             " with libxenlight"), vm->def->id);
2059
            goto endjob;
2060 2061 2062 2063
        }
        break;

    case VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG:
2064
        if (libxl_set_vcpuonline(priv->ctx, vm->def->id, &map) != 0) {
2065 2066
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to set vcpus for domain '%d'"
2067
                             " with libxenlight"), vm->def->id);
2068
            goto endjob;
2069 2070 2071 2072 2073 2074 2075 2076
        }
        def->vcpus = nvcpus;
        break;
    }

    ret = 0;

    if (flags & VIR_DOMAIN_VCPU_CONFIG)
2077
        ret = virDomainSaveConfig(cfg->configDir, def);
2078

2079
 endjob:
2080 2081 2082
    if (!libxlDomainObjEndJob(driver, vm))
        vm = NULL;

2083
 cleanup:
2084 2085
    VIR_FREE(bitmask);
     if (vm)
2086
        virObjectUnlock(vm);
2087
     virObjectUnref(cfg);
2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102
    return ret;
}

static int
libxlDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
{
    return libxlDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_VCPU_LIVE);
}

static int
libxlDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
    virDomainObjPtr vm;
    virDomainDefPtr def;
    int ret = -1;
2103
    bool active;
2104 2105 2106 2107 2108

    virCheckFlags(VIR_DOMAIN_VCPU_LIVE |
                  VIR_DOMAIN_VCPU_CONFIG |
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

J
Jim Fehlig 已提交
2109
    if (!(vm = libxlDomObjFromDomain(dom)))
2110 2111
        goto cleanup;

2112
    if (virDomainGetVcpusFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
2113 2114
        goto cleanup;

2115 2116 2117 2118 2119 2120 2121 2122 2123
    active = virDomainObjIsActive(vm);

    if ((flags & (VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG)) == 0) {
        if (active)
            flags |= VIR_DOMAIN_VCPU_LIVE;
        else
            flags |= VIR_DOMAIN_VCPU_CONFIG;
    }
    if ((flags & VIR_DOMAIN_VCPU_LIVE) && (flags & VIR_DOMAIN_VCPU_CONFIG)) {
2124 2125
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid flag combination: (0x%x)"), flags);
2126 2127 2128
        return -1;
    }

2129
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
2130
        if (!active) {
2131 2132
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("Domain is not running"));
2133 2134 2135 2136
            goto cleanup;
        }
        def = vm->def;
    } else {
2137
        if (!vm->persistent) {
2138 2139
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("domain is transient"));
2140 2141
            goto cleanup;
        }
2142 2143 2144 2145 2146
        def = vm->newDef ? vm->newDef : vm->def;
    }

    ret = (flags & VIR_DOMAIN_VCPU_MAXIMUM) ? def->maxvcpus : def->vcpus;

2147
 cleanup:
2148
    if (vm)
2149
        virObjectUnlock(vm);
2150 2151 2152 2153
    return ret;
}

static int
2154 2155 2156
libxlDomainPinVcpuFlags(virDomainPtr dom, unsigned int vcpu,
                        unsigned char *cpumap, int maplen,
                        unsigned int flags)
2157 2158
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
2159
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2160
    virDomainDefPtr targetDef = NULL;
2161
    virBitmapPtr pcpumap = NULL;
2162 2163
    virDomainObjPtr vm;
    int ret = -1;
2164 2165 2166

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
2167

J
Jim Fehlig 已提交
2168
    if (!(vm = libxlDomObjFromDomain(dom)))
2169 2170
        goto cleanup;

2171
    if (virDomainPinVcpuFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
2172 2173
        goto cleanup;

2174 2175 2176
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

2177
    if ((flags & VIR_DOMAIN_AFFECT_LIVE) && !virDomainObjIsActive(vm)) {
2178
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
2179
                       _("domain is inactive"));
2180
        goto endjob;
2181 2182
    }

2183 2184
    if (virDomainLiveConfigHelperMethod(cfg->caps, driver->xmlopt, vm,
                                        &flags, &targetDef) < 0)
2185
        goto endjob;
2186

2187
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
2188 2189 2190 2191 2192
        targetDef = vm->def;

    /* Make sure coverity knows targetDef is valid at this point. */
    sa_assert(targetDef);

2193 2194
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
2195
        goto endjob;
2196

2197 2198 2199 2200 2201
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        libxl_bitmap map = { .size = maplen, .map = cpumap };
        libxlDomainObjPrivatePtr priv;

        priv = vm->privateData;
2202
        if (libxl_set_vcpuaffinity(priv->ctx, vm->def->id, vcpu, &map) != 0) {
2203 2204 2205
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to pin vcpu '%d' with libxenlight"),
                           vcpu);
2206
            goto endjob;
2207
        }
2208
    }
2209

2210 2211
    /* full bitmap means reset the settings (if any). */
    if (virBitmapIsAllSet(pcpumap)) {
2212 2213 2214
        virDomainPinDel(&targetDef->cputune.vcpupin,
                        &targetDef->cputune.nvcpupin,
                        vcpu);
2215
        goto done;
2216 2217
    }

2218 2219
    if (!targetDef->cputune.vcpupin) {
        if (VIR_ALLOC(targetDef->cputune.vcpupin) < 0)
2220
            goto endjob;
2221
        targetDef->cputune.nvcpupin = 0;
H
Hu Tao 已提交
2222
    }
2223 2224 2225 2226 2227
    if (virDomainPinAdd(&targetDef->cputune.vcpupin,
                        &targetDef->cputune.nvcpupin,
                        cpumap,
                        maplen,
                        vcpu) < 0) {
2228 2229
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("failed to update or add vcpupin xml"));
2230
        goto endjob;
2231 2232
    }

2233
 done:
2234 2235
    ret = 0;

2236 2237 2238 2239 2240 2241
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        ret = virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm);
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        ret = virDomainSaveConfig(cfg->configDir, targetDef);
    }

2242
 endjob:
2243 2244 2245
    if (!libxlDomainObjEndJob(driver, vm))
        vm = NULL;

2246
 cleanup:
2247
    if (vm)
2248
        virObjectUnlock(vm);
2249
    virBitmapFree(pcpumap);
2250
    virObjectUnref(cfg);
2251 2252 2253
    return ret;
}

2254 2255 2256 2257 2258 2259 2260 2261
static int
libxlDomainPinVcpu(virDomainPtr dom, unsigned int vcpu, unsigned char *cpumap,
                   int maplen)
{
    return libxlDomainPinVcpuFlags(dom, vcpu, cpumap, maplen,
                                   VIR_DOMAIN_AFFECT_LIVE);
}

2262 2263 2264 2265 2266 2267 2268 2269 2270
static int
libxlDomainGetVcpuPinInfo(virDomainPtr dom, int ncpumaps,
                          unsigned char *cpumaps, int maplen,
                          unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    virDomainObjPtr vm = NULL;
    virDomainDefPtr targetDef = NULL;
2271
    virDomainPinDefPtr *vcpupin_list;
2272 2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288
    virBitmapPtr cpumask = NULL;
    int maxcpu, hostcpus, vcpu, pcpu, n, ret = -1;
    unsigned char *cpumap;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainGetVcpuPinInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (virDomainLiveConfigHelperMethod(cfg->caps, driver->xmlopt, vm,
                                        &flags, &targetDef) < 0)
        goto cleanup;

2289
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318
        targetDef = vm->def;

    /* Make sure coverity knows targetDef is valid at this point. */
    sa_assert(targetDef);

    /* Clamp to actual number of vcpus */
    if (ncpumaps > targetDef->vcpus)
        ncpumaps = targetDef->vcpus;

    /* we use cfg->ctx, as vm->privateData->ctx may be NULL if VM is down. */
    if ((hostcpus = libxl_get_max_cpus(cfg->ctx)) < 0)
        goto cleanup;

    maxcpu = maplen * 8;
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;

    /* initialize cpumaps */
    memset(cpumaps, 0xff, maplen * ncpumaps);
    if (maxcpu % 8) {
        for (vcpu = 0; vcpu < ncpumaps; vcpu++) {
            cpumap = VIR_GET_CPUMAP(cpumaps, maplen, vcpu);
            cpumap[maplen - 1] &= (1 << maxcpu % 8) - 1;
        }
    }

    /* if vcpupin setting exists, there may be unused pcpus */
    for (n = 0; n < targetDef->cputune.nvcpupin; n++) {
        vcpupin_list = targetDef->cputune.vcpupin;
2319
        vcpu = vcpupin_list[n]->id;
2320 2321 2322
        cpumask = vcpupin_list[n]->cpumask;
        cpumap = VIR_GET_CPUMAP(cpumaps, maplen, vcpu);
        for (pcpu = 0; pcpu < maxcpu; pcpu++) {
J
Ján Tomko 已提交
2323
            if (!virBitmapIsBitSet(cpumask, pcpu))
2324 2325 2326 2327 2328
                VIR_UNUSE_CPU(cpumap, pcpu);
        }
    }
    ret = ncpumaps;

2329
 cleanup:
2330 2331 2332 2333 2334
    if (vm)
        virObjectUnlock(vm);
    virObjectUnref(cfg);
    return ret;
}
2335 2336 2337 2338 2339 2340 2341 2342 2343 2344

static int
libxlDomainGetVcpus(virDomainPtr dom, virVcpuInfoPtr info, int maxinfo,
                    unsigned char *cpumaps, int maplen)
{
    libxlDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;
    libxl_vcpuinfo *vcpuinfo;
    int maxcpu, hostcpus;
2345
    size_t i;
2346 2347
    unsigned char *cpumap;

J
Jim Fehlig 已提交
2348
    if (!(vm = libxlDomObjFromDomain(dom)))
2349 2350
        goto cleanup;

2351 2352 2353
    if (virDomainGetVcpusEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2354
    if (!virDomainObjIsActive(vm)) {
2355
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
2356 2357 2358 2359
        goto cleanup;
    }

    priv = vm->privateData;
2360
    if ((vcpuinfo = libxl_list_vcpu(priv->ctx, vm->def->id, &maxcpu,
2361
                                    &hostcpus)) == NULL) {
2362 2363
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to list vcpus for domain '%d' with libxenlight"),
2364
                       vm->def->id);
2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386
        goto cleanup;
    }

    if (cpumaps && maplen > 0)
        memset(cpumaps, 0, maplen * maxinfo);
    for (i = 0; i < maxcpu && i < maxinfo; ++i) {
        info[i].number = vcpuinfo[i].vcpuid;
        info[i].cpu = vcpuinfo[i].cpu;
        info[i].cpuTime = vcpuinfo[i].vcpu_time;
        if (vcpuinfo[i].running)
            info[i].state = VIR_VCPU_RUNNING;
        else if (vcpuinfo[i].blocked)
            info[i].state = VIR_VCPU_BLOCKED;
        else
            info[i].state = VIR_VCPU_OFFLINE;

        if (cpumaps && maplen > 0) {
            cpumap = VIR_GET_CPUMAP(cpumaps, maplen, i);
            memcpy(cpumap, vcpuinfo[i].cpumap.map,
                   MIN(maplen, vcpuinfo[i].cpumap.size));
        }

J
Jim Fehlig 已提交
2387
        libxl_vcpuinfo_dispose(&vcpuinfo[i]);
2388 2389 2390 2391 2392
    }
    VIR_FREE(vcpuinfo);

    ret = maxinfo;

2393
 cleanup:
2394
    if (vm)
2395
        virObjectUnlock(vm);
2396 2397 2398
    return ret;
}

J
Jim Fehlig 已提交
2399
static char *
2400
libxlDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
2401 2402 2403 2404
{
    virDomainObjPtr vm;
    char *ret = NULL;

2405 2406
    /* Flags checked by virDomainDefFormat */

J
Jim Fehlig 已提交
2407
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
2408 2409
        goto cleanup;

2410 2411 2412
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

2413 2414
    ret = virDomainDefFormat(vm->def,
                              virDomainDefFormatConvertXMLFlags(flags));
J
Jim Fehlig 已提交
2415

2416
 cleanup:
J
Jim Fehlig 已提交
2417
    if (vm)
2418
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
2419 2420 2421
    return ret;
}

2422
static char *
2423 2424 2425
libxlConnectDomainXMLFromNative(virConnectPtr conn,
                                const char *nativeFormat,
                                const char *nativeConfig,
2426
                                unsigned int flags)
2427 2428
{
    libxlDriverPrivatePtr driver = conn->privateData;
2429
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2430 2431 2432 2433
    virDomainDefPtr def = NULL;
    virConfPtr conf = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2434 2435
    virCheckFlags(0, NULL);

2436 2437 2438
    if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0)
        goto cleanup;

2439 2440 2441 2442 2443
    if (STREQ(nativeFormat, LIBXL_CONFIG_FORMAT_XL)) {
        if (!(conf = virConfReadMem(nativeConfig, strlen(nativeConfig), 0)))
            goto cleanup;
        if (!(def = xenParseXL(conf,
                               cfg->caps,
2444
                               cfg->verInfo->xen_version_major)))
2445 2446
            goto cleanup;
    } else if (STREQ(nativeFormat, LIBXL_CONFIG_FORMAT_XM)) {
2447 2448 2449 2450 2451
        if (!(conf = virConfReadMem(nativeConfig, strlen(nativeConfig), 0)))
            goto cleanup;

        if (!(def = xenParseXM(conf,
                               cfg->verInfo->xen_version_major,
2452
                               cfg->caps)))
2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464
            goto cleanup;
    } else if (STREQ(nativeFormat, LIBXL_CONFIG_FORMAT_SEXPR)) {
        /* only support latest xend config format */
        if (!(def = xenParseSxprString(nativeConfig,
                                       XEND_CONFIG_VERSION_3_1_0,
                                       NULL,
                                       -1))) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("parsing sxpr config failed"));
            goto cleanup;
        }
    } else {
2465 2466
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), nativeFormat);
2467 2468 2469
        goto cleanup;
    }

2470
    xml = virDomainDefFormat(def, VIR_DOMAIN_DEF_FORMAT_INACTIVE);
2471

2472
 cleanup:
2473 2474 2475
    virDomainDefFree(def);
    if (conf)
        virConfFree(conf);
2476
    virObjectUnref(cfg);
2477 2478 2479 2480 2481
    return xml;
}

#define MAX_CONFIG_SIZE (1024 * 65)
static char *
2482 2483 2484
libxlConnectDomainXMLToNative(virConnectPtr conn, const char * nativeFormat,
                              const char * domainXml,
                              unsigned int flags)
2485 2486
{
    libxlDriverPrivatePtr driver = conn->privateData;
2487
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2488 2489 2490 2491 2492
    virDomainDefPtr def = NULL;
    virConfPtr conf = NULL;
    int len = MAX_CONFIG_SIZE;
    char *ret = NULL;

E
Eric Blake 已提交
2493 2494
    virCheckFlags(0, NULL);

2495 2496 2497
    if (virConnectDomainXMLToNativeEnsureACL(conn) < 0)
        goto cleanup;

2498
    if (!(def = virDomainDefParseString(domainXml,
2499
                                        cfg->caps, driver->xmlopt,
2500
                                        1 << VIR_DOMAIN_VIRT_XEN,
2501
                                        VIR_DOMAIN_DEF_PARSE_INACTIVE)))
2502 2503
        goto cleanup;

2504 2505 2506 2507 2508 2509 2510 2511 2512 2513
    if (STREQ(nativeFormat, LIBXL_CONFIG_FORMAT_XL)) {
        if (!(conf = xenFormatXL(def, conn, cfg->verInfo->xen_version_major)))
            goto cleanup;
    } else if (STREQ(nativeFormat, LIBXL_CONFIG_FORMAT_XM)) {
        if (!(conf = xenFormatXM(conn, def, cfg->verInfo->xen_version_major)))
            goto cleanup;
    } else {

        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), nativeFormat);
2514
        goto cleanup;
2515
    }
2516

2517
    if (VIR_ALLOC_N(ret, len) < 0)
2518 2519 2520 2521 2522 2523 2524
        goto cleanup;

    if (virConfWriteMem(ret, &len, conf) < 0) {
        VIR_FREE(ret);
        goto cleanup;
    }

2525
 cleanup:
2526 2527 2528
    virDomainDefFree(def);
    if (conf)
        virConfFree(conf);
2529
    virObjectUnref(cfg);
2530 2531 2532
    return ret;
}

J
Jim Fehlig 已提交
2533
static int
2534 2535
libxlConnectListDefinedDomains(virConnectPtr conn,
                               char **const names, int nnames)
J
Jim Fehlig 已提交
2536 2537 2538 2539
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

2540 2541 2542
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        return -1;

2543 2544
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         virConnectListDefinedDomainsCheckACL, conn);
J
Jim Fehlig 已提交
2545 2546 2547 2548
    return n;
}

static int
2549
libxlConnectNumOfDefinedDomains(virConnectPtr conn)
J
Jim Fehlig 已提交
2550 2551 2552 2553
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

2554 2555 2556
    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        return -1;

2557
    n = virDomainObjListNumOfDomains(driver->domains, false,
2558 2559
                                     virConnectNumOfDefinedDomainsCheckACL,
                                     conn);
J
Jim Fehlig 已提交
2560 2561 2562 2563 2564
    return n;
}

static int
libxlDomainCreateWithFlags(virDomainPtr dom,
E
Eric Blake 已提交
2565
                           unsigned int flags)
J
Jim Fehlig 已提交
2566 2567 2568 2569 2570 2571 2572
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_START_PAUSED, -1);

J
Jim Fehlig 已提交
2573
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
2574 2575
        goto cleanup;

2576 2577 2578
    if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
2579
    if (virDomainObjIsActive(vm)) {
2580 2581
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is already running"));
J
Jim Fehlig 已提交
2582 2583 2584
        goto cleanup;
    }

2585
    ret = libxlDomainStart(driver, vm, (flags & VIR_DOMAIN_START_PAUSED) != 0, -1);
2586 2587 2588
    if (ret < 0)
        goto cleanup;
    dom->id = vm->def->id;
J
Jim Fehlig 已提交
2589

2590
 cleanup:
J
Jim Fehlig 已提交
2591
    if (vm)
2592
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
2593 2594 2595 2596 2597 2598 2599 2600 2601 2602
    return ret;
}

static int
libxlDomainCreate(virDomainPtr dom)
{
    return libxlDomainCreateWithFlags(dom, 0);
}

static virDomainPtr
2603
libxlDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
J
Jim Fehlig 已提交
2604 2605
{
    libxlDriverPrivatePtr driver = conn->privateData;
2606
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
2607 2608 2609
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    virDomainPtr dom = NULL;
2610
    virObjectEventPtr event = NULL;
2611
    virDomainDefPtr oldDef = NULL;
2612
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
J
Jim Fehlig 已提交
2613

2614 2615 2616 2617
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE;
2618

2619
    if (!(def = virDomainDefParseString(xml, cfg->caps, driver->xmlopt,
M
Matthias Bolte 已提交
2620
                                        1 << VIR_DOMAIN_VIRT_XEN,
2621
                                        parse_flags)))
2622
        goto cleanup;
J
Jim Fehlig 已提交
2623

2624
    if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
2625
        goto cleanup;
2626

2627
    if (!(vm = virDomainObjListAdd(driver->domains, def,
2628
                                   driver->xmlopt,
2629 2630
                                   0,
                                   &oldDef)))
2631
        goto cleanup;
2632

J
Jim Fehlig 已提交
2633 2634 2635
    def = NULL;
    vm->persistent = 1;

2636
    if (virDomainSaveConfig(cfg->configDir,
J
Jim Fehlig 已提交
2637
                            vm->newDef ? vm->newDef : vm->def) < 0) {
2638
        virDomainObjListRemove(driver->domains, vm);
J
Jim Fehlig 已提交
2639 2640 2641 2642 2643 2644 2645 2646
        vm = NULL;
        goto cleanup;
    }

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
    if (dom)
        dom->id = vm->def->id;

2647
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_DEFINED,
2648
                                     !oldDef ?
2649 2650 2651
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

2652
 cleanup:
J
Jim Fehlig 已提交
2653
    virDomainDefFree(def);
2654
    virDomainDefFree(oldDef);
J
Jim Fehlig 已提交
2655
    if (vm)
2656
        virObjectUnlock(vm);
2657 2658
    if (event)
        libxlDomainEventQueue(driver, event);
2659
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
2660 2661 2662
    return dom;
}

2663 2664 2665 2666 2667 2668
static virDomainPtr
libxlDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return libxlDomainDefineXMLFlags(conn, xml, 0);
}

J
Jim Fehlig 已提交
2669
static int
2670 2671
libxlDomainUndefineFlags(virDomainPtr dom,
                         unsigned int flags)
J
Jim Fehlig 已提交
2672 2673
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
2674
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
2675
    virDomainObjPtr vm;
2676
    virObjectEventPtr event = NULL;
2677
    char *name = NULL;
J
Jim Fehlig 已提交
2678 2679
    int ret = -1;

2680 2681
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE, -1);

J
Jim Fehlig 已提交
2682
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
2683 2684
        goto cleanup;

2685 2686 2687
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
2688
    if (!vm->persistent) {
2689 2690
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
J
Jim Fehlig 已提交
2691 2692 2693
        goto cleanup;
    }

2694 2695 2696 2697 2698 2699 2700
    name = libxlDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    if (virFileExists(name)) {
        if (flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE) {
            if (unlink(name) < 0) {
2701 2702
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to remove domain managed save image"));
2703 2704 2705
                goto cleanup;
            }
        } else {
2706 2707 2708
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Refusing to undefine while domain managed "
                             "save image exists"));
2709 2710 2711 2712
            goto cleanup;
        }
    }

2713
    if (virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm) < 0)
J
Jim Fehlig 已提交
2714 2715
        goto cleanup;

2716
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_UNDEFINED,
2717 2718
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

2719 2720 2721
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
2722
        virDomainObjListRemove(driver->domains, vm);
2723 2724 2725
        vm = NULL;
    }

J
Jim Fehlig 已提交
2726 2727
    ret = 0;

2728
 cleanup:
2729
    VIR_FREE(name);
J
Jim Fehlig 已提交
2730
    if (vm)
2731
        virObjectUnlock(vm);
2732 2733
    if (event)
        libxlDomainEventQueue(driver, event);
2734
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
2735 2736 2737
    return ret;
}

2738 2739 2740 2741 2742 2743
static int
libxlDomainUndefine(virDomainPtr dom)
{
    return libxlDomainUndefineFlags(dom, 0);
}

2744 2745 2746 2747 2748 2749
static int
libxlDomainChangeEjectableMedia(libxlDomainObjPrivatePtr priv,
                                virDomainObjPtr vm, virDomainDiskDefPtr disk)
{
    virDomainDiskDefPtr origdisk = NULL;
    libxl_device_disk x_disk;
2750
    size_t i;
2751 2752
    int ret = -1;

2753
    for (i = 0; i < vm->def->ndisks; i++) {
2754 2755 2756 2757 2758 2759 2760 2761
        if (vm->def->disks[i]->bus == disk->bus &&
            STREQ(vm->def->disks[i]->dst, disk->dst)) {
            origdisk = vm->def->disks[i];
            break;
        }
    }

    if (!origdisk) {
2762 2763 2764
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No device with bus '%s' and target '%s'"),
                       virDomainDiskBusTypeToString(disk->bus), disk->dst);
2765 2766 2767 2768
        goto cleanup;
    }

    if (origdisk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
2769 2770 2771
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Removable media not supported for %s device"),
                       virDomainDiskDeviceTypeToString(disk->device));
2772 2773 2774
        return -1;
    }

J
Jim Fehlig 已提交
2775
    if (libxlMakeDisk(disk, &x_disk) < 0)
2776 2777
        goto cleanup;

J
Jim Fehlig 已提交
2778
    if ((ret = libxl_cdrom_insert(priv->ctx, vm->def->id, &x_disk, NULL)) < 0) {
2779 2780 2781
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to change media for disk '%s'"),
                       disk->dst);
2782 2783 2784
        goto cleanup;
    }

2785 2786 2787
    if (virDomainDiskSetSource(origdisk, virDomainDiskGetSource(disk)) < 0)
        goto cleanup;
    virDomainDiskSetType(origdisk, virDomainDiskGetType(disk));
2788 2789 2790 2791 2792

    virDomainDiskDefFree(disk);

    ret = 0;

2793
 cleanup:
2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810
    return ret;
}

static int
libxlDomainAttachDeviceDiskLive(libxlDomainObjPrivatePtr priv,
                                virDomainObjPtr vm, virDomainDeviceDefPtr dev)
{
    virDomainDiskDefPtr l_disk = dev->data.disk;
    libxl_device_disk x_disk;
    int ret = -1;

    switch (l_disk->device)  {
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
            ret = libxlDomainChangeEjectableMedia(priv, vm, l_disk);
            break;
        case VIR_DOMAIN_DISK_DEVICE_DISK:
            if (l_disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {
2811
                if (virDomainDiskIndexByName(vm->def, l_disk->dst, true) >= 0) {
2812 2813
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("target %s already exists"), l_disk->dst);
2814 2815 2816
                    goto cleanup;
                }

2817
                if (!virDomainDiskGetSource(l_disk)) {
2818 2819
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("disk source path is missing"));
2820 2821 2822
                    goto cleanup;
                }

2823
                if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
2824 2825
                    goto cleanup;

J
Jim Fehlig 已提交
2826
                if (libxlMakeDisk(l_disk, &x_disk) < 0)
2827 2828
                    goto cleanup;

J
Jim Fehlig 已提交
2829 2830
                if ((ret = libxl_device_disk_add(priv->ctx, vm->def->id,
                                                &x_disk, NULL)) < 0) {
2831 2832 2833
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("libxenlight failed to attach disk '%s'"),
                                   l_disk->dst);
2834 2835 2836 2837 2838 2839
                    goto cleanup;
                }

                virDomainDiskInsertPreAlloced(vm->def, l_disk);

            } else {
2840 2841 2842
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("disk bus '%s' cannot be hotplugged."),
                               virDomainDiskBusTypeToString(l_disk->bus));
2843 2844 2845
            }
            break;
        default:
2846 2847 2848
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("disk device type '%s' cannot be hotplugged"),
                           virDomainDiskDeviceTypeToString(l_disk->device));
2849 2850 2851
            break;
    }

2852
 cleanup:
2853 2854 2855
    return ret;
}

2856 2857 2858 2859 2860 2861 2862 2863 2864
static int
libxlDomainAttachHostPCIDevice(libxlDriverPrivatePtr driver,
                               libxlDomainObjPrivatePtr priv,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
    libxl_device_pci pcidev;
    virDomainHostdevDefPtr found;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
2865
    virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
2866 2867 2868 2869 2870 2871 2872

    if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
        return -1;

    if (virDomainHostdevFind(vm->def, hostdev, &found) >= 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("target pci device %.4x:%.2x:%.2x.%.1x already exists"),
2873 2874
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
2875 2876 2877 2878 2879 2880 2881 2882 2883
        return -1;
    }

    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
        return -1;

    if (virHostdevPreparePCIDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                    vm->def->name, vm->def->uuid,
                                    &hostdev, 1, 0) < 0)
C
Chunyan Liu 已提交
2884
        return -1;
2885

2886
    if (libxlMakePCI(hostdev, &pcidev) < 0)
C
Chunyan Liu 已提交
2887
        goto error;
2888 2889 2890 2891

    if (libxl_device_pci_add(priv->ctx, vm->def->id, &pcidev, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to attach pci device %.4x:%.2x:%.2x.%.1x"),
2892 2893
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
C
Chunyan Liu 已提交
2894
        goto error;
2895 2896 2897 2898 2899
    }

    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
    return 0;

2900
 error:
2901 2902 2903 2904 2905 2906 2907 2908 2909
    virHostdevReAttachPCIDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                 vm->def->name, &hostdev, 1, NULL);
    return -1;
}

static int
libxlDomainAttachHostDevice(libxlDriverPrivatePtr driver,
                            libxlDomainObjPrivatePtr priv,
                            virDomainObjPtr vm,
2910
                            virDomainHostdevDefPtr hostdev)
2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921
{
    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("hostdev mode '%s' not supported"),
                       virDomainHostdevModeTypeToString(hostdev->mode));
        return -1;
    }

    switch (hostdev->source.subsys.type) {
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
        if (libxlDomainAttachHostPCIDevice(driver, priv, vm, hostdev) < 0)
C
Chunyan Liu 已提交
2922
            return -1;
2923 2924 2925 2926 2927 2928
        break;

    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("hostdev subsys type '%s' not supported"),
                       virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
C
Chunyan Liu 已提交
2929
        return -1;
2930 2931 2932 2933 2934
    }

    return 0;
}

2935 2936 2937 2938 2939 2940
static int
libxlDomainDetachDeviceDiskLive(libxlDomainObjPrivatePtr priv,
                                virDomainObjPtr vm, virDomainDeviceDefPtr dev)
{
    virDomainDiskDefPtr l_disk = NULL;
    libxl_device_disk x_disk;
2941
    int idx;
2942 2943 2944 2945 2946 2947
    int ret = -1;

    switch (dev->data.disk->device)  {
        case VIR_DOMAIN_DISK_DEVICE_DISK:
            if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {

2948 2949 2950
                if ((idx = virDomainDiskIndexByName(vm->def,
                                                    dev->data.disk->dst,
                                                    false)) < 0) {
2951 2952
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("disk %s not found"), dev->data.disk->dst);
2953 2954 2955
                    goto cleanup;
                }

2956
                l_disk = vm->def->disks[idx];
2957

J
Jim Fehlig 已提交
2958
                if (libxlMakeDisk(l_disk, &x_disk) < 0)
2959 2960
                    goto cleanup;

J
Jim Fehlig 已提交
2961 2962
                if ((ret = libxl_device_disk_remove(priv->ctx, vm->def->id,
                                                    &x_disk, NULL)) < 0) {
2963 2964 2965
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("libxenlight failed to detach disk '%s'"),
                                   l_disk->dst);
2966 2967 2968
                    goto cleanup;
                }

2969
                virDomainDiskRemove(vm->def, idx);
2970 2971 2972
                virDomainDiskDefFree(l_disk);

            } else {
2973 2974 2975
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("disk bus '%s' cannot be hot unplugged."),
                               virDomainDiskBusTypeToString(dev->data.disk->bus));
2976 2977 2978
            }
            break;
        default:
2979 2980 2981
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot hot unplugged"),
                           virDomainDiskDeviceTypeToString(dev->data.disk->device));
2982 2983 2984
            break;
    }

2985
 cleanup:
2986 2987 2988
    return ret;
}

2989 2990 2991 2992 2993 2994 2995 2996 2997
static int
libxlDomainAttachNetDevice(libxlDriverPrivatePtr driver,
                           libxlDomainObjPrivatePtr priv,
                           virDomainObjPtr vm,
                           virDomainNetDefPtr net)
{
    int actualType;
    libxl_device_nic nic;
    int ret = -1;
2998
    char mac[VIR_MAC_STRING_BUFLEN];
2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012

    /* preallocate new slot for device */
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0)
        return -1;

    /* If appropriate, grab a physical device from the configured
     * network's pool of devices, or resolve bridge device name
     * to the one defined in the network definition.
     */
    if (networkAllocateActualDevice(vm->def, net) < 0)
        return -1;

    actualType = virDomainNetGetActualType(net);

3013 3014 3015 3016 3017 3018 3019
    if (virDomainHasNet(vm->def, net)) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("network device with mac %s already exists"),
                       virMacAddrFormat(&net->mac, mac));
        return -1;
    }

3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050
    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        /* This is really a "smart hostdev", so it should be attached
         * as a hostdev (the hostdev code will reach over into the
         * netdev-specific code as appropriate), then also added to
         * the nets list (see out:) if successful.
         */
        ret = libxlDomainAttachHostDevice(driver, priv, vm,
                                          virDomainNetGetActualHostdev(net));
        goto out;
    }

    libxl_device_nic_init(&nic);
    if (libxlMakeNic(vm->def, net, &nic) < 0)
        goto cleanup;

    if (libxl_device_nic_add(priv->ctx, vm->def->id, &nic, 0)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxenlight failed to attach network device"));
        goto cleanup;
    }

    ret = 0;

 cleanup:
    libxl_device_nic_dispose(&nic);
 out:
    if (!ret)
        vm->def->nets[vm->def->nnets++] = net;
    return ret;
}

3051
static int
3052 3053 3054
libxlDomainAttachDeviceLive(libxlDriverPrivatePtr driver,
                            libxlDomainObjPrivatePtr priv,
                            virDomainObjPtr vm,
3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
            ret = libxlDomainAttachDeviceDiskLive(priv, vm, dev);
            if (!ret)
                dev->data.disk = NULL;
            break;

3066 3067 3068 3069 3070 3071 3072
        case VIR_DOMAIN_DEVICE_NET:
            ret = libxlDomainAttachNetDevice(driver, priv, vm,
                                             dev->data.net);
            if (!ret)
                dev->data.net = NULL;
            break;

3073
        case VIR_DOMAIN_DEVICE_HOSTDEV:
3074 3075
            ret = libxlDomainAttachHostDevice(driver, priv, vm,
                                              dev->data.hostdev);
3076 3077 3078 3079
            if (!ret)
                dev->data.hostdev = NULL;
            break;

3080
        default:
3081 3082 3083
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot be attached"),
                           virDomainDeviceTypeToString(dev->type));
3084 3085 3086 3087 3088 3089 3090 3091 3092 3093
            break;
    }

    return ret;
}

static int
libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
{
    virDomainDiskDefPtr disk;
3094
    virDomainNetDefPtr net;
3095 3096
    virDomainHostdevDefPtr hostdev;
    virDomainHostdevDefPtr found;
3097
    virDomainHostdevSubsysPCIPtr pcisrc;
3098
    char mac[VIR_MAC_STRING_BUFLEN];
3099 3100 3101 3102

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
            disk = dev->data.disk;
3103
            if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
3104 3105
                virReportError(VIR_ERR_INVALID_ARG,
                               _("target %s already exists."), disk->dst);
3106 3107
                return -1;
            }
3108
            if (virDomainDiskInsert(vmdef, disk))
3109 3110 3111 3112
                return -1;
            /* vmdef has the pointer. Generic codes for vmdef will do all jobs */
            dev->data.disk = NULL;
            break;
3113 3114 3115

        case VIR_DOMAIN_DEVICE_NET:
            net = dev->data.net;
3116 3117 3118 3119 3120 3121
            if (virDomainHasNet(vmdef, net)) {
                virReportError(VIR_ERR_INVALID_ARG,
                               _("network device with mac %s already exists"),
                               virMacAddrFormat(&net->mac, mac));
                return -1;
            }
3122 3123 3124 3125 3126
            if (virDomainNetInsert(vmdef, net))
                return -1;
            dev->data.net = NULL;
            break;

3127 3128 3129 3130 3131 3132 3133
        case VIR_DOMAIN_DEVICE_HOSTDEV:
            hostdev = dev->data.hostdev;

            if (hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
                return -1;

            if (virDomainHostdevFind(vmdef, hostdev, &found) >= 0) {
3134
                pcisrc = &hostdev->source.subsys.u.pci;
3135 3136 3137
                virReportError(VIR_ERR_OPERATION_FAILED,
                               _("target pci device %.4x:%.2x:%.2x.%.1x\
                                  already exists"),
3138 3139
                               pcisrc->addr.domain, pcisrc->addr.bus,
                               pcisrc->addr.slot, pcisrc->addr.function);
3140 3141 3142
                return -1;
            }

3143 3144
            if (virDomainHostdevInsert(vmdef, hostdev) < 0)
                return -1;
3145
            break;
3146 3147

        default:
3148 3149
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("persistent attach of device is not supported"));
3150 3151 3152 3153 3154 3155
            return -1;
    }
    return 0;
}

static int
3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190
libxlComparePCIDevice(virDomainDefPtr def ATTRIBUTE_UNUSED,
                      virDomainDeviceDefPtr device ATTRIBUTE_UNUSED,
                      virDomainDeviceInfoPtr info1,
                      void *opaque)
{
    virDomainDeviceInfoPtr info2 = opaque;

    if (info1->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI ||
        info2->type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_PCI)
        return 0;

    if (info1->addr.pci.domain == info2->addr.pci.domain &&
        info1->addr.pci.bus == info2->addr.pci.bus &&
        info1->addr.pci.slot == info2->addr.pci.slot &&
        info1->addr.pci.function != info2->addr.pci.function)
        return -1;
    return 0;
}

static bool
libxlIsMultiFunctionDevice(virDomainDefPtr def,
                           virDomainDeviceInfoPtr dev)
{
    if (virDomainDeviceInfoIterate(def, libxlComparePCIDevice, dev) < 0)
        return true;
    return false;
}

static int
libxlDomainDetachHostPCIDevice(libxlDriverPrivatePtr driver,
                               libxlDomainObjPrivatePtr priv,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
    virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
3191
    virDomainHostdevSubsysPCIPtr pcisrc = &subsys->u.pci;
3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203
    libxl_device_pci pcidev;
    virDomainHostdevDefPtr detach;
    int idx;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;

    if (subsys->type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
        return -1;

    idx = virDomainHostdevFind(vm->def, hostdev, &detach);
    if (idx < 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("host pci device %.4x:%.2x:%.2x.%.1x not found"),
3204 3205
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
3206 3207 3208 3209 3210 3211
        return -1;
    }

    if (libxlIsMultiFunctionDevice(vm->def, detach->info)) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("cannot hot unplug multifunction PCI device: %.4x:%.2x:%.2x.%.1x"),
3212 3213
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
C
Chunyan Liu 已提交
3214
        goto error;
3215 3216 3217 3218 3219
    }


    libxl_device_pci_init(&pcidev);

3220
    if (libxlMakePCI(detach, &pcidev) < 0)
C
Chunyan Liu 已提交
3221
        goto error;
3222 3223 3224 3225 3226

    if (libxl_device_pci_remove(priv->ctx, vm->def->id, &pcidev, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to detach pci device\
                          %.4x:%.2x:%.2x.%.1x"),
3227 3228
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
C
Chunyan Liu 已提交
3229
        goto error;
3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240
    }

    libxl_device_pci_dispose(&pcidev);

    virDomainHostdevRemove(vm->def, idx);

    virHostdevReAttachPCIDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                 vm->def->name, &hostdev, 1, NULL);

    return 0;

3241
 error:
3242 3243 3244 3245 3246 3247 3248 3249
    virDomainHostdevDefFree(detach);
    return -1;
}

static int
libxlDomainDetachHostDevice(libxlDriverPrivatePtr driver,
                            libxlDomainObjPrivatePtr priv,
                            virDomainObjPtr vm,
3250
                            virDomainHostdevDefPtr hostdev)
3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273
{
    virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;

    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("hostdev mode '%s' not supported"),
                       virDomainHostdevModeTypeToString(hostdev->mode));
        return -1;
    }

    switch (subsys->type) {
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI:
            return libxlDomainDetachHostPCIDevice(driver, priv, vm, hostdev);

        default:
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected hostdev type %d"), subsys->type);
            break;
    }

    return -1;
}

3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 3315 3316 3317 3318 3319 3320
static int
libxlDomainDetachNetDevice(libxlDriverPrivatePtr driver,
                           libxlDomainObjPrivatePtr priv,
                           virDomainObjPtr vm,
                           virDomainNetDefPtr net)
{
    int detachidx;
    virDomainNetDefPtr detach = NULL;
    libxl_device_nic nic;
    char mac[VIR_MAC_STRING_BUFLEN];
    int ret = -1;

    if ((detachidx = virDomainNetFindIdx(vm->def, net)) < 0)
        return -1;

    detach = vm->def->nets[detachidx];

    if (virDomainNetGetActualType(detach) == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
        /* This is really a "smart hostdev", so it should be attached as a
         * hostdev, then also removed from nets list (see out:) if successful.
         */
        ret = libxlDomainDetachHostDevice(driver, priv, vm,
                                          virDomainNetGetActualHostdev(detach));
        goto out;
    }

    libxl_device_nic_init(&nic);
    if (libxl_mac_to_device_nic(priv->ctx, vm->def->id,
                                virMacAddrFormat(&detach->mac, mac), &nic))
        goto cleanup;

    if (libxl_device_nic_remove(priv->ctx, vm->def->id, &nic, 0)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxenlight failed to detach network device"));
        goto cleanup;
    }

    ret = 0;

 cleanup:
    libxl_device_nic_dispose(&nic);
 out:
    if (!ret)
        virDomainNetRemove(vm->def, detachidx);
    return ret;
}

3321 3322 3323 3324
static int
libxlDomainDetachDeviceLive(libxlDriverPrivatePtr driver,
                            libxlDomainObjPrivatePtr priv,
                            virDomainObjPtr vm,
3325 3326 3327 3328 3329 3330 3331 3332 3333
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
            ret = libxlDomainDetachDeviceDiskLive(priv, vm, dev);
            break;

3334 3335 3336 3337 3338
        case VIR_DOMAIN_DEVICE_NET:
            ret = libxlDomainDetachNetDevice(driver, priv, vm,
                                             dev->data.net);
            break;

3339
        case VIR_DOMAIN_DEVICE_HOSTDEV:
3340 3341
            ret = libxlDomainDetachHostDevice(driver, priv, vm,
                                              dev->data.hostdev);
3342 3343
            break;

3344
        default:
3345 3346 3347
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot be detached"),
                           virDomainDeviceTypeToString(dev->type));
3348 3349 3350 3351 3352 3353
            break;
    }

    return ret;
}

3354

3355 3356 3357
static int
libxlDomainDetachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
{
3358
    virDomainDiskDefPtr disk, detach;
3359
    virDomainHostdevDefPtr hostdev, det_hostdev;
3360
    virDomainNetDefPtr net;
3361
    int idx;
3362 3363 3364 3365

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
            disk = dev->data.disk;
3366
            if (!(detach = virDomainDiskRemoveByName(vmdef, disk->dst))) {
3367 3368
                virReportError(VIR_ERR_INVALID_ARG,
                               _("no target device %s"), disk->dst);
3369
                return -1;
3370
            }
3371
            virDomainDiskDefFree(detach);
3372
            break;
3373

3374 3375 3376 3377 3378 3379 3380 3381 3382
        case VIR_DOMAIN_DEVICE_NET:
            net = dev->data.net;
            if ((idx = virDomainNetFindIdx(vmdef, net)) < 0)
                return -1;

            /* this is guaranteed to succeed */
            virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
            break;

3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394
        case VIR_DOMAIN_DEVICE_HOSTDEV: {
            hostdev = dev->data.hostdev;
            if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) {
                virReportError(VIR_ERR_INVALID_ARG, "%s",
                               _("device not present in domain configuration"));
                return -1;
            }
            virDomainHostdevRemove(vmdef, idx);
            virDomainHostdevDefFree(det_hostdev);
            break;
        }

3395
        default:
3396 3397
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("persistent detach of device is not supported"));
3398
            return -1;
3399 3400
    }

3401
    return 0;
3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420
}

static int
libxlDomainUpdateDeviceLive(libxlDomainObjPrivatePtr priv,
                            virDomainObjPtr vm, virDomainDeviceDefPtr dev)
{
    virDomainDiskDefPtr disk;
    int ret = -1;

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
            disk = dev->data.disk;
            switch (disk->device) {
                case VIR_DOMAIN_DISK_DEVICE_CDROM:
                    ret = libxlDomainChangeEjectableMedia(priv, vm, disk);
                    if (ret == 0)
                        dev->data.disk = NULL;
                    break;
                default:
3421 3422 3423
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("disk bus '%s' cannot be updated."),
                                   virDomainDiskBusTypeToString(disk->bus));
3424 3425 3426 3427
                    break;
            }
            break;
        default:
3428 3429 3430
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot be updated"),
                           virDomainDeviceTypeToString(dev->type));
3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441
            break;
    }

    return ret;
}

static int
libxlDomainUpdateDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
{
    virDomainDiskDefPtr orig;
    virDomainDiskDefPtr disk;
3442
    int idx;
3443 3444 3445 3446 3447
    int ret = -1;

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
            disk = dev->data.disk;
3448
            if ((idx = virDomainDiskIndexByName(vmdef, disk->dst, false)) < 0) {
3449 3450
                virReportError(VIR_ERR_INVALID_ARG,
                               _("target %s doesn't exist."), disk->dst);
3451 3452
                goto cleanup;
            }
3453
            orig = vmdef->disks[idx];
3454
            if (!(orig->device == VIR_DOMAIN_DISK_DEVICE_CDROM)) {
3455 3456
                virReportError(VIR_ERR_INVALID_ARG, "%s",
                               _("this disk doesn't support update"));
3457 3458 3459
                goto cleanup;
            }

3460 3461 3462 3463 3464 3465
            if (virDomainDiskSetSource(orig, virDomainDiskGetSource(disk)) < 0)
                goto cleanup;
            virDomainDiskSetType(orig, virDomainDiskGetType(disk));
            virDomainDiskSetFormat(orig, virDomainDiskGetFormat(disk));
            if (virDomainDiskSetDriver(orig, virDomainDiskGetDriver(disk)) < 0)
                goto cleanup;
3466 3467
            break;
        default:
3468 3469
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("persistent update of device is not supported"));
3470 3471 3472 3473 3474
            goto cleanup;
    }

    ret = 0;

3475
 cleanup:
3476 3477 3478 3479 3480
    return ret;
}


static int
3481 3482
libxlDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                             unsigned int flags)
3483 3484
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
3485
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3486 3487 3488 3489 3490 3491 3492 3493 3494
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL;
    libxlDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

J
Jim Fehlig 已提交
3495
    if (!(vm = libxlDomObjFromDomain(dom)))
3496 3497
        goto cleanup;

3498 3499 3500
    if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

3501 3502 3503
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

3504 3505 3506 3507 3508 3509 3510 3511
    if (virDomainObjIsActive(vm)) {
        if (flags == VIR_DOMAIN_DEVICE_MODIFY_CURRENT)
            flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
    } else {
        if (flags == VIR_DOMAIN_DEVICE_MODIFY_CURRENT)
            flags |= VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
        /* check consistency between flags and the vm state */
        if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
3512 3513
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("Domain is not running"));
3514
            goto endjob;
3515 3516 3517 3518
        }
    }

    if ((flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) && !vm->persistent) {
3519 3520
         virReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify device on transient domain"));
3521
         goto endjob;
3522 3523 3524 3525 3526
    }

    priv = vm->privateData;

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
3527
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
3528
                                            cfg->caps, driver->xmlopt,
3529
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
3530
            goto endjob;
3531 3532

        /* Make a copy for updated domain. */
3533
        if (!(vmdef = virDomainObjCopyPersistentDef(vm, cfg->caps,
3534
                                                    driver->xmlopt)))
3535
            goto endjob;
3536

3537
        if (libxlDomainAttachDeviceConfig(vmdef, dev) < 0)
3538
            goto endjob;
3539
    }
3540 3541 3542 3543

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
        /* If dev exists it was created to modify the domain config. Free it. */
        virDomainDeviceDefFree(dev);
3544
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
3545
                                            cfg->caps, driver->xmlopt,
3546
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
3547
            goto endjob;
3548

3549
        if (libxlDomainAttachDeviceLive(driver, priv, vm, dev) < 0)
3550
            goto endjob;
3551

3552 3553 3554 3555
        /*
         * update domain status forcibly because the domain status may be
         * changed even if we attach the device failed.
         */
3556
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
3557
            goto endjob;
3558 3559
    }

3560 3561
    ret = 0;

3562
    /* Finally, if no error until here, we can save config. */
3563
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
3564
        ret = virDomainSaveConfig(cfg->configDir, vmdef);
3565
        if (!ret) {
3566
            virDomainObjAssignDef(vm, vmdef, false, NULL);
3567 3568 3569 3570
            vmdef = NULL;
        }
    }

3571
 endjob:
3572 3573 3574
    if (!libxlDomainObjEndJob(driver, vm))
        vm = NULL;

3575
 cleanup:
3576 3577 3578
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
    if (vm)
3579
        virObjectUnlock(vm);
3580
    virObjectUnref(cfg);
3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594
    return ret;
}

static int
libxlDomainAttachDevice(virDomainPtr dom, const char *xml)
{
    return libxlDomainAttachDeviceFlags(dom, xml,
                                        VIR_DOMAIN_DEVICE_MODIFY_LIVE);
}

static int
libxlDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                             unsigned int flags)
{
3595
    libxlDriverPrivatePtr driver = dom->conn->privateData;
3596
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3597 3598 3599 3600 3601 3602 3603 3604 3605
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL;
    libxlDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

J
Jim Fehlig 已提交
3606
    if (!(vm = libxlDomObjFromDomain(dom)))
3607 3608
        goto cleanup;

3609 3610 3611
    if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

3612 3613 3614
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

3615 3616 3617 3618 3619 3620 3621 3622 3623 3624
    if (virDomainObjIsActive(vm)) {
        if (flags == VIR_DOMAIN_DEVICE_MODIFY_CURRENT)
            flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
    } else {
        if (flags == VIR_DOMAIN_DEVICE_MODIFY_CURRENT)
            flags |= VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
        /* check consistency between flags and the vm state */
        if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("Domain is not running"));
3625
            goto endjob;
3626 3627 3628 3629 3630 3631
        }
    }

    if ((flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) && !vm->persistent) {
         virReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify device on transient domain"));
3632
         goto endjob;
3633 3634 3635 3636 3637 3638
    }

    priv = vm->privateData;

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
3639
                                            cfg->caps, driver->xmlopt,
3640
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
3641
            goto endjob;
3642 3643

        /* Make a copy for updated domain. */
3644
        if (!(vmdef = virDomainObjCopyPersistentDef(vm, cfg->caps,
3645
                                                    driver->xmlopt)))
3646
            goto endjob;
3647

3648
        if (libxlDomainDetachDeviceConfig(vmdef, dev) < 0)
3649
            goto endjob;
3650 3651 3652 3653 3654 3655
    }

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
        /* If dev exists it was created to modify the domain config. Free it. */
        virDomainDeviceDefFree(dev);
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
3656
                                            cfg->caps, driver->xmlopt,
3657
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
3658
            goto endjob;
3659

3660
        if (libxlDomainDetachDeviceLive(driver, priv, vm, dev) < 0)
3661
            goto endjob;
3662 3663 3664 3665 3666

        /*
         * update domain status forcibly because the domain status may be
         * changed even if we attach the device failed.
         */
3667
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
3668
            goto endjob;
3669 3670
    }

3671 3672
    ret = 0;

3673
    /* Finally, if no error until here, we can save config. */
3674
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
3675
        ret = virDomainSaveConfig(cfg->configDir, vmdef);
3676 3677 3678 3679 3680 3681
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

3682
 endjob:
3683 3684 3685
    if (!libxlDomainObjEndJob(driver, vm))
        vm = NULL;

3686
 cleanup:
3687 3688 3689 3690
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
    if (vm)
        virObjectUnlock(vm);
3691
    virObjectUnref(cfg);
3692
    return ret;
3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705
}

static int
libxlDomainDetachDevice(virDomainPtr dom, const char *xml)
{
    return libxlDomainDetachDeviceFlags(dom, xml,
                                        VIR_DOMAIN_DEVICE_MODIFY_LIVE);
}

static int
libxlDomainUpdateDeviceFlags(virDomainPtr dom, const char *xml,
                             unsigned int flags)
{
3706
    libxlDriverPrivatePtr driver = dom->conn->privateData;
3707
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3708 3709 3710 3711 3712 3713 3714 3715 3716
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL;
    libxlDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

J
Jim Fehlig 已提交
3717
    if (!(vm = libxlDomObjFromDomain(dom)))
3718 3719
        goto cleanup;

3720 3721 3722
    if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746
    if (virDomainObjIsActive(vm)) {
        if (flags == VIR_DOMAIN_DEVICE_MODIFY_CURRENT)
            flags |= VIR_DOMAIN_DEVICE_MODIFY_LIVE;
    } else {
        if (flags == VIR_DOMAIN_DEVICE_MODIFY_CURRENT)
            flags |= VIR_DOMAIN_DEVICE_MODIFY_CONFIG;
        /* check consistency between flags and the vm state */
        if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("Domain is not running"));
            goto cleanup;
        }
    }

    if ((flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) && !vm->persistent) {
         virReportError(VIR_ERR_OPERATION_INVALID,
                        "%s", _("cannot modify device on transient domain"));
         goto cleanup;
    }

    priv = vm->privateData;

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
3747
                                            cfg->caps, driver->xmlopt,
3748
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
3749 3750 3751
            goto cleanup;

        /* Make a copy for updated domain. */
3752
        if (!(vmdef = virDomainObjCopyPersistentDef(vm, cfg->caps,
3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764 3765
                                                    driver->xmlopt)))
            goto cleanup;

        if ((ret = libxlDomainUpdateDeviceConfig(vmdef, dev)) < 0)
            goto cleanup;
    } else {
        ret = 0;
    }

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_LIVE) {
        /* If dev exists it was created to modify the domain config. Free it. */
        virDomainDeviceDefFree(dev);
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
3766
                                            cfg->caps, driver->xmlopt,
3767
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
3768 3769 3770 3771 3772 3773 3774 3775 3776
            goto cleanup;

        if ((ret = libxlDomainUpdateDeviceLive(priv, vm, dev)) < 0)
            goto cleanup;

        /*
         * update domain status forcibly because the domain status may be
         * changed even if we attach the device failed.
         */
3777
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
3778 3779 3780 3781 3782
            ret = -1;
    }

    /* Finally, if no error until here, we can save config. */
    if (!ret && (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG)) {
3783
        ret = virDomainSaveConfig(cfg->configDir, vmdef);
3784 3785 3786 3787 3788 3789
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

3790
 cleanup:
3791 3792 3793 3794
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
    if (vm)
        virObjectUnlock(vm);
3795
    virObjectUnref(cfg);
3796
    return ret;
3797 3798
}

3799 3800 3801 3802 3803
static unsigned long long
libxlNodeGetFreeMemory(virConnectPtr conn)
{
    libxl_physinfo phy_info;
    libxlDriverPrivatePtr driver = conn->privateData;
3804 3805
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    unsigned long long ret = 0;
3806

3807
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
3808
        goto cleanup;
3809

3810
    if (libxl_get_physinfo(cfg->ctx, &phy_info)) {
3811 3812
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxl_get_physinfo_info failed"));
3813
        goto cleanup;
3814 3815
    }

3816 3817
    ret = phy_info.free_pages * cfg->verInfo->pagesize;

3818
 cleanup:
3819 3820
    virObjectUnref(cfg);
    return ret;
3821 3822
}

3823 3824 3825 3826 3827 3828 3829 3830 3831 3832
static int
libxlNodeGetCellsFreeMemory(virConnectPtr conn,
                            unsigned long long *freeMems,
                            int startCell,
                            int maxCells)
{
    int n, lastCell, numCells;
    int ret = -1, nr_nodes = 0;
    libxl_numainfo *numa_info = NULL;
    libxlDriverPrivatePtr driver = conn->privateData;
3833
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3834 3835

    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
3836
        goto cleanup;
3837

3838
    numa_info = libxl_get_numainfo(cfg->ctx, &nr_nodes);
3839
    if (numa_info == NULL || nr_nodes == 0) {
3840 3841 3842
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxl_get_numainfo failed"));
        goto cleanup;
3843 3844 3845
    }

    /* Check/sanitize the cell range */
3846
    if (startCell >= nr_nodes) {
3847 3848
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("start cell %d out of range (0-%d)"),
3849
                       startCell, nr_nodes - 1);
3850 3851 3852
        goto cleanup;
    }
    lastCell = startCell + maxCells - 1;
3853 3854
    if (lastCell >= nr_nodes)
        lastCell = nr_nodes - 1;
3855 3856 3857 3858 3859 3860 3861

    for (numCells = 0, n = startCell; n <= lastCell; n++) {
        if (numa_info[n].size == LIBXL_NUMAINFO_INVALID_ENTRY)
            freeMems[numCells++] = 0;
        else
            freeMems[numCells++] = numa_info[n].free;
    }
3862

3863 3864
    ret = numCells;

3865
 cleanup:
3866
    libxl_numainfo_list_free(numa_info, nr_nodes);
3867
    virObjectUnref(cfg);
3868 3869 3870
    return ret;
}

3871
static int
3872
libxlConnectDomainEventRegister(virConnectPtr conn,
3873 3874
                                virConnectDomainEventCallback callback,
                                void *opaque,
3875
                                virFreeCallback freecb)
3876 3877 3878
{
    libxlDriverPrivatePtr driver = conn->privateData;

3879 3880 3881
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

3882 3883 3884 3885
    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        return -1;
3886

3887
    return 0;
3888 3889 3890 3891
}


static int
3892 3893
libxlConnectDomainEventDeregister(virConnectPtr conn,
                                  virConnectDomainEventCallback callback)
3894 3895 3896
{
    libxlDriverPrivatePtr driver = conn->privateData;

3897 3898 3899
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

3900 3901 3902 3903
    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        return -1;
3904

3905
    return 0;
3906 3907
}

3908 3909 3910 3911 3912 3913
static int
libxlDomainGetAutostart(virDomainPtr dom, int *autostart)
{
    virDomainObjPtr vm;
    int ret = -1;

J
Jim Fehlig 已提交
3914
    if (!(vm = libxlDomObjFromDomain(dom)))
3915 3916
        goto cleanup;

3917 3918 3919
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3920 3921 3922
    *autostart = vm->autostart;
    ret = 0;

3923
 cleanup:
3924
    if (vm)
3925
        virObjectUnlock(vm);
3926 3927 3928 3929 3930 3931 3932
    return ret;
}

static int
libxlDomainSetAutostart(virDomainPtr dom, int autostart)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
3933
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3934 3935 3936 3937
    virDomainObjPtr vm;
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

J
Jim Fehlig 已提交
3938
    if (!(vm = libxlDomObjFromDomain(dom)))
3939 3940
        goto cleanup;

3941 3942 3943
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3944 3945 3946
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

3947
    if (!vm->persistent) {
3948 3949
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient domain"));
3950
        goto endjob;
3951 3952 3953 3954 3955
    }

    autostart = (autostart != 0);

    if (vm->autostart != autostart) {
3956
        if (!(configFile = virDomainConfigFile(cfg->configDir, vm->def->name)))
3957
            goto endjob;
3958
        if (!(autostartLink = virDomainConfigFile(cfg->autostartDir, vm->def->name)))
3959
            goto endjob;
3960 3961

        if (autostart) {
3962
            if (virFileMakePath(cfg->autostartDir) < 0) {
3963
                virReportSystemError(errno,
3964
                                     _("cannot create autostart directory %s"),
3965
                                     cfg->autostartDir);
3966
                goto endjob;
3967 3968 3969 3970 3971 3972
            }

            if (symlink(configFile, autostartLink) < 0) {
                virReportSystemError(errno,
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
3973
                goto endjob;
3974 3975 3976 3977 3978 3979
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
                virReportSystemError(errno,
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
3980
                goto endjob;
3981 3982 3983 3984 3985 3986 3987
            }
        }

        vm->autostart = autostart;
    }
    ret = 0;

3988
 endjob:
3989 3990 3991
    if (!libxlDomainObjEndJob(driver, vm))
        vm = NULL;

3992
 cleanup:
3993 3994 3995
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
    if (vm)
3996
        virObjectUnlock(vm);
3997
    virObjectUnref(cfg);
3998 3999 4000
    return ret;
}

4001 4002 4003 4004 4005 4006
static char *
libxlDomainGetSchedulerType(virDomainPtr dom, int *nparams)
{
    libxlDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    char * ret = NULL;
4007
    const char *name = NULL;
J
Jim Fehlig 已提交
4008
    libxl_scheduler sched_id;
4009

J
Jim Fehlig 已提交
4010
    if (!(vm = libxlDomObjFromDomain(dom)))
4011 4012
        goto cleanup;

4013 4014 4015
    if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4016
    if (!virDomainObjIsActive(vm)) {
4017
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
4018 4019 4020 4021
        goto cleanup;
    }

    priv = vm->privateData;
J
Jim Fehlig 已提交
4022
    sched_id = libxl_get_scheduler(priv->ctx);
4023

4024 4025
    if (nparams)
        *nparams = 0;
4026
    switch (sched_id) {
J
Jim Fehlig 已提交
4027
    case LIBXL_SCHEDULER_SEDF:
4028
        name = "sedf";
4029
        break;
J
Jim Fehlig 已提交
4030
    case LIBXL_SCHEDULER_CREDIT:
4031
        name = "credit";
4032 4033
        if (nparams)
            *nparams = XEN_SCHED_CREDIT_NPARAM;
4034
        break;
J
Jim Fehlig 已提交
4035
    case LIBXL_SCHEDULER_CREDIT2:
4036
        name = "credit2";
4037
        break;
J
Jim Fehlig 已提交
4038
    case LIBXL_SCHEDULER_ARINC653:
4039
        name = "arinc653";
4040 4041
        break;
    default:
J
Jim Fehlig 已提交
4042 4043
        virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Failed to get scheduler id for domain '%d'"
4044
                     " with libxenlight"), vm->def->id);
4045 4046 4047
        goto cleanup;
    }

4048
    ignore_value(VIR_STRDUP(ret, name));
4049

4050
 cleanup:
4051
    if (vm)
4052
        virObjectUnlock(vm);
4053 4054 4055
    return ret;
}

4056
static int
4057 4058 4059 4060
libxlDomainGetSchedulerParametersFlags(virDomainPtr dom,
                                       virTypedParameterPtr params,
                                       int *nparams,
                                       unsigned int flags)
4061 4062 4063
{
    libxlDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
4064 4065
    libxl_domain_sched_params sc_info;
    libxl_scheduler sched_id;
4066 4067
    int ret = -1;

4068 4069 4070 4071
    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
4072

J
Jim Fehlig 已提交
4073
    if (!(vm = libxlDomObjFromDomain(dom)))
4074 4075
        goto cleanup;

4076 4077 4078
    if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4079
    if (!virDomainObjIsActive(vm)) {
J
Jim Fehlig 已提交
4080 4081
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not running"));
4082 4083 4084 4085 4086
        goto cleanup;
    }

    priv = vm->privateData;

J
Jim Fehlig 已提交
4087
    sched_id = libxl_get_scheduler(priv->ctx);
4088

J
Jim Fehlig 已提交
4089
    if (sched_id != LIBXL_SCHEDULER_CREDIT) {
4090 4091
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Only 'credit' scheduler is supported"));
4092 4093 4094
        goto cleanup;
    }

4095
    if (libxl_domain_sched_params_get(priv->ctx, vm->def->id, &sc_info) != 0) {
4096 4097
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to get scheduler parameters for domain '%d'"
4098
                         " with libxenlight"), vm->def->id);
4099 4100 4101
        goto cleanup;
    }

4102 4103
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_WEIGHT,
                                VIR_TYPED_PARAM_UINT, sc_info.weight) < 0)
4104 4105
        goto cleanup;

4106
    if (*nparams > 1) {
4107 4108
        if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CAP,
                                    VIR_TYPED_PARAM_UINT, sc_info.cap) < 0)
4109
            goto cleanup;
4110 4111
    }

4112 4113
    if (*nparams > XEN_SCHED_CREDIT_NPARAM)
        *nparams = XEN_SCHED_CREDIT_NPARAM;
4114 4115
    ret = 0;

4116
 cleanup:
4117
    if (vm)
4118
        virObjectUnlock(vm);
4119 4120 4121 4122
    return ret;
}

static int
4123 4124 4125 4126 4127 4128 4129 4130 4131 4132 4133
libxlDomainGetSchedulerParameters(virDomainPtr dom, virTypedParameterPtr params,
                                  int *nparams)
{
    return libxlDomainGetSchedulerParametersFlags(dom, params, nparams, 0);
}

static int
libxlDomainSetSchedulerParametersFlags(virDomainPtr dom,
                                       virTypedParameterPtr params,
                                       int nparams,
                                       unsigned int flags)
4134
{
4135
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4136 4137
    libxlDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
4138
    libxl_domain_sched_params sc_info;
4139
    int sched_id;
4140
    size_t i;
4141 4142
    int ret = -1;

4143
    virCheckFlags(0, -1);
4144 4145 4146 4147 4148 4149
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_SCHEDULER_WEIGHT,
                               VIR_TYPED_PARAM_UINT,
                               VIR_DOMAIN_SCHEDULER_CAP,
                               VIR_TYPED_PARAM_UINT,
                               NULL) < 0)
4150
        return -1;
4151

J
Jim Fehlig 已提交
4152
    if (!(vm = libxlDomObjFromDomain(dom)))
4153 4154
        goto cleanup;

4155 4156 4157
    if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4158 4159 4160
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

4161
    if (!virDomainObjIsActive(vm)) {
4162
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
4163
        goto endjob;
4164 4165 4166 4167
    }

    priv = vm->privateData;

J
Jim Fehlig 已提交
4168
    sched_id = libxl_get_scheduler(priv->ctx);
4169

J
Jim Fehlig 已提交
4170
    if (sched_id != LIBXL_SCHEDULER_CREDIT) {
4171 4172
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Only 'credit' scheduler is supported"));
4173
        goto endjob;
4174 4175
    }

4176
    if (libxl_domain_sched_params_get(priv->ctx, vm->def->id, &sc_info) != 0) {
4177 4178
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to get scheduler parameters for domain '%d'"
4179
                         " with libxenlight"), vm->def->id);
4180
        goto endjob;
4181 4182 4183
    }

    for (i = 0; i < nparams; ++i) {
4184
        virTypedParameterPtr param = &params[i];
4185

4186
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_WEIGHT))
4187
            sc_info.weight = params[i].value.ui;
4188
        else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CAP))
4189 4190 4191
            sc_info.cap = params[i].value.ui;
    }

4192
    if (libxl_domain_sched_params_set(priv->ctx, vm->def->id, &sc_info) != 0) {
4193 4194
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to set scheduler parameters for domain '%d'"
4195
                         " with libxenlight"), vm->def->id);
4196
        goto endjob;
4197 4198 4199 4200
    }

    ret = 0;

4201
 endjob:
4202 4203 4204
    if (!libxlDomainObjEndJob(driver, vm))
        vm = NULL;

4205
 cleanup:
4206
    if (vm)
4207
        virObjectUnlock(vm);
4208 4209 4210
    return ret;
}

B
Bamvor Jian Zhang 已提交
4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231

static int
libxlDomainOpenConsole(virDomainPtr dom,
                       const char *dev_name,
                       virStreamPtr st,
                       unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainChrDefPtr chr = NULL;
    libxlDomainObjPrivatePtr priv;

    virCheckFlags(VIR_DOMAIN_CONSOLE_FORCE, -1);

    if (dev_name) {
        /* XXX support device aliases in future */
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Named device aliases are not supported"));
        goto cleanup;
    }

J
Jim Fehlig 已提交
4232
    if (!(vm = libxlDomObjFromDomain(dom)))
B
Bamvor Jian Zhang 已提交
4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245
        goto cleanup;

    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto cleanup;
    }

    priv = vm->privateData;

I
Ian Campbell 已提交
4246 4247
    if (vm->def->nconsoles)
        chr = vm->def->consoles[0];
B
Bamvor Jian Zhang 已提交
4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270 4271 4272 4273 4274

    if (!chr) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find character device %s"),
                       NULLSTR(dev_name));
        goto cleanup;
    }

    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("character device %s is not using a PTY"),
                       NULLSTR(dev_name));
        goto cleanup;
    }

    /* handle mutually exclusive access to console devices */
    ret = virChrdevOpen(priv->devs,
                        &chr->source,
                        st,
                        (flags & VIR_DOMAIN_CONSOLE_FORCE) != 0);

    if (ret == 1) {
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Active console session exists for this domain"));
        ret = -1;
    }

4275
 cleanup:
B
Bamvor Jian Zhang 已提交
4276 4277 4278 4279 4280
    if (vm)
        virObjectUnlock(vm);
    return ret;
}

4281 4282 4283 4284 4285 4286 4287
static int
libxlDomainSetSchedulerParameters(virDomainPtr dom, virTypedParameterPtr params,
                                  int nparams)
{
    return libxlDomainSetSchedulerParametersFlags(dom, params, nparams, 0);
}

4288 4289 4290 4291 4292 4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 4317
/* NUMA node affinity information is available through libxl
 * starting from Xen 4.3. */
#ifdef LIBXL_HAVE_DOMAIN_NODEAFFINITY

/* Number of Xen NUMA parameters */
# define LIBXL_NUMA_NPARAM 2

static int
libxlDomainGetNumaParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
{
    libxlDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    libxl_bitmap nodemap;
    virBitmapPtr nodes = NULL;
    char *nodeset = NULL;
    int rc, ret = -1;
    size_t i, j;

    /* In Xen 4.3, it is possible to query the NUMA node affinity of a domain
     * via libxl, but not to change it. We therefore only allow AFFECT_LIVE. */
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    /* We blindly return a string, and let libvirt.c and remote_driver.c do
     * the filtering on behalf of older clients that can't parse it. */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

4318 4319
    libxl_bitmap_init(&nodemap);

J
Jim Fehlig 已提交
4320
    if (!(vm = libxlDomObjFromDomain(dom)))
4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341
        goto cleanup;

    if (virDomainGetNumaParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not running"));
        goto cleanup;
    }

    priv = vm->privateData;

    if ((*nparams) == 0) {
        *nparams = LIBXL_NUMA_NPARAM;
        ret = 0;
        goto cleanup;
    }

    for (i = 0; i < LIBXL_NUMA_NPARAM && i < *nparams; i++) {
        virMemoryParameterPtr param = &params[i];
4342
        int numnodes;
4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358 4359 4360

        switch (i) {
        case 0:
            /* NUMA mode */

            /* Xen implements something that is really close to numactl's
             * 'interleave' policy (see `man 8 numactl' for details). */
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_MODE,
                                        VIR_TYPED_PARAM_INT,
                                        VIR_DOMAIN_NUMATUNE_MEM_INTERLEAVE) < 0)
                goto cleanup;

            break;

        case 1:
            /* Node affinity */

            /* Let's allocate both libxl and libvirt bitmaps */
4361 4362 4363 4364
            numnodes = libxl_get_max_nodes(priv->ctx);
            if (numnodes <= 0)
                goto cleanup;

J
Ján Tomko 已提交
4365
            if (libxl_node_bitmap_alloc(priv->ctx, &nodemap, 0)) {
4366 4367 4368
                virReportOOMError();
                goto cleanup;
            }
J
Ján Tomko 已提交
4369 4370
            if (!(nodes = virBitmapNew(numnodes)))
                goto cleanup;
4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391

            rc = libxl_domain_get_nodeaffinity(priv->ctx,
                                               vm->def->id,
                                               &nodemap);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get numa affinity"));
                goto cleanup;
            }

            /* First, we convert libxl_bitmap into virBitmap. After that,
             * we format virBitmap as a string that can be returned. */
            virBitmapClearAll(nodes);
            libxl_for_each_set_bit(j, nodemap) {
                if (virBitmapSetBit(nodes, j)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Node %zu out of range"), j);
                    goto cleanup;
                }
            }

4392
            if (!(nodeset = virBitmapFormat(nodes)))
4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408
                goto cleanup;

            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_NODESET,
                                        VIR_TYPED_PARAM_STRING, nodeset) < 0)
                goto cleanup;

            nodeset = NULL;

            break;
        }
    }

    if (*nparams > LIBXL_NUMA_NPARAM)
        *nparams = LIBXL_NUMA_NPARAM;
    ret = 0;

4409
 cleanup:
4410 4411 4412 4413 4414 4415 4416 4417 4418
    VIR_FREE(nodeset);
    virBitmapFree(nodes);
    libxl_bitmap_dispose(&nodemap);
    if (vm)
        virObjectUnlock(vm);
    return ret;
}
#endif

J
Jim Fehlig 已提交
4419 4420 4421 4422 4423 4424
static int
libxlDomainIsActive(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

J
Jim Fehlig 已提交
4425
    if (!(obj = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
4426
        goto cleanup;
4427 4428 4429 4430

    if (virDomainIsActiveEnsureACL(dom->conn, obj->def) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
4431 4432
    ret = virDomainObjIsActive(obj);

4433
 cleanup:
J
Jim Fehlig 已提交
4434
    if (obj)
4435
        virObjectUnlock(obj);
J
Jim Fehlig 已提交
4436 4437 4438 4439 4440 4441 4442 4443 4444
    return ret;
}

static int
libxlDomainIsPersistent(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

J
Jim Fehlig 已提交
4445
    if (!(obj = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
4446
        goto cleanup;
4447 4448 4449 4450

    if (virDomainIsPersistentEnsureACL(dom->conn, obj->def) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
4451 4452
    ret = obj->persistent;

4453
 cleanup:
J
Jim Fehlig 已提交
4454
    if (obj)
4455
        virObjectUnlock(obj);
J
Jim Fehlig 已提交
4456 4457 4458
    return ret;
}

4459 4460 4461 4462 4463 4464
static int
libxlDomainIsUpdated(virDomainPtr dom)
{
    virDomainObjPtr vm;
    int ret = -1;

J
Jim Fehlig 已提交
4465
    if (!(vm = libxlDomObjFromDomain(dom)))
4466
        goto cleanup;
4467 4468 4469 4470

    if (virDomainIsUpdatedEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4471 4472
    ret = vm->updated;

4473
 cleanup:
4474
    if (vm)
4475
        virObjectUnlock(vm);
4476 4477 4478
    return ret;
}

4479
static int
4480 4481 4482
libxlConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID,
                                   virConnectDomainEventGenericCallback callback,
                                   void *opaque, virFreeCallback freecb)
4483 4484 4485 4486
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int ret;

4487 4488 4489
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

4490 4491 4492 4493
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID, callback, opaque,
                                      freecb, &ret) < 0)
4494
        ret = -1;
4495 4496 4497 4498 4499 4500

    return ret;
}


static int
4501
libxlConnectDomainEventDeregisterAny(virConnectPtr conn, int callbackID)
4502 4503 4504
{
    libxlDriverPrivatePtr driver = conn->privateData;

4505 4506 4507
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

4508 4509 4510 4511
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
                                        callbackID) < 0)
        return -1;
4512

4513
    return 0;
4514 4515
}

J
Jim Fehlig 已提交
4516

4517
static int
4518
libxlConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
4519 4520 4521 4522
{
    return 1;
}

4523
static int
4524 4525 4526
libxlConnectListAllDomains(virConnectPtr conn,
                           virDomainPtr **domains,
                           unsigned int flags)
4527 4528 4529 4530
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
4531
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
4532

4533 4534 4535
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

4536 4537
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
4538 4539 4540 4541

    return ret;
}

4542 4543 4544 4545 4546 4547 4548 4549 4550
/* Which features are supported by this driver? */
static int
libxlConnectSupportsFeature(virConnectPtr conn, int feature)
{
    if (virConnectSupportsFeatureEnsureACL(conn) < 0)
        return -1;

    switch (feature) {
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
J
Jim Fehlig 已提交
4551
    case VIR_DRV_FEATURE_MIGRATION_PARAMS:
4552 4553 4554 4555 4556
        return 1;
    default:
        return 0;
    }
}
4557

4558 4559 4560 4561 4562 4563 4564 4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582
static int
libxlNodeDeviceGetPCIInfo(virNodeDeviceDefPtr def,
                          unsigned *domain,
                          unsigned *bus,
                          unsigned *slot,
                          unsigned *function)
{
    virNodeDevCapsDefPtr cap;

    cap = def->caps;
    while (cap) {
        if (cap->type == VIR_NODE_DEV_CAP_PCI_DEV) {
            *domain   = cap->data.pci_dev.domain;
            *bus      = cap->data.pci_dev.bus;
            *slot     = cap->data.pci_dev.slot;
            *function = cap->data.pci_dev.function;
            break;
        }

        cap = cap->next;
    }

    if (!cap) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("device %s is not a PCI device"), def->name);
C
Chunyan Liu 已提交
4583
        return -1;
4584 4585
    }

C
Chunyan Liu 已提交
4586
    return 0;
4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634
}

static int
libxlNodeDeviceDetachFlags(virNodeDevicePtr dev,
                           const char *driverName,
                           unsigned int flags)
{
    virPCIDevicePtr pci = NULL;
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
    int ret = -1;
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
    libxlDriverPrivatePtr driver = dev->conn->privateData;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;

    virCheckFlags(0, -1);

    xml = virNodeDeviceGetXMLDesc(dev, 0);
    if (!xml)
        goto cleanup;

    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
    if (!def)
        goto cleanup;

    if (virNodeDeviceDetachFlagsEnsureACL(dev->conn, def) < 0)
        goto cleanup;

    if (libxlNodeDeviceGetPCIInfo(def, &domain, &bus, &slot, &function) < 0)
        goto cleanup;

    pci = virPCIDeviceNew(domain, bus, slot, function);
    if (!pci)
        goto cleanup;

    if (!driverName || STREQ(driverName, "xen")) {
        if (virPCIDeviceSetStubDriver(pci, "pciback") < 0)
            goto cleanup;
    } else {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported driver name '%s'"), driverName);
        goto cleanup;
    }

    if (virHostdevPCINodeDeviceDetach(hostdev_mgr, pci) < 0)
        goto cleanup;

    ret = 0;
4635
 cleanup:
4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677
    virPCIDeviceFree(pci);
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
libxlNodeDeviceDettach(virNodeDevicePtr dev)
{
    return libxlNodeDeviceDetachFlags(dev, NULL, 0);
}

static int
libxlNodeDeviceReAttach(virNodeDevicePtr dev)
{
    virPCIDevicePtr pci = NULL;
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
    int ret = -1;
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
    libxlDriverPrivatePtr driver = dev->conn->privateData;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;

    xml = virNodeDeviceGetXMLDesc(dev, 0);
    if (!xml)
        goto cleanup;

    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
    if (!def)
        goto cleanup;

    if (virNodeDeviceReAttachEnsureACL(dev->conn, def) < 0)
        goto cleanup;

    if (libxlNodeDeviceGetPCIInfo(def, &domain, &bus, &slot, &function) < 0)
        goto cleanup;

    pci = virPCIDeviceNew(domain, bus, slot, function);
    if (!pci)
        goto cleanup;

    if (virHostdevPCINodeDeviceReAttach(hostdev_mgr, pci) < 0)
C
Chunyan Liu 已提交
4678
        goto cleanup;
4679 4680

    ret = 0;
C
Chunyan Liu 已提交
4681

4682
 cleanup:
C
Chunyan Liu 已提交
4683
    virPCIDeviceFree(pci);
4684 4685 4686 4687 4688 4689 4690 4691
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
libxlNodeDeviceReset(virNodeDevicePtr dev)
{
C
Chunyan Liu 已提交
4692
    virPCIDevicePtr pci = NULL;
4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
    int ret = -1;
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
    libxlDriverPrivatePtr driver = dev->conn->privateData;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;

    xml = virNodeDeviceGetXMLDesc(dev, 0);
    if (!xml)
        goto cleanup;

    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
    if (!def)
        goto cleanup;

    if (virNodeDeviceResetEnsureACL(dev->conn, def) < 0)
        goto cleanup;

    if (libxlNodeDeviceGetPCIInfo(def, &domain, &bus, &slot, &function) < 0)
        goto cleanup;

    pci = virPCIDeviceNew(domain, bus, slot, function);
    if (!pci)
        goto cleanup;

    if (virHostdevPCINodeDeviceReset(hostdev_mgr, pci) < 0)
C
Chunyan Liu 已提交
4719
        goto cleanup;
4720 4721

    ret = 0;
C
Chunyan Liu 已提交
4722

4723
 cleanup:
C
Chunyan Liu 已提交
4724
    virPCIDeviceFree(pci);
4725 4726 4727 4728 4729
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

J
Jim Fehlig 已提交
4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740
static char *
libxlDomainMigrateBegin3Params(virDomainPtr domain,
                               virTypedParameterPtr params,
                               int nparams,
                               char **cookieout ATTRIBUTE_UNUSED,
                               int *cookieoutlen ATTRIBUTE_UNUSED,
                               unsigned int flags)
{
    const char *xmlin = NULL;
    virDomainObjPtr vm = NULL;

4741 4742 4743 4744 4745
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return NULL;
#endif

J
Jim Fehlig 已提交
4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 4763 4764 4765 4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789
    virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL);
    if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
        return NULL;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_XML,
                                &xmlin) < 0)
        return NULL;

    if (!(vm = libxlDomObjFromDomain(domain)))
        return NULL;

    if (virDomainMigrateBegin3ParamsEnsureACL(domain->conn, vm->def) < 0) {
        virObjectUnlock(vm);
        return NULL;
    }

    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        virObjectUnlock(vm);
        return NULL;
    }

    return libxlDomainMigrationBegin(domain->conn, vm, xmlin);
}

static int
libxlDomainMigratePrepare3Params(virConnectPtr dconn,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 const char *cookiein ATTRIBUTE_UNUSED,
                                 int cookieinlen ATTRIBUTE_UNUSED,
                                 char **cookieout ATTRIBUTE_UNUSED,
                                 int *cookieoutlen ATTRIBUTE_UNUSED,
                                 char **uri_out,
                                 unsigned int flags)
{
    libxlDriverPrivatePtr driver = dconn->privateData;
    virDomainDefPtr def = NULL;
    const char *dom_xml = NULL;
    const char *dname = NULL;
    const char *uri_in = NULL;

4790 4791 4792 4793 4794
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816
    virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
    if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
        goto error;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_XML,
                                &dom_xml) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_NAME,
                                &dname) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_URI,
                                &uri_in) < 0)

        goto error;

    if (!(def = libxlDomainMigrationPrepareDef(driver, dom_xml, dname)))
        goto error;

    if (virDomainMigratePrepare3ParamsEnsureACL(dconn, def) < 0)
        goto error;

4817
    if (libxlDomainMigrationPrepare(dconn, &def, uri_in, uri_out, flags) < 0)
J
Jim Fehlig 已提交
4818 4819 4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838 4839 4840 4841 4842 4843 4844
        goto error;

    return 0;

 error:
    virDomainDefFree(def);
    return -1;
}

static int
libxlDomainMigratePerform3Params(virDomainPtr dom,
                                 const char *dconnuri,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 const char *cookiein ATTRIBUTE_UNUSED,
                                 int cookieinlen ATTRIBUTE_UNUSED,
                                 char **cookieout ATTRIBUTE_UNUSED,
                                 int *cookieoutlen ATTRIBUTE_UNUSED,
                                 unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    const char *dom_xml = NULL;
    const char *dname = NULL;
    const char *uri = NULL;
    int ret = -1;

4845 4846 4847 4848 4849
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868 4869 4870 4871 4872
    virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
    if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
        goto cleanup;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_XML,
                                &dom_xml) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_NAME,
                                &dname) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_URI,
                                &uri) < 0)

        goto cleanup;

    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

    if (virDomainMigratePerform3ParamsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

    if (libxlDomainMigrationPerform(driver, vm, dom_xml, dconnuri,
4873
                                    uri, dname, flags) < 0)
J
Jim Fehlig 已提交
4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885 4886 4887 4888 4889 4890 4891 4892 4893 4894 4895 4896 4897
        goto cleanup;

    ret = 0;

 cleanup:
    if (vm)
        virObjectUnlock(vm);
    return ret;
}

static virDomainPtr
libxlDomainMigrateFinish3Params(virConnectPtr dconn,
                                virTypedParameterPtr params,
                                int nparams,
                                const char *cookiein ATTRIBUTE_UNUSED,
                                int cookieinlen ATTRIBUTE_UNUSED,
                                char **cookieout ATTRIBUTE_UNUSED,
                                int *cookieoutlen ATTRIBUTE_UNUSED,
                                unsigned int flags,
                                int cancelled)
{
    libxlDriverPrivatePtr driver = dconn->privateData;
    virDomainObjPtr vm = NULL;
    const char *dname = NULL;
4898
    virDomainPtr ret = NULL;
J
Jim Fehlig 已提交
4899

4900 4901 4902 4903 4904
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return NULL;
#endif

J
Jim Fehlig 已提交
4905 4906 4907 4908 4909 4910 4911 4912 4913 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925 4926 4927 4928
    virCheckFlags(LIBXL_MIGRATION_FLAGS, NULL);
    if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
        return NULL;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_NAME,
                                &dname) < 0)
        return NULL;

    if (!dname ||
        !(vm = virDomainObjListFindByName(driver->domains, dname))) {
        /* Migration obviously failed if the domain doesn't exist */
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Migration failed. No domain on destination host "
                         "with matching name '%s'"),
                       NULLSTR(dname));
        return NULL;
    }

    if (virDomainMigrateFinish3ParamsEnsureACL(dconn, vm->def) < 0) {
        virObjectUnlock(vm);
        return NULL;
    }

4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940 4941 4942
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) {
        virObjectUnlock(vm);
        return NULL;
    }

    ret = libxlDomainMigrationFinish(dconn, vm, flags, cancelled);

    if (!libxlDomainObjEndJob(driver, vm))
        vm = NULL;

    if (vm)
        virObjectUnlock(vm);

    return ret;
J
Jim Fehlig 已提交
4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956
}

static int
libxlDomainMigrateConfirm3Params(virDomainPtr domain,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 const char *cookiein ATTRIBUTE_UNUSED,
                                 int cookieinlen ATTRIBUTE_UNUSED,
                                 unsigned int flags,
                                 int cancelled)
{
    libxlDriverPrivatePtr driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;

4957 4958 4959 4960 4961
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976
    virCheckFlags(LIBXL_MIGRATION_FLAGS, -1);
    if (virTypedParamsValidate(params, nparams, LIBXL_MIGRATION_PARAMETERS) < 0)
        return -1;

    if (!(vm = libxlDomObjFromDomain(domain)))
        return -1;

    if (virDomainMigrateConfirm3ParamsEnsureACL(domain->conn, vm->def) < 0) {
        virObjectUnlock(vm);
        return -1;
    }

    return libxlDomainMigrationConfirm(driver, vm, flags, cancelled);
}

4977

4978
static virHypervisorDriver libxlHypervisorDriver = {
4979
    .name = LIBXL_DRIVER_NAME,
4980 4981 4982 4983
    .connectOpen = libxlConnectOpen, /* 0.9.0 */
    .connectClose = libxlConnectClose, /* 0.9.0 */
    .connectGetType = libxlConnectGetType, /* 0.9.0 */
    .connectGetVersion = libxlConnectGetVersion, /* 0.9.0 */
4984
    .connectGetHostname = libxlConnectGetHostname, /* 0.9.0 */
4985
    .connectGetSysinfo = libxlConnectGetSysinfo, /* 1.1.0 */
4986
    .connectGetMaxVcpus = libxlConnectGetMaxVcpus, /* 0.9.0 */
4987
    .nodeGetInfo = libxlNodeGetInfo, /* 0.9.0 */
4988 4989 4990 4991
    .connectGetCapabilities = libxlConnectGetCapabilities, /* 0.9.0 */
    .connectListDomains = libxlConnectListDomains, /* 0.9.0 */
    .connectNumOfDomains = libxlConnectNumOfDomains, /* 0.9.0 */
    .connectListAllDomains = libxlConnectListAllDomains, /* 0.9.13 */
4992 4993 4994 4995 4996 4997 4998
    .domainCreateXML = libxlDomainCreateXML, /* 0.9.0 */
    .domainLookupByID = libxlDomainLookupByID, /* 0.9.0 */
    .domainLookupByUUID = libxlDomainLookupByUUID, /* 0.9.0 */
    .domainLookupByName = libxlDomainLookupByName, /* 0.9.0 */
    .domainSuspend = libxlDomainSuspend, /* 0.9.0 */
    .domainResume = libxlDomainResume, /* 0.9.0 */
    .domainShutdown = libxlDomainShutdown, /* 0.9.0 */
4999
    .domainShutdownFlags = libxlDomainShutdownFlags, /* 0.9.10 */
5000 5001
    .domainReboot = libxlDomainReboot, /* 0.9.0 */
    .domainDestroy = libxlDomainDestroy, /* 0.9.0 */
5002
    .domainDestroyFlags = libxlDomainDestroyFlags, /* 0.9.4 */
5003 5004
    .domainGetOSType = libxlDomainGetOSType, /* 0.9.0 */
    .domainGetMaxMemory = libxlDomainGetMaxMemory, /* 0.9.0 */
5005
    .domainSetMaxMemory = libxlDomainSetMaxMemory, /* 0.9.2 */
5006 5007 5008 5009
    .domainSetMemory = libxlDomainSetMemory, /* 0.9.0 */
    .domainSetMemoryFlags = libxlDomainSetMemoryFlags, /* 0.9.0 */
    .domainGetInfo = libxlDomainGetInfo, /* 0.9.0 */
    .domainGetState = libxlDomainGetState, /* 0.9.2 */
5010
    .domainSave = libxlDomainSave, /* 0.9.2 */
5011
    .domainSaveFlags = libxlDomainSaveFlags, /* 0.9.4 */
5012
    .domainRestore = libxlDomainRestore, /* 0.9.2 */
5013
    .domainRestoreFlags = libxlDomainRestoreFlags, /* 0.9.4 */
5014
    .domainCoreDump = libxlDomainCoreDump, /* 0.9.2 */
5015 5016 5017 5018
    .domainSetVcpus = libxlDomainSetVcpus, /* 0.9.0 */
    .domainSetVcpusFlags = libxlDomainSetVcpusFlags, /* 0.9.0 */
    .domainGetVcpusFlags = libxlDomainGetVcpusFlags, /* 0.9.0 */
    .domainPinVcpu = libxlDomainPinVcpu, /* 0.9.0 */
5019
    .domainPinVcpuFlags = libxlDomainPinVcpuFlags, /* 1.2.1 */
5020
    .domainGetVcpus = libxlDomainGetVcpus, /* 0.9.0 */
5021
    .domainGetVcpuPinInfo = libxlDomainGetVcpuPinInfo, /* 1.2.1 */
5022
    .domainGetXMLDesc = libxlDomainGetXMLDesc, /* 0.9.0 */
5023 5024 5025 5026
    .connectDomainXMLFromNative = libxlConnectDomainXMLFromNative, /* 0.9.0 */
    .connectDomainXMLToNative = libxlConnectDomainXMLToNative, /* 0.9.0 */
    .connectListDefinedDomains = libxlConnectListDefinedDomains, /* 0.9.0 */
    .connectNumOfDefinedDomains = libxlConnectNumOfDefinedDomains, /* 0.9.0 */
5027 5028 5029
    .domainCreate = libxlDomainCreate, /* 0.9.0 */
    .domainCreateWithFlags = libxlDomainCreateWithFlags, /* 0.9.0 */
    .domainDefineXML = libxlDomainDefineXML, /* 0.9.0 */
5030
    .domainDefineXMLFlags = libxlDomainDefineXMLFlags, /* 1.2.12 */
5031
    .domainUndefine = libxlDomainUndefine, /* 0.9.0 */
5032
    .domainUndefineFlags = libxlDomainUndefineFlags, /* 0.9.4 */
5033 5034 5035 5036 5037
    .domainAttachDevice = libxlDomainAttachDevice, /* 0.9.2 */
    .domainAttachDeviceFlags = libxlDomainAttachDeviceFlags, /* 0.9.2 */
    .domainDetachDevice = libxlDomainDetachDevice,    /* 0.9.2 */
    .domainDetachDeviceFlags = libxlDomainDetachDeviceFlags, /* 0.9.2 */
    .domainUpdateDeviceFlags = libxlDomainUpdateDeviceFlags, /* 0.9.2 */
5038 5039 5040 5041
    .domainGetAutostart = libxlDomainGetAutostart, /* 0.9.0 */
    .domainSetAutostart = libxlDomainSetAutostart, /* 0.9.0 */
    .domainGetSchedulerType = libxlDomainGetSchedulerType, /* 0.9.0 */
    .domainGetSchedulerParameters = libxlDomainGetSchedulerParameters, /* 0.9.0 */
5042
    .domainGetSchedulerParametersFlags = libxlDomainGetSchedulerParametersFlags, /* 0.9.2 */
5043
    .domainSetSchedulerParameters = libxlDomainSetSchedulerParameters, /* 0.9.0 */
5044
    .domainSetSchedulerParametersFlags = libxlDomainSetSchedulerParametersFlags, /* 0.9.2 */
5045 5046 5047
#ifdef LIBXL_HAVE_DOMAIN_NODEAFFINITY
    .domainGetNumaParameters = libxlDomainGetNumaParameters, /* 1.1.1 */
#endif
5048
    .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
5049
    .nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
5050 5051
    .connectDomainEventRegister = libxlConnectDomainEventRegister, /* 0.9.0 */
    .connectDomainEventDeregister = libxlConnectDomainEventDeregister, /* 0.9.0 */
5052 5053 5054
    .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */
    .domainHasManagedSaveImage = libxlDomainHasManagedSaveImage, /* 0.9.2 */
    .domainManagedSaveRemove = libxlDomainManagedSaveRemove, /* 0.9.2 */
B
Bamvor Jian Zhang 已提交
5055
    .domainOpenConsole = libxlDomainOpenConsole, /* 1.1.2 */
5056 5057 5058
    .domainIsActive = libxlDomainIsActive, /* 0.9.0 */
    .domainIsPersistent = libxlDomainIsPersistent, /* 0.9.0 */
    .domainIsUpdated = libxlDomainIsUpdated, /* 0.9.0 */
5059 5060 5061
    .connectDomainEventRegisterAny = libxlConnectDomainEventRegisterAny, /* 0.9.0 */
    .connectDomainEventDeregisterAny = libxlConnectDomainEventDeregisterAny, /* 0.9.0 */
    .connectIsAlive = libxlConnectIsAlive, /* 0.9.8 */
5062
    .connectSupportsFeature = libxlConnectSupportsFeature, /* 1.1.1 */
5063 5064 5065 5066
    .nodeDeviceDettach = libxlNodeDeviceDettach, /* 1.2.3 */
    .nodeDeviceDetachFlags = libxlNodeDeviceDetachFlags, /* 1.2.3 */
    .nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.2.3 */
    .nodeDeviceReset = libxlNodeDeviceReset, /* 1.2.3 */
5067 5068 5069 5070 5071
    .domainMigrateBegin3Params = libxlDomainMigrateBegin3Params, /* 1.2.6 */
    .domainMigratePrepare3Params = libxlDomainMigratePrepare3Params, /* 1.2.6 */
    .domainMigratePerform3Params = libxlDomainMigratePerform3Params, /* 1.2.6 */
    .domainMigrateFinish3Params = libxlDomainMigrateFinish3Params, /* 1.2.6 */
    .domainMigrateConfirm3Params = libxlDomainMigrateConfirm3Params, /* 1.2.6 */
J
Jim Fehlig 已提交
5072 5073
};

5074 5075 5076 5077
static virConnectDriver libxlConnectDriver = {
    .hypervisorDriver = &libxlHypervisorDriver,
};

J
Jim Fehlig 已提交
5078 5079
static virStateDriver libxlStateDriver = {
    .name = "LIBXL",
5080
    .stateInitialize = libxlStateInitialize,
5081
    .stateAutoStart = libxlStateAutoStart,
5082 5083
    .stateCleanup = libxlStateCleanup,
    .stateReload = libxlStateReload,
J
Jim Fehlig 已提交
5084 5085 5086 5087 5088 5089
};


int
libxlRegister(void)
{
5090 5091
    if (virRegisterConnectDriver(&libxlConnectDriver,
                                 true) < 0)
J
Jim Fehlig 已提交
5092 5093 5094 5095 5096 5097
        return -1;
    if (virRegisterStateDriver(&libxlStateDriver) < 0)
        return -1;

    return 0;
}