libxl_driver.c 194.3 KB
Newer Older
1 2 3
/*
 * libxl_driver.c: core driver methods for managing libxenlight domains
 *
4
 * Copyright (C) 2006-2015 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 <xenstore.h>
34
#include <fcntl.h>
35
#include <regex.h>
J
Jim Fehlig 已提交
36 37

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

#define VIR_FROM_THIS VIR_FROM_LIBXL

69 70
VIR_LOG_INIT("libxl.libxl_driver");

J
Jim Fehlig 已提交
71 72 73 74 75 76
#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

77
#define LIBXL_NB_TOTAL_CPU_STAT_PARAM 1
78
#define LIBXL_NB_TOTAL_BLK_STAT_PARAM 6
79

80
#define HYPERVISOR_CAPABILITIES "/proc/xen/capabilities"
R
Roman Bogorodskiy 已提交
81
#define HYPERVISOR_XENSTORED "/dev/xen/xenstored"
82

83 84 85
/* Number of Xen scheduler parameters */
#define XEN_SCHED_CREDIT_NPARAM   2

J
Jim Fehlig 已提交
86 87 88 89 90 91 92 93 94
#define LIBXL_CHECK_DOM0_GOTO(name, label)                               \
    do {                                                                  \
        if (STREQ_NULLABLE(name, "Domain-0")) {                           \
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",               \
                           _("Domain-0 does not support requested operation")); \
            goto label;                                                   \
        }                                                                 \
    } while (0)

95

96
static libxlDriverPrivatePtr libxl_driver;
J
Jim Fehlig 已提交
97

98 99 100 101 102 103 104 105 106
/* 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;
};

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
/* Object used to store disk statistics across multiple xen backends */
typedef struct _libxlBlockStats libxlBlockStats;
typedef libxlBlockStats *libxlBlockStatsPtr;
struct _libxlBlockStats {
    long long rd_req;
    long long rd_bytes;
    long long wr_req;
    long long wr_bytes;
    long long f_req;

    char *backend;
    union {
        struct {
            long long ds_req;
            long long oo_req;
        } vbd;
    } u;
};

J
Jim Fehlig 已提交
126
/* Function declarations */
127 128
static int
libxlDomainManagedSaveLoad(virDomainObjPtr vm,
129 130
                           void *opaque);

J
Jim Fehlig 已提交
131 132

/* Function definitions */
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 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
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 已提交
310 311 312 313 314 315 316
static virDomainObjPtr
libxlDomObjFromDomain(virDomainPtr dom)
{
    virDomainObjPtr vm;
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

W
Wang Yufei 已提交
317
    vm = virDomainObjListFindByUUIDRef(driver->domains, dom->uuid);
J
Jim Fehlig 已提交
318 319 320 321 322 323 324 325 326 327 328
    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;
}

329 330
static int
libxlAutostartDomain(virDomainObjPtr vm,
331 332 333
                     void *opaque)
{
    libxlDriverPrivatePtr driver = opaque;
334
    int ret = -1;
335

W
Wang Yufei 已提交
336
    virObjectRef(vm);
337
    virObjectLock(vm);
338 339
    virResetLastError();

W
Wang Yufei 已提交
340 341
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;
342

343
    if (vm->autostart && !virDomainObjIsActive(vm) &&
344
        libxlDomainStartNew(driver, vm, false) < 0) {
345 346 347
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to autostart VM '%s': %s"),
                       vm->def->name, virGetLastErrorMessage());
348
        goto endjob;
349 350
    }

351
    ret = 0;
352 353

 endjob:
W
Wang Yufei 已提交
354 355 356
    libxlDomainObjEndJob(driver, vm);
 cleanup:
    virDomainObjEndAPI(&vm);
357

358
    return ret;
359 360
}

J
Jim Fehlig 已提交
361 362 363 364
/*
 * Reconnect to running domains that were previously started/created
 * with libxenlight driver.
 */
365 366
static int
libxlReconnectDomain(virDomainObjPtr vm,
J
Jim Fehlig 已提交
367 368 369
                     void *opaque)
{
    libxlDriverPrivatePtr driver = opaque;
370
    libxlDomainObjPrivatePtr priv = vm->privateData;
J
Jim Fehlig 已提交
371
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
372 373 374 375
    int rc;
    libxl_dominfo d_info;
    int len;
    uint8_t *data = NULL;
376
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
377
    unsigned int hostdev_flags = VIR_HOSTDEV_SP_PCI;
378
    int ret = -1;
379 380 381 382

#ifdef LIBXL_HAVE_PVUSB
    hostdev_flags |= VIR_HOSTDEV_SP_USB;
#endif
J
Jim Fehlig 已提交
383

384
    virObjectRef(vm);
385
    virObjectLock(vm);
J
Jim Fehlig 已提交
386

387 388
    libxl_dominfo_init(&d_info);

J
Jim Fehlig 已提交
389
    /* Does domain still exist? */
J
Jim Fehlig 已提交
390
    rc = libxl_domain_info(cfg->ctx, &d_info, vm->def->id);
J
Jim Fehlig 已提交
391
    if (rc == ERROR_INVAL) {
392
        goto error;
J
Jim Fehlig 已提交
393 394 395
    } else if (rc != 0) {
        VIR_DEBUG("libxl_domain_info failed (code %d), ignoring domain %d",
                  rc, vm->def->id);
396
        goto error;
J
Jim Fehlig 已提交
397 398 399
    }

    /* Is this a domain that was under libvirt control? */
J
Jim Fehlig 已提交
400
    if (libxl_userdata_retrieve(cfg->ctx, vm->def->id,
J
Jim Fehlig 已提交
401 402
                                "libvirt-xml", &data, &len)) {
        VIR_DEBUG("libxl_userdata_retrieve failed, ignoring domain %d", vm->def->id);
403
        goto error;
J
Jim Fehlig 已提交
404 405 406 407
    }

    /* Update domid in case it changed (e.g. reboot) while we were gone? */
    vm->def->id = d_info.domid;
408

409 410
    libxlLoggerOpenFile(cfg->logger, vm->def->id, vm->def->name, NULL);

411
    /* Update hostdev state */
412
    if (virHostdevUpdateActiveDomainDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
413
                                            vm->def, hostdev_flags) < 0)
414
        goto error;
415

416
    if (virAtomicIntInc(&driver->nactive) == 1 && driver->inhibitCallback)
417 418
        driver->inhibitCallback(true, driver->inhibitOpaque);

419
    /* Enable domain death events */
J
Jim Fehlig 已提交
420
    libxl_evenable_domain_death(cfg->ctx, vm->def->id, 0, &priv->deathW);
421

C
Cédric Bosdonnat 已提交
422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
    /* now that we know it's reconnected call the hook if present */
    if (virHookPresent(VIR_HOOK_DRIVER_LIBXL) &&
        STRNEQ("Domain-0", vm->def->name)) {
        char *xml = virDomainDefFormat(vm->def, cfg->caps, 0);
        int hookret;

        /* we can't stop the operation even if the script raised an error */
        hookret = virHookCall(VIR_HOOK_DRIVER_LIBXL, vm->def->name,
                              VIR_HOOK_LIBXL_OP_RECONNECT, VIR_HOOK_SUBOP_BEGIN,
                              NULL, xml, NULL);
        VIR_FREE(xml);
        if (hookret < 0) {
            /* Stop the domain if the hook failed */
            if (virDomainObjIsActive(vm)) {
                libxlDomainDestroyInternal(driver, vm);
                virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF, VIR_DOMAIN_SHUTOFF_FAILED);
            }
            goto error;
        }
    }

443 444 445
    ret = 0;

 cleanup:
446
    libxl_dominfo_dispose(&d_info);
447
    virObjectUnlock(vm);
448
    virObjectUnref(vm);
J
Jim Fehlig 已提交
449
    virObjectUnref(cfg);
450
    return ret;
J
Jim Fehlig 已提交
451

452
 error:
453
    libxlDomainCleanup(driver, vm);
454
    if (!vm->persistent) {
455
        virDomainObjListRemoveLocked(driver->domains, vm);
456

457 458 459 460 461
        /* virDomainObjListRemoveLocked leaves the object unlocked,
         * lock it again to factorize more code. */
        virObjectLock(vm);
    }
    goto cleanup;
J
Jim Fehlig 已提交
462 463 464 465 466
}

static void
libxlReconnectDomains(libxlDriverPrivatePtr driver)
{
467
    virDomainObjListForEach(driver->domains, libxlReconnectDomain, driver);
J
Jim Fehlig 已提交
468 469 470
}

static int
471
libxlStateCleanup(void)
J
Jim Fehlig 已提交
472 473 474 475
{
    if (!libxl_driver)
        return -1;

476
    virObjectUnref(libxl_driver->hostdevMgr);
477
    virObjectUnref(libxl_driver->config);
478
    virObjectUnref(libxl_driver->xmlopt);
479
    virObjectUnref(libxl_driver->domains);
480
    virObjectUnref(libxl_driver->reservedGraphicsPorts);
J
Jim Fehlig 已提交
481
    virObjectUnref(libxl_driver->migrationPorts);
482
    virLockManagerPluginUnref(libxl_driver->lockManager);
J
Jim Fehlig 已提交
483

484
    virObjectUnref(libxl_driver->domainEventState);
485
    virSysinfoDefFree(libxl_driver->hostsysinfo);
486

J
Jim Fehlig 已提交
487 488 489 490 491 492
    virMutexDestroy(&libxl_driver->lock);
    VIR_FREE(libxl_driver);

    return 0;
}

493 494
static bool
libxlDriverShouldLoad(bool privileged)
495
{
496
    bool ret = false;
J
Jim Fehlig 已提交
497

498
    /* Don't load if non-root */
J
Jim Fehlig 已提交
499
    if (!privileged) {
500
        VIR_INFO("Not running privileged, disabling libxenlight driver");
501
        return ret;
J
Jim Fehlig 已提交
502 503
    }

R
Roman Bogorodskiy 已提交
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
    if (virFileExists(HYPERVISOR_CAPABILITIES)) {
        int status;
        char *output = NULL;
        /*
         * 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.
         */
        status = virFileReadAll(HYPERVISOR_CAPABILITIES, 10, &output);
        if (status >= 0)
            status = strncmp(output, "control_d", 9);
        VIR_FREE(output);
        if (status) {
            VIR_INFO("No Xen capabilities detected, probably not running "
                     "in a Xen Dom0.  Disabling libxenlight driver");

            return ret;
        }
    } else if (!virFileExists(HYPERVISOR_XENSTORED)) {
        VIR_INFO("Disabling driver as neither " HYPERVISOR_CAPABILITIES
                 " nor " HYPERVISOR_XENSTORED " exist");
525 526 527 528
        return ret;
    }

    /* Don't load if legacy xen toolstack (xend) is in use */
529 530 531 532 533 534 535 536 537 538 539
    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);
540 541
    } else {
        ret = true;
J
Jim Fehlig 已提交
542 543
    }

544 545 546
    return ret;
}

547 548 549 550 551 552 553 554 555 556
/* 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,
};

557 558 559 560 561 562 563 564
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
};

565 566 567 568 569 570
const struct libxl_event_hooks ev_hooks = {
    .event_occurs_mask = LIBXL_EVENTMASK_ALL,
    .event_occurs = libxlDomainEventHandler,
    .disaster = NULL,
};

J
Jim Fehlig 已提交
571 572 573 574 575 576 577 578
static int
libxlAddDom0(libxlDriverPrivatePtr driver)
{
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr oldDef = NULL;
    libxl_dominfo d_info;
579
    unsigned long long maxmem;
J
Jim Fehlig 已提交
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
    int ret = -1;

    libxl_dominfo_init(&d_info);

    /* Ensure we have a dom0 */
    if (libxl_domain_info(cfg->ctx, &d_info, 0) != 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("unable to get Domain-0 information from libxenlight"));
        goto cleanup;
    }

    if (!(def = virDomainDefNew()))
        goto cleanup;

    def->id = 0;
    def->virtType = VIR_DOMAIN_VIRT_XEN;
    if (VIR_STRDUP(def->name, "Domain-0") < 0)
        goto cleanup;

    def->os.type = VIR_DOMAIN_OSTYPE_XEN;

    if (virUUIDParse("00000000-0000-0000-0000-000000000000", def->uuid) < 0)
        goto cleanup;

    if (!(vm = virDomainObjListAdd(driver->domains, def,
                                   driver->xmlopt,
                                   0,
                                   &oldDef)))
        goto cleanup;

    def = NULL;

J
Jim Fehlig 已提交
612
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
613
    if (virDomainDefSetVcpusMax(vm->def, d_info.vcpu_max_id + 1, driver->xmlopt))
614 615
        goto cleanup;

616 617
    if (virDomainDefSetVcpus(vm->def, d_info.vcpu_online) < 0)
        goto cleanup;
J
Jim Fehlig 已提交
618
    vm->def->mem.cur_balloon = d_info.current_memkb;
619 620 621
    if (libxlDriverGetDom0MaxmemConf(cfg, &maxmem) < 0)
        maxmem = d_info.current_memkb;
    virDomainDefSetMemoryTotal(vm->def, maxmem);
J
Jim Fehlig 已提交
622 623 624 625 626 627 628 629 630 631 632 633 634

    ret = 0;

 cleanup:
    libxl_dominfo_dispose(&d_info);
    virDomainDefFree(def);
    virDomainDefFree(oldDef);
    if (vm)
        virObjectUnlock(vm);
    virObjectUnref(cfg);
    return ret;
}

635 636 637 638 639
static int
libxlStateInitialize(bool privileged,
                     virStateInhibitCallback callback ATTRIBUTE_UNUSED,
                     void *opaque ATTRIBUTE_UNUSED)
{
640
    libxlDriverConfigPtr cfg;
641
    char *driverConf = NULL;
642 643 644 645 646
    char ebuf[1024];

    if (!libxlDriverShouldLoad(privileged))
        return 0;

J
Jim Fehlig 已提交
647 648 649 650
    if (VIR_ALLOC(libxl_driver) < 0)
        return -1;

    if (virMutexInit(&libxl_driver->lock) < 0) {
651 652
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot initialize mutex"));
J
Jim Fehlig 已提交
653 654 655 656 657
        VIR_FREE(libxl_driver);
        return -1;
    }

    /* Allocate bitmap for vnc port reservation */
658
    if (!(libxl_driver->reservedGraphicsPorts =
J
Ján Tomko 已提交
659 660
          virPortAllocatorNew(_("VNC"),
                              LIBXL_VNC_PORT_MIN,
661 662
                              LIBXL_VNC_PORT_MAX,
                              0)))
663
        goto error;
J
Jim Fehlig 已提交
664

J
Jim Fehlig 已提交
665 666 667 668
    /* Allocate bitmap for migration port reservation */
    if (!(libxl_driver->migrationPorts =
          virPortAllocatorNew(_("migration"),
                              LIBXL_MIGRATION_PORT_MIN,
669
                              LIBXL_MIGRATION_PORT_MAX, 0)))
J
Jim Fehlig 已提交
670 671
        goto error;

672 673
    if (!(libxl_driver->domains = virDomainObjListNew()))
        goto error;
J
Jim Fehlig 已提交
674

675 676 677
    if (!(libxl_driver->hostdevMgr = virHostdevManagerGetDefault()))
        goto error;

678
    if (!(cfg = libxlDriverConfigNew()))
679
        goto error;
J
Jim Fehlig 已提交
680

681 682 683 684 685 686 687
    if (virAsprintf(&driverConf, "%s/libxl.conf", cfg->configBaseDir) < 0)
        goto error;

    if (libxlDriverConfigLoadFile(cfg, driverConf) < 0)
        goto error;
    VIR_FREE(driverConf);

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

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

694 695 696
    /* Register callback to handle domain events */
    libxl_event_register_callbacks(cfg->ctx, &ev_hooks, libxl_driver);

697 698
    libxl_driver->config = cfg;
    if (virFileMakePath(cfg->stateDir) < 0) {
699 700
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create state dir '%s': %s"),
701
                       cfg->stateDir,
702
                       virStrerror(errno, ebuf, sizeof(ebuf)));
J
Jim Fehlig 已提交
703 704
        goto error;
    }
705
    if (virFileMakePath(cfg->libDir) < 0) {
706 707
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create lib dir '%s': %s"),
708
                       cfg->libDir,
709
                       virStrerror(errno, ebuf, sizeof(ebuf)));
J
Jim Fehlig 已提交
710 711
        goto error;
    }
712
    if (virFileMakePath(cfg->saveDir) < 0) {
713 714
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create save dir '%s': %s"),
715
                       cfg->saveDir,
716
                       virStrerror(errno, ebuf, sizeof(ebuf)));
J
Jim Fehlig 已提交
717 718
        goto error;
    }
719 720 721 722 723 724 725
    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
Joao Martins 已提交
726 727 728 729 730 731 732
    if (virFileMakePath(cfg->channelDir) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("failed to create channel dir '%s': %s"),
                       cfg->channelDir,
                       virStrerror(errno, ebuf, sizeof(ebuf)));
        goto error;
    }
J
Jim Fehlig 已提交
733

734 735 736 737 738 739 740 741
    if (!(libxl_driver->lockManager =
          virLockManagerPluginNew(cfg->lockManagerName ?
                                  cfg->lockManagerName : "nop",
                                  "libxl",
                                  cfg->configBaseDir,
                                  0)))
        goto error;

742
    /* read the host sysinfo */
743
    libxl_driver->hostsysinfo = virSysinfoRead();
744

745
    libxl_driver->domainEventState = virObjectEventStateNew();
E
Eric Blake 已提交
746
    if (!libxl_driver->domainEventState)
747 748
        goto error;

749
    if ((cfg->caps = libxlMakeCapabilities(cfg->ctx)) == NULL) {
750 751
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot create capabilities for libxenlight"));
J
Jim Fehlig 已提交
752 753 754
        goto error;
    }

755
    if (!(libxl_driver->xmlopt = libxlCreateXMLConf()))
756
        goto error;
J
Jim Fehlig 已提交
757

J
Jim Fehlig 已提交
758 759 760 761
    /* Add Domain-0 */
    if (libxlAddDom0(libxl_driver) < 0)
        goto error;

J
Jim Fehlig 已提交
762
    /* Load running domains first. */
763
    if (virDomainObjListLoadAllConfigs(libxl_driver->domains,
764 765
                                       cfg->stateDir,
                                       cfg->autostartDir,
766
                                       1,
767
                                       cfg->caps,
768
                                       libxl_driver->xmlopt,
769
                                       NULL, NULL) < 0)
J
Jim Fehlig 已提交
770 771 772 773 774
        goto error;

    libxlReconnectDomains(libxl_driver);

    /* Then inactive persistent configs */
775
    if (virDomainObjListLoadAllConfigs(libxl_driver->domains,
776 777
                                       cfg->configDir,
                                       cfg->autostartDir,
778
                                       0,
779
                                       cfg->caps,
780
                                       libxl_driver->xmlopt,
781
                                       NULL, NULL) < 0)
J
Jim Fehlig 已提交
782 783
        goto error;

784 785
    virDomainObjListForEach(libxl_driver->domains, libxlDomainManagedSaveLoad,
                            libxl_driver);
786

J
Jim Fehlig 已提交
787 788
    return 0;

789
 error:
790
    VIR_FREE(driverConf);
791
    libxlStateCleanup();
792
    return -1;
J
Jim Fehlig 已提交
793 794
}

795 796 797 798 799 800 801 802 803 804
static void
libxlStateAutoStart(void)
{
    if (!libxl_driver)
        return;

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

J
Jim Fehlig 已提交
805
static int
806
libxlStateReload(void)
J
Jim Fehlig 已提交
807
{
808 809
    libxlDriverConfigPtr cfg;

J
Jim Fehlig 已提交
810 811 812
    if (!libxl_driver)
        return 0;

813 814
    cfg = libxlDriverConfigGet(libxl_driver);

815
    virDomainObjListLoadAllConfigs(libxl_driver->domains,
816 817
                                   cfg->configDir,
                                   cfg->autostartDir,
818
                                   1,
819
                                   cfg->caps,
820
                                   libxl_driver->xmlopt,
821 822
                                   NULL, libxl_driver);

823 824
    virDomainObjListForEach(libxl_driver->domains, libxlAutostartDomain,
                            libxl_driver);
825

826
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
827 828 829 830 831
    return 0;
}


static virDrvOpenStatus
832 833
libxlConnectOpen(virConnectPtr conn,
                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
834
                 virConfPtr conf ATTRIBUTE_UNUSED,
835
                 unsigned int flags)
J
Jim Fehlig 已提交
836
{
E
Eric Blake 已提交
837 838
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

J
Jim Fehlig 已提交
839 840 841 842
    if (conn->uri == NULL) {
        if (libxl_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;

843
        if (!(conn->uri = virURIParse("xen:///")))
J
Jim Fehlig 已提交
844 845 846 847 848 849 850 851 852 853 854 855
            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) {
856 857
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("libxenlight state driver is not active"));
J
Jim Fehlig 已提交
858 859 860 861 862 863 864 865
            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")) {
866 867 868
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected Xen URI path '%s', try xen:///"),
                           NULLSTR(conn->uri->path));
J
Jim Fehlig 已提交
869 870 871 872
            return VIR_DRV_OPEN_ERROR;
        }
    }

873 874 875
    if (virConnectOpenEnsureACL(conn) < 0)
        return VIR_DRV_OPEN_ERROR;

J
Jim Fehlig 已提交
876 877 878 879 880 881
    conn->privateData = libxl_driver;

    return VIR_DRV_OPEN_SUCCESS;
};

static int
882
libxlConnectClose(virConnectPtr conn ATTRIBUTE_UNUSED)
J
Jim Fehlig 已提交
883 884 885 886 887 888
{
    conn->privateData = NULL;
    return 0;
}

static const char *
889
libxlConnectGetType(virConnectPtr conn)
J
Jim Fehlig 已提交
890
{
891 892 893
    if (virConnectGetTypeEnsureACL(conn) < 0)
        return NULL;

J
Jim Fehlig 已提交
894
    return "Xen";
J
Jim Fehlig 已提交
895 896 897
}

static int
898
libxlConnectGetVersion(virConnectPtr conn, unsigned long *version)
J
Jim Fehlig 已提交
899 900
{
    libxlDriverPrivatePtr driver = conn->privateData;
901
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
902

903 904 905
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return 0;

906 907 908
    cfg = libxlDriverConfigGet(driver);
    *version = cfg->version;
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
909 910 911
    return 0;
}

912

913
static char *libxlConnectGetHostname(virConnectPtr conn)
914
{
915 916 917
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

918 919 920
    return virGetHostname();
}

921 922 923 924 925 926 927 928
static char *
libxlConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    virBuffer buf = VIR_BUFFER_INITIALIZER;

    virCheckFlags(0, NULL);

929 930 931
    if (virConnectGetSysinfoEnsureACL(conn) < 0)
        return NULL;

932 933 934 935 936 937 938 939
    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;
940
    if (virBufferCheckError(&buf) < 0)
941 942 943
        return NULL;
    return virBufferContentAndReset(&buf);
}
944

J
Jim Fehlig 已提交
945
static int
946
libxlConnectGetMaxVcpus(virConnectPtr conn, const char *type ATTRIBUTE_UNUSED)
J
Jim Fehlig 已提交
947 948 949
{
    int ret;
    libxlDriverPrivatePtr driver = conn->privateData;
950
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
951

952 953 954
    if (virConnectGetMaxVcpusEnsureACL(conn) < 0)
        return -1;

955 956
    cfg = libxlDriverConfigGet(driver);
    ret = libxl_get_max_cpus(cfg->ctx);
957 958 959 960 961
    /* 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)
962
        ret = -1;
J
Jim Fehlig 已提交
963

964
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
965 966 967 968 969 970
    return ret;
}

static int
libxlNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
{
971 972 973
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

974
    return libxlDriverNodeGetInfo(conn->privateData, info);
J
Jim Fehlig 已提交
975 976 977
}

static char *
978
libxlConnectGetCapabilities(virConnectPtr conn)
J
Jim Fehlig 已提交
979 980 981
{
    libxlDriverPrivatePtr driver = conn->privateData;
    char *xml;
982
    libxlDriverConfigPtr cfg;
J
Jim Fehlig 已提交
983

984 985 986
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

987
    cfg = libxlDriverConfigGet(driver);
988
    xml = virCapabilitiesFormatXML(cfg->caps);
J
Jim Fehlig 已提交
989

990
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
991 992 993 994
    return xml;
}

static int
995
libxlConnectListDomains(virConnectPtr conn, int *ids, int nids)
J
Jim Fehlig 已提交
996 997 998 999
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

1000 1001 1002
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

1003 1004
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                     virConnectListDomainsCheckACL, conn);
J
Jim Fehlig 已提交
1005 1006 1007 1008 1009

    return n;
}

static int
1010
libxlConnectNumOfDomains(virConnectPtr conn)
J
Jim Fehlig 已提交
1011 1012 1013 1014
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

1015 1016 1017
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

1018 1019
    n = virDomainObjListNumOfDomains(driver->domains, true,
                                     virConnectNumOfDomainsCheckACL, conn);
J
Jim Fehlig 已提交
1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031

    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;
1032
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1033
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
J
Jim Fehlig 已提交
1034

1035 1036 1037 1038
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
                  VIR_DOMAIN_START_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_START_VALIDATE)
1039
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
J
Jim Fehlig 已提交
1040

1041
    if (!(def = virDomainDefParseString(xml, cfg->caps, driver->xmlopt,
1042
                                        NULL, parse_flags)))
J
Jim Fehlig 已提交
1043 1044
        goto cleanup;

1045 1046 1047
    if (virDomainCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

1048
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1049
                                   driver->xmlopt,
1050
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
1051 1052
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
J
Jim Fehlig 已提交
1053
        goto cleanup;
W
Wang Yufei 已提交
1054
    virObjectRef(vm);
J
Jim Fehlig 已提交
1055 1056
    def = NULL;

1057 1058 1059 1060 1061 1062 1063 1064
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) {
        if (!vm->persistent) {
            virDomainObjListRemove(driver->domains, vm);
            vm = NULL;
        }
        goto cleanup;
    }

1065 1066
    if (libxlDomainStartNew(driver, vm,
                         (flags & VIR_DOMAIN_START_PAUSED) != 0) < 0) {
1067 1068 1069
        if (!vm->persistent) {
            virDomainObjListRemove(driver->domains, vm);
            vm = NULL;
1070
            goto cleanup;
1071
        }
1072
        goto endjob;
J
Jim Fehlig 已提交
1073 1074
    }

1075
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
J
Jim Fehlig 已提交
1076

1077
 endjob:
W
Wang Yufei 已提交
1078
    libxlDomainObjEndJob(driver, vm);
1079

1080
 cleanup:
J
Jim Fehlig 已提交
1081
    virDomainDefFree(def);
W
Wang Yufei 已提交
1082
    virDomainObjEndAPI(&vm);
1083
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
    return dom;
}

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

1094
    vm = virDomainObjListFindByID(driver->domains, id);
J
Jim Fehlig 已提交
1095
    if (!vm) {
1096
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
1097 1098 1099
        goto cleanup;
    }

1100 1101 1102
    if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1103
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
J
Jim Fehlig 已提交
1104

1105
 cleanup:
J
Jim Fehlig 已提交
1106
    if (vm)
1107
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
    return dom;
}

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

1118
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
J
Jim Fehlig 已提交
1119
    if (!vm) {
1120
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
1121 1122 1123
        goto cleanup;
    }

1124 1125 1126
    if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1127
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
J
Jim Fehlig 已提交
1128

1129
 cleanup:
J
Jim Fehlig 已提交
1130
    if (vm)
1131
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141
    return dom;
}

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

1142
    vm = virDomainObjListFindByName(driver->domains, name);
J
Jim Fehlig 已提交
1143
    if (!vm) {
1144
        virReportError(VIR_ERR_NO_DOMAIN, NULL);
J
Jim Fehlig 已提交
1145 1146 1147
        goto cleanup;
    }

1148 1149 1150
    if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
        goto cleanup;

1151
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
J
Jim Fehlig 已提交
1152

1153
 cleanup:
1154
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
1155 1156 1157
    return dom;
}

1158 1159 1160 1161
static int
libxlDomainSuspend(virDomainPtr dom)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1162
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1163
    virDomainObjPtr vm;
1164
    virObjectEventPtr event = NULL;
1165 1166
    int ret = -1;

J
Jim Fehlig 已提交
1167
    if (!(vm = libxlDomObjFromDomain(dom)))
1168
        goto cleanup;
1169

J
Jim Fehlig 已提交
1170 1171
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

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

1175 1176 1177
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1178
    if (!virDomainObjIsActive(vm)) {
1179
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
1180
        goto endjob;
1181 1182
    }

J
Jiri Denemark 已提交
1183
    if (virDomainObjGetState(vm, NULL) != VIR_DOMAIN_PAUSED) {
J
Jim Fehlig 已提交
1184
        if (libxl_domain_pause(cfg->ctx, vm->def->id) != 0) {
1185 1186
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to suspend domain '%d' with libxenlight"),
1187
                           vm->def->id);
1188
            goto endjob;
1189 1190
        }

J
Jiri Denemark 已提交
1191
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_USER);
1192

1193
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
1194 1195 1196
                                         VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }

1197
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
1198
        goto endjob;
1199 1200 1201

    ret = 0;

1202
 endjob:
W
Wang Yufei 已提交
1203
    libxlDomainObjEndJob(driver, vm);
1204

1205
 cleanup:
W
Wang Yufei 已提交
1206
    virDomainObjEndAPI(&vm);
1207
    if (event)
1208
        libxlDomainEventQueue(driver, event);
1209
    virObjectUnref(cfg);
1210 1211 1212 1213 1214 1215 1216 1217
    return ret;
}


static int
libxlDomainResume(virDomainPtr dom)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1218
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1219
    virDomainObjPtr vm;
1220
    virObjectEventPtr event = NULL;
1221 1222
    int ret = -1;

J
Jim Fehlig 已提交
1223
    if (!(vm = libxlDomObjFromDomain(dom)))
1224 1225
        goto cleanup;

J
Jim Fehlig 已提交
1226 1227
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

1228 1229 1230
    if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1231 1232 1233
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1234
    if (!virDomainObjIsActive(vm)) {
1235
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
1236
        goto endjob;
1237 1238
    }

J
Jiri Denemark 已提交
1239
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
J
Jim Fehlig 已提交
1240
        if (libxl_domain_unpause(cfg->ctx, vm->def->id) != 0) {
1241 1242
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to resume domain '%d' with libxenlight"),
1243
                           vm->def->id);
1244
            goto endjob;
1245 1246
        }

J
Jiri Denemark 已提交
1247 1248
        virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                             VIR_DOMAIN_RUNNING_UNPAUSED);
1249

1250
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_RESUMED,
1251 1252 1253
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
    }

1254
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
1255
        goto endjob;
1256 1257 1258

    ret = 0;

1259
 endjob:
W
Wang Yufei 已提交
1260
    libxlDomainObjEndJob(driver, vm);
1261

1262
 cleanup:
W
Wang Yufei 已提交
1263
    virDomainObjEndAPI(&vm);
1264
    if (event)
1265
        libxlDomainEventQueue(driver, event);
1266
    virObjectUnref(cfg);
1267 1268 1269
    return ret;
}

J
Jim Fehlig 已提交
1270
static int
1271
libxlDomainShutdownFlags(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
1272
{
J
Jim Fehlig 已提交
1273 1274
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1275 1276 1277
    virDomainObjPtr vm;
    int ret = -1;

1278 1279 1280 1281 1282
    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;
1283

J
Jim Fehlig 已提交
1284
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1285 1286
        goto cleanup;

J
Jim Fehlig 已提交
1287 1288
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

1289
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
1290 1291
        goto cleanup;

J
Jim Fehlig 已提交
1292
    if (!virDomainObjIsActive(vm)) {
1293 1294
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
J
Jim Fehlig 已提交
1295 1296 1297
        goto cleanup;
    }

1298
    if (flags & VIR_DOMAIN_SHUTDOWN_PARAVIRT) {
J
Jim Fehlig 已提交
1299
        ret = libxl_domain_shutdown(cfg->ctx, vm->def->id);
1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313
        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) {
J
Jim Fehlig 已提交
1314
        ret = libxl_send_trigger(cfg->ctx, vm->def->id,
1315 1316 1317 1318
                                 LIBXL_TRIGGER_POWER, 0);
        if (ret == 0)
            goto cleanup;

1319 1320
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to shutdown domain '%d' with libxenlight"),
1321
                       vm->def->id);
1322
        ret = -1;
J
Jim Fehlig 已提交
1323 1324
    }

1325
 cleanup:
J
Jim Fehlig 已提交
1326
    if (vm)
1327
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
1328
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1329 1330 1331
    return ret;
}

1332 1333 1334 1335 1336 1337 1338
static int
libxlDomainShutdown(virDomainPtr dom)
{
    return libxlDomainShutdownFlags(dom, 0);
}


J
Jim Fehlig 已提交
1339
static int
E
Eric Blake 已提交
1340
libxlDomainReboot(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
1341
{
J
Jim Fehlig 已提交
1342 1343
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1344 1345 1346
    virDomainObjPtr vm;
    int ret = -1;

J
Jim Fehlig 已提交
1347 1348 1349
    virCheckFlags(VIR_DOMAIN_REBOOT_PARAVIRT, -1);
    if (flags == 0)
        flags = VIR_DOMAIN_REBOOT_PARAVIRT;
E
Eric Blake 已提交
1350

J
Jim Fehlig 已提交
1351
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1352 1353
        goto cleanup;

J
Jim Fehlig 已提交
1354 1355
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

1356
    if (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
1357 1358
        goto cleanup;

J
Jim Fehlig 已提交
1359
    if (!virDomainObjIsActive(vm)) {
1360 1361
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
J
Jim Fehlig 已提交
1362 1363 1364
        goto cleanup;
    }

J
Jim Fehlig 已提交
1365
    if (flags & VIR_DOMAIN_REBOOT_PARAVIRT) {
J
Jim Fehlig 已提交
1366
        ret = libxl_domain_reboot(cfg->ctx, vm->def->id);
J
Jim Fehlig 已提交
1367 1368 1369
        if (ret == 0)
            goto cleanup;

1370 1371
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to reboot domain '%d' with libxenlight"),
1372
                       vm->def->id);
J
Jim Fehlig 已提交
1373
        ret = -1;
J
Jim Fehlig 已提交
1374 1375
    }

1376
 cleanup:
J
Jim Fehlig 已提交
1377
    if (vm)
1378
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
1379
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1380 1381 1382 1383
    return ret;
}

static int
1384 1385
libxlDomainDestroyFlags(virDomainPtr dom,
                        unsigned int flags)
J
Jim Fehlig 已提交
1386 1387
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
J
Jim Fehlig 已提交
1388
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1389 1390
    virDomainObjPtr vm;
    int ret = -1;
1391
    virObjectEventPtr event = NULL;
J
Jim Fehlig 已提交
1392

1393 1394
    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
1395
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1396 1397
        goto cleanup;

J
Jim Fehlig 已提交
1398 1399
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

1400 1401 1402
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1403 1404 1405
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
1406
    if (!virDomainObjIsActive(vm)) {
1407 1408
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is not running"));
1409
        goto endjob;
J
Jim Fehlig 已提交
1410 1411
    }

1412
    if (libxlDomainDestroyInternal(driver, vm) < 0) {
1413
        virReportError(VIR_ERR_INTERNAL_ERROR,
1414
                       _("Failed to destroy domain '%d'"), vm->def->id);
1415
        goto endjob;
J
Jim Fehlig 已提交
1416 1417
    }

1418 1419 1420 1421 1422 1423 1424
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
                         VIR_DOMAIN_SHUTOFF_DESTROYED);

    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);

    libxlDomainCleanup(driver, vm);
1425 1426
    if (!vm->persistent)
        virDomainObjListRemove(driver->domains, vm);
J
Jim Fehlig 已提交
1427 1428 1429

    ret = 0;

1430
 endjob:
W
Wang Yufei 已提交
1431
    libxlDomainObjEndJob(driver, vm);
1432

1433
 cleanup:
W
Wang Yufei 已提交
1434
    virDomainObjEndAPI(&vm);
1435 1436
    if (event)
        libxlDomainEventQueue(driver, event);
J
Jim Fehlig 已提交
1437
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1438 1439 1440
    return ret;
}

1441 1442 1443 1444 1445 1446
static int
libxlDomainDestroy(virDomainPtr dom)
{
    return libxlDomainDestroyFlags(dom, 0);
}

1447 1448 1449 1450 1451 1452
static char *
libxlDomainGetOSType(virDomainPtr dom)
{
    virDomainObjPtr vm;
    char *type = NULL;

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

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

1459
    if (VIR_STRDUP(type, virDomainOSTypeToString(vm->def->os.type)) < 0)
1460
        goto cleanup;
1461

1462
 cleanup:
1463
    if (vm)
1464
        virObjectUnlock(vm);
1465 1466 1467
    return type;
}

1468
static unsigned long long
1469 1470 1471
libxlDomainGetMaxMemory(virDomainPtr dom)
{
    virDomainObjPtr vm;
1472
    unsigned long long ret = 0;
1473

J
Jim Fehlig 已提交
1474
    if (!(vm = libxlDomObjFromDomain(dom)))
1475
        goto cleanup;
1476 1477 1478 1479

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

1480
    ret = virDomainDefGetMemoryTotal(vm->def);
1481

1482
 cleanup:
1483
    if (vm)
1484
        virObjectUnlock(vm);
1485 1486 1487
    return ret;
}

1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517

/*
 * Helper method for --current, --live, and --config options, and check
 * whether domain is active or can get persistent domain configuration.
 *
 * Return 0 if success, also change the flags and get the persistent
 * domain configuration if needed. Return -1 on error.
 */
static int
virDomainLiveConfigHelperMethod(virCapsPtr caps,
                                virDomainXMLOptionPtr xmlopt,
                                virDomainObjPtr dom,
                                unsigned int *flags,
                                virDomainDefPtr *persistentDef)
{
    if (virDomainObjUpdateModificationImpact(dom, flags) < 0)
        return -1;

    if (*flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (!(*persistentDef = virDomainObjGetPersistentDef(caps, xmlopt, dom))) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Get persistent config failed"));
            return -1;
        }
    }

    return 0;
}


1518
static int
1519
libxlDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
1520 1521 1522
                          unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
1523
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1524
    virDomainObjPtr vm;
1525
    virDomainDefPtr persistentDef = NULL;
1526 1527 1528
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_MEM_LIVE |
1529 1530
                  VIR_DOMAIN_MEM_CONFIG |
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
1531

J
Jim Fehlig 已提交
1532
    if (!(vm = libxlDomObjFromDomain(dom)))
1533 1534
        goto cleanup;

1535 1536 1537
    if (virDomainSetMemoryFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

1538 1539 1540
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1541 1542
    if (virDomainLiveConfigHelperMethod(cfg->caps, driver->xmlopt, vm, &flags,
                                        &persistentDef) < 0)
1543
        goto endjob;
1544

1545 1546
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
        /* resize the maximum memory */
1547

1548
        if (flags & VIR_DOMAIN_MEM_LIVE) {
J
Jim Fehlig 已提交
1549
            if (libxl_domain_setmaxmem(cfg->ctx, vm->def->id, newmem) < 0) {
1550 1551
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to set maximum memory for domain '%d'"
1552
                                 " with libxenlight"), vm->def->id);
1553
                goto endjob;
1554 1555 1556 1557 1558 1559
            }
        }

        if (flags & VIR_DOMAIN_MEM_CONFIG) {
            /* Help clang 2.8 decipher the logic flow.  */
            sa_assert(persistentDef);
1560
            virDomainDefSetMemoryTotal(persistentDef, newmem);
1561 1562
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
1563
            ret = virDomainSaveConfig(cfg->configDir, cfg->caps, persistentDef);
1564
            goto endjob;
1565 1566
        }

1567 1568
    } else {
        /* resize the current memory */
1569

1570
        if (newmem > virDomainDefGetMemoryTotal(vm->def)) {
1571 1572
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("cannot set memory higher than max memory"));
1573
            goto endjob;
1574 1575 1576
        }

        if (flags & VIR_DOMAIN_MEM_LIVE) {
1577 1578 1579 1580
            int res;

            /* Unlock virDomainObj while ballooning memory */
            virObjectUnlock(vm);
J
Jim Fehlig 已提交
1581
            res = libxl_set_memory_target(cfg->ctx, vm->def->id, newmem, 0,
1582 1583 1584
                                          /* force */ 1);
            virObjectLock(vm);
            if (res < 0) {
1585 1586
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to set memory for domain '%d'"
1587
                                 " with libxenlight"), vm->def->id);
1588
                goto endjob;
1589 1590 1591 1592 1593 1594
            }
        }

        if (flags & VIR_DOMAIN_MEM_CONFIG) {
            sa_assert(persistentDef);
            persistentDef->mem.cur_balloon = newmem;
1595
            ret = virDomainSaveConfig(cfg->configDir, cfg->caps, persistentDef);
1596
            goto endjob;
1597
        }
1598 1599
    }

1600 1601
    ret = 0;

1602
 endjob:
W
Wang Yufei 已提交
1603
    libxlDomainObjEndJob(driver, vm);
1604

1605
 cleanup:
W
Wang Yufei 已提交
1606
    virDomainObjEndAPI(&vm);
1607
    virObjectUnref(cfg);
1608 1609 1610 1611 1612 1613 1614 1615 1616
    return ret;
}

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

1617 1618 1619 1620 1621 1622
static int
libxlDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
{
    return libxlDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
}

J
Jim Fehlig 已提交
1623 1624 1625
static int
libxlDomainGetInfo(virDomainPtr dom, virDomainInfoPtr info)
{
J
Jim Fehlig 已提交
1626 1627
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
1628
    virDomainObjPtr vm;
1629
    libxl_dominfo d_info;
J
Jim Fehlig 已提交
1630 1631
    int ret = -1;

J
Jim Fehlig 已提交
1632
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
1633 1634
        goto cleanup;

1635 1636 1637
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1638
    info->maxMem = virDomainDefGetMemoryTotal(vm->def);
1639 1640 1641 1642
    if (!virDomainObjIsActive(vm)) {
        info->cpuTime = 0;
        info->memory = vm->def->mem.cur_balloon;
    } else {
1643 1644
        libxl_dominfo_init(&d_info);

J
Jim Fehlig 已提交
1645
        if (libxl_domain_info(cfg->ctx, &d_info, vm->def->id) != 0) {
1646
            virReportError(VIR_ERR_INTERNAL_ERROR,
1647 1648
                           _("libxl_domain_info failed for domain '%d'"),
                           vm->def->id);
1649 1650 1651 1652
            goto cleanup;
        }
        info->cpuTime = d_info.cpu_time;
        info->memory = d_info.current_memkb;
1653 1654

        libxl_dominfo_dispose(&d_info);
1655 1656
    }

J
Jiri Denemark 已提交
1657
    info->state = virDomainObjGetState(vm, NULL);
1658
    info->nrVirtCpu = virDomainDefGetVcpus(vm->def);
J
Jim Fehlig 已提交
1659 1660
    ret = 0;

1661
 cleanup:
J
Jim Fehlig 已提交
1662
    if (vm)
1663
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
1664
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
1665 1666 1667
    return ret;
}

1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
static int
libxlDomainGetState(virDomainPtr dom,
                    int *state,
                    int *reason,
                    unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
1679
    if (!(vm = libxlDomObjFromDomain(dom)))
1680 1681
        goto cleanup;

1682 1683 1684
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
1685
    *state = virDomainObjGetState(vm, reason);
1686 1687
    ret = 0;

1688
 cleanup:
1689
    if (vm)
1690
        virObjectUnlock(vm);
1691 1692 1693
    return ret;
}

1694 1695 1696
/*
 * virDomainObjPtr must be locked on invocation
 */
1697
static int
1698 1699
libxlDoDomainSave(libxlDriverPrivatePtr driver, virDomainObjPtr vm,
                  const char *to)
1700
{
J
Jim Fehlig 已提交
1701
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1702
    libxlSavefileHeader hdr;
1703
    virObjectEventPtr event = NULL;
1704 1705
    char *xml = NULL;
    uint32_t xml_len;
1706
    int fd = -1;
1707 1708 1709
    int ret = -1;

    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PAUSED) {
1710 1711 1712
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("Domain '%d' has to be running because libxenlight will"
                         " suspend it"), vm->def->id);
1713 1714 1715 1716
        goto cleanup;
    }

    if ((fd = virFileOpenAs(to, O_CREAT|O_TRUNC|O_WRONLY, S_IRUSR|S_IWUSR,
L
Laine Stump 已提交
1717
                            -1, -1, 0)) < 0) {
1718 1719 1720 1721 1722
        virReportSystemError(-fd,
                             _("Failed to create domain save file '%s'"), to);
        goto cleanup;
    }

1723
    if ((xml = virDomainDefFormat(vm->def, cfg->caps, 0)) == NULL)
1724 1725 1726 1727 1728 1729 1730 1731 1732
        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)) {
1733 1734
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Failed to write save file header"));
1735 1736 1737 1738
        goto cleanup;
    }

    if (safewrite(fd, xml, xml_len) != xml_len) {
1739 1740
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Failed to write xml description"));
1741 1742 1743
        goto cleanup;
    }

1744 1745
    /* Unlock virDomainObj while saving domain */
    virObjectUnlock(vm);
J
Jim Fehlig 已提交
1746
    ret = libxl_domain_suspend(cfg->ctx, vm->def->id, fd, 0, NULL);
1747 1748 1749
    virObjectLock(vm);

    if (ret != 0) {
1750 1751 1752
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to save domain '%d' with libxenlight"),
                       vm->def->id);
1753
        ret = -1;
1754 1755 1756
        goto cleanup;
    }

1757 1758 1759
    virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
                         VIR_DOMAIN_SHUTOFF_SAVED);

1760
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
1761 1762
                                         VIR_DOMAIN_EVENT_STOPPED_SAVED);

1763
    if (libxlDomainDestroyInternal(driver, vm) < 0) {
1764 1765
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to destroy domain '%d'"), vm->def->id);
1766 1767 1768
        goto cleanup;
    }

1769
    libxlDomainCleanup(driver, vm);
1770
    vm->hasManagedSave = true;
1771 1772
    ret = 0;

1773
 cleanup:
1774 1775 1776 1777 1778
    VIR_FREE(xml);
    if (VIR_CLOSE(fd) < 0)
        virReportSystemError(errno, "%s", _("cannot close file"));
    if (event)
        libxlDomainEventQueue(driver, event);
J
Jim Fehlig 已提交
1779
    virObjectUnref(cfg);
1780 1781 1782 1783
    return ret;
}

static int
1784 1785
libxlDomainSaveFlags(virDomainPtr dom, const char *to, const char *dxml,
                     unsigned int flags)
1786
{
1787 1788
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
1789
    int ret = -1;
1790
    bool remove_dom = false;
1791

1792 1793 1794 1795 1796
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

1797 1798
    virCheckFlags(0, -1);
    if (dxml) {
1799 1800
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("xml modification unsupported"));
1801 1802 1803
        return -1;
    }

J
Jim Fehlig 已提交
1804
    if (!(vm = libxlDomObjFromDomain(dom)))
1805 1806
        goto cleanup;

J
Jim Fehlig 已提交
1807 1808
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

1809 1810 1811
    if (virDomainSaveFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

1812 1813 1814
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1815
    if (!virDomainObjIsActive(vm)) {
1816
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
1817
        goto endjob;
1818 1819
    }

1820
    if (libxlDoDomainSave(driver, vm, to) < 0)
1821
        goto endjob;
1822

1823 1824
    if (!vm->persistent)
        remove_dom = true;
1825 1826

    ret = 0;
1827

1828
 endjob:
W
Wang Yufei 已提交
1829
    libxlDomainObjEndJob(driver, vm);
1830

1831
 cleanup:
1832 1833 1834 1835
    if (remove_dom && vm) {
        virDomainObjListRemove(driver->domains, vm);
        vm = NULL;
    }
W
Wang Yufei 已提交
1836
    virDomainObjEndAPI(&vm);
1837 1838
    return ret;
}
1839

1840
static int
1841 1842 1843 1844 1845 1846 1847 1848
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)
1849 1850
{
    libxlDriverPrivatePtr driver = conn->privateData;
1851
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1852 1853 1854 1855 1856
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    libxlSavefileHeader hdr;
    int fd = -1;
    int ret = -1;
1857

1858 1859 1860 1861 1862
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

1863
    virCheckFlags(VIR_DOMAIN_SAVE_PAUSED, -1);
1864
    if (dxml) {
1865 1866
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("xml modification unsupported"));
1867 1868 1869
        return -1;
    }

1870
    fd = libxlDomainSaveImageOpen(driver, cfg, from, &def, &hdr);
1871
    if (fd < 0)
1872
        goto cleanup;
1873

1874
    if (virDomainRestoreFlagsEnsureACL(conn, def) < 0)
1875
        goto cleanup;
1876

1877
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1878
                                   driver->xmlopt,
1879 1880 1881
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1882
        goto cleanup;
W
Wang Yufei 已提交
1883
    virObjectRef(vm);
1884 1885
    def = NULL;

1886 1887 1888 1889 1890 1891 1892 1893
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) {
        if (!vm->persistent) {
            virDomainObjListRemove(driver->domains, vm);
            vm = NULL;
        }
        goto cleanup;
    }

1894 1895 1896
    ret = libxlDomainStartRestore(driver, vm,
                                  (flags & VIR_DOMAIN_SAVE_PAUSED) != 0,
                                  fd, hdr.version);
1897
    if (ret < 0 && !vm->persistent)
1898
        virDomainObjListRemove(driver->domains, vm);
1899

W
Wang Yufei 已提交
1900
    libxlDomainObjEndJob(driver, vm);
1901

1902
 cleanup:
1903 1904
    if (VIR_CLOSE(fd) < 0)
        virReportSystemError(errno, "%s", _("cannot close file"));
1905
    virDomainDefFree(def);
W
Wang Yufei 已提交
1906
    virDomainObjEndAPI(&vm);
1907
    virObjectUnref(cfg);
1908 1909 1910
    return ret;
}

1911 1912 1913 1914 1915 1916
static int
libxlDomainRestore(virConnectPtr conn, const char *from)
{
    return libxlDomainRestoreFlags(conn, from, NULL, 0);
}

1917
static int
1918
libxlDomainCoreDump(virDomainPtr dom, const char *to, unsigned int flags)
1919 1920
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
J
Jim Fehlig 已提交
1921
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
1922
    virDomainObjPtr vm;
1923
    virObjectEventPtr event = NULL;
1924
    bool remove_dom = false;
1925 1926 1927 1928 1929
    bool paused = false;
    int ret = -1;

    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH, -1);

J
Jim Fehlig 已提交
1930
    if (!(vm = libxlDomObjFromDomain(dom)))
1931 1932
        goto cleanup;

J
Jim Fehlig 已提交
1933 1934
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

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

1938 1939 1940
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

1941
    if (!virDomainObjIsActive(vm)) {
1942
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
1943
        goto endjob;
1944 1945 1946 1947
    }

    if (!(flags & VIR_DUMP_LIVE) &&
        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
J
Jim Fehlig 已提交
1948
        if (libxl_domain_pause(cfg->ctx, vm->def->id) != 0) {
1949 1950 1951
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Before dumping core, failed to suspend domain '%d'"
                             " with libxenlight"),
1952
                           vm->def->id);
1953
            goto endjob;
1954 1955 1956 1957 1958
        }
        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED, VIR_DOMAIN_PAUSED_DUMP);
        paused = true;
    }

1959 1960
    /* Unlock virDomainObj while dumping core */
    virObjectUnlock(vm);
J
Jim Fehlig 已提交
1961
    ret = libxl_domain_core_dump(cfg->ctx, vm->def->id, to, NULL);
1962 1963
    virObjectLock(vm);
    if (ret != 0) {
1964 1965
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to dump core of domain '%d' with libxenlight"),
1966
                       vm->def->id);
1967 1968
        ret = -1;
        goto unpause;
1969 1970 1971
    }

    if (flags & VIR_DUMP_CRASH) {
1972
        if (libxlDomainDestroyInternal(driver, vm) < 0) {
1973
            virReportError(VIR_ERR_INTERNAL_ERROR,
1974
                           _("Failed to destroy domain '%d'"), vm->def->id);
1975
            goto unpause;
1976 1977
        }

1978 1979 1980
        libxlDomainCleanup(driver, vm);
        virDomainObjSetState(vm, VIR_DOMAIN_SHUTOFF,
                             VIR_DOMAIN_SHUTOFF_CRASHED);
1981
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
1982
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
1983 1984
        if (!vm->persistent)
            remove_dom = true;
1985 1986 1987 1988
    }

    ret = 0;

1989
 unpause:
1990
    if (virDomainObjIsActive(vm) && paused) {
J
Jim Fehlig 已提交
1991
        if (libxl_domain_unpause(cfg->ctx, vm->def->id) != 0) {
1992 1993
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("After dumping core, failed to resume domain '%d' with"
1994
                             " libxenlight"), vm->def->id);
1995 1996 1997 1998 1999
        } else {
            virDomainObjSetState(vm, VIR_DOMAIN_RUNNING,
                                 VIR_DOMAIN_RUNNING_UNPAUSED);
        }
    }
2000

2001
 endjob:
W
Wang Yufei 已提交
2002
    libxlDomainObjEndJob(driver, vm);
2003

2004
 cleanup:
2005 2006 2007 2008
    if (remove_dom && vm) {
        virDomainObjListRemove(driver->domains, vm);
        vm = NULL;
    }
W
Wang Yufei 已提交
2009
    virDomainObjEndAPI(&vm);
2010
    if (event)
2011
        libxlDomainEventQueue(driver, event);
J
Jim Fehlig 已提交
2012
    virObjectUnref(cfg);
2013 2014 2015
    return ret;
}

2016 2017 2018 2019 2020 2021 2022
static int
libxlDomainManagedSave(virDomainPtr dom, unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    char *name = NULL;
    int ret = -1;
2023
    bool remove_dom = false;
2024 2025 2026

    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
2027
    if (!(vm = libxlDomObjFromDomain(dom)))
2028 2029
        goto cleanup;

J
Jim Fehlig 已提交
2030 2031
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

2032 2033 2034
    if (virDomainManagedSaveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2035 2036 2037
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

2038
    if (!virDomainObjIsActive(vm)) {
2039
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
2040
        goto endjob;
2041
    }
2042
    if (!vm->persistent) {
2043 2044
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot do managed save for transient domain"));
2045
        goto endjob;
2046
    }
2047 2048 2049

    name = libxlDomainManagedSavePath(driver, vm);
    if (name == NULL)
2050
        goto endjob;
2051 2052 2053

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

2054
    if (libxlDoDomainSave(driver, vm, name) < 0)
2055
        goto endjob;
2056

2057 2058
    if (!vm->persistent)
        remove_dom = true;
2059 2060

    ret = 0;
2061

2062
 endjob:
W
Wang Yufei 已提交
2063
    libxlDomainObjEndJob(driver, vm);
2064

2065
 cleanup:
2066 2067 2068 2069
    if (remove_dom && vm) {
        virDomainObjListRemove(driver->domains, vm);
        vm = NULL;
    }
W
Wang Yufei 已提交
2070
    virDomainObjEndAPI(&vm);
2071 2072 2073 2074
    VIR_FREE(name);
    return ret;
}

2075 2076
static int
libxlDomainManagedSaveLoad(virDomainObjPtr vm,
2077 2078 2079 2080
                           void *opaque)
{
    libxlDriverPrivatePtr driver = opaque;
    char *name;
2081
    int ret = -1;
2082

2083
    virObjectLock(vm);
2084 2085 2086 2087 2088 2089

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

    vm->hasManagedSave = virFileExists(name);

2090
    ret = 0;
2091
 cleanup:
2092
    virObjectUnlock(vm);
2093
    VIR_FREE(name);
2094
    return ret;
2095 2096
}

2097 2098 2099 2100 2101 2102 2103 2104
static int
libxlDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

J
Jim Fehlig 已提交
2105
    if (!(vm = libxlDomObjFromDomain(dom)))
2106 2107
        goto cleanup;

2108 2109 2110
    if (virDomainHasManagedSaveImageEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2111
    ret = vm->hasManagedSave;
2112

2113
 cleanup:
2114
    if (vm)
2115
        virObjectUnlock(vm);
2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128
    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 已提交
2129
    if (!(vm = libxlDomObjFromDomain(dom)))
2130 2131
        goto cleanup;

2132 2133 2134
    if (virDomainManagedSaveRemoveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2135 2136 2137 2138 2139
    name = libxlDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    ret = unlink(name);
2140
    vm->hasManagedSave = false;
2141

2142
 cleanup:
2143 2144
    VIR_FREE(name);
    if (vm)
2145
        virObjectUnlock(vm);
2146 2147 2148
    return ret;
}

2149 2150 2151 2152 2153
static int
libxlDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                         unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
2154
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2155 2156
    virDomainDefPtr def;
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
2157
    libxl_bitmap map;
2158 2159
    uint8_t *bitmask = NULL;
    unsigned int maplen;
2160 2161
    size_t i;
    unsigned int pos;
2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173
    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)) {
2174 2175
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid flag combination: (0x%x)"), flags);
2176 2177 2178 2179
        return -1;
    }

    if (!nvcpus) {
2180
        virReportError(VIR_ERR_INVALID_ARG, "%s", _("nvcpus is zero"));
2181 2182 2183
        return -1;
    }

J
Jim Fehlig 已提交
2184
    if (!(vm = libxlDomObjFromDomain(dom)))
2185 2186
        goto cleanup;

2187 2188 2189
    if (virDomainSetVcpusFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

2190 2191 2192
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

2193
    if (!virDomainObjIsActive(vm) && (flags & VIR_DOMAIN_VCPU_LIVE)) {
2194 2195
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot set vcpus on an inactive domain"));
2196
        goto endjob;
2197 2198 2199
    }

    if (!vm->persistent && (flags & VIR_DOMAIN_VCPU_CONFIG)) {
2200 2201
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot change persistent config of a transient domain"));
2202
        goto endjob;
2203 2204
    }

2205
    if ((max = libxlConnectGetMaxVcpus(dom->conn, NULL)) < 0) {
2206 2207
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not determine max vcpus for the domain"));
2208
        goto endjob;
2209 2210
    }

2211 2212
    if (!(flags & VIR_DOMAIN_VCPU_MAXIMUM) && virDomainDefGetVcpusMax(vm->def) < max)
        max = virDomainDefGetVcpusMax(vm->def);
2213 2214

    if (nvcpus > max) {
2215 2216 2217
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the domain: %d > %d"), nvcpus, max);
2218
        goto endjob;
2219 2220
    }

2221
    if (!(def = virDomainObjGetPersistentDef(cfg->caps, driver->xmlopt, vm)))
2222
        goto endjob;
2223

E
Eric Blake 已提交
2224
    maplen = VIR_CPU_MAPLEN(nvcpus);
2225
    if (VIR_ALLOC_N(bitmask, maplen) < 0)
2226
        goto endjob;
2227 2228

    for (i = 0; i < nvcpus; ++i) {
E
Eric Blake 已提交
2229
        pos = i / 8;
2230 2231 2232 2233 2234 2235 2236 2237
        bitmask[pos] |= 1 << (i % 8);
    }

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

    switch (flags) {
    case VIR_DOMAIN_VCPU_MAXIMUM | VIR_DOMAIN_VCPU_CONFIG:
2238
        if (virDomainDefSetVcpusMax(def, nvcpus, driver->xmlopt) < 0)
2239
            goto cleanup;
2240 2241 2242
        break;

    case VIR_DOMAIN_VCPU_CONFIG:
2243 2244
        if (virDomainDefSetVcpus(def, nvcpus) < 0)
            goto cleanup;
2245 2246 2247
        break;

    case VIR_DOMAIN_VCPU_LIVE:
J
Jim Fehlig 已提交
2248
        if (libxl_set_vcpuonline(cfg->ctx, vm->def->id, &map) != 0) {
2249 2250
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to set vcpus for domain '%d'"
2251
                             " with libxenlight"), vm->def->id);
2252
            goto endjob;
2253
        }
2254 2255
        if (virDomainDefSetVcpus(vm->def, nvcpus) < 0)
            goto endjob;
2256 2257 2258
        break;

    case VIR_DOMAIN_VCPU_LIVE | VIR_DOMAIN_VCPU_CONFIG:
J
Jim Fehlig 已提交
2259
        if (libxl_set_vcpuonline(cfg->ctx, vm->def->id, &map) != 0) {
2260 2261
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to set vcpus for domain '%d'"
2262
                             " with libxenlight"), vm->def->id);
2263
            goto endjob;
2264
        }
2265 2266 2267
        if (virDomainDefSetVcpus(vm->def, nvcpus) < 0 ||
            virDomainDefSetVcpus(def, nvcpus) < 0)
            goto endjob;
2268 2269 2270 2271 2272
        break;
    }

    ret = 0;

2273
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
2274
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0) {
2275 2276 2277 2278 2279
            VIR_WARN("Unable to save status on vm %s after changing vcpus",
                     vm->def->name);
        }
    }
    if (flags & VIR_DOMAIN_VCPU_CONFIG) {
2280
        if (virDomainSaveConfig(cfg->configDir, cfg->caps, def) < 0) {
2281 2282 2283 2284
            VIR_WARN("Unable to save configuration of vm %s after changing vcpus",
                     vm->def->name);
        }
    }
2285

2286
 endjob:
W
Wang Yufei 已提交
2287
    libxlDomainObjEndJob(driver, vm);
2288

2289
 cleanup:
2290
    VIR_FREE(bitmask);
W
Wang Yufei 已提交
2291 2292
    virDomainObjEndAPI(&vm);
    virObjectUnref(cfg);
2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307
    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;
2308
    bool active;
2309 2310 2311 2312 2313

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

J
Jim Fehlig 已提交
2314
    if (!(vm = libxlDomObjFromDomain(dom)))
2315 2316
        goto cleanup;

2317
    if (virDomainGetVcpusFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
2318 2319
        goto cleanup;

2320 2321 2322 2323 2324 2325 2326 2327 2328
    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)) {
2329 2330
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid flag combination: (0x%x)"), flags);
2331 2332 2333
        return -1;
    }

2334
    if (flags & VIR_DOMAIN_VCPU_LIVE) {
2335
        if (!active) {
2336 2337
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("Domain is not running"));
2338 2339 2340 2341
            goto cleanup;
        }
        def = vm->def;
    } else {
2342
        if (!vm->persistent) {
2343 2344
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("domain is transient"));
2345 2346
            goto cleanup;
        }
2347 2348 2349
        def = vm->newDef ? vm->newDef : vm->def;
    }

2350 2351 2352
    if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
        ret = virDomainDefGetVcpusMax(def);
    else
2353
        ret = virDomainDefGetVcpus(def);
2354

2355
 cleanup:
2356
    if (vm)
2357
        virObjectUnlock(vm);
2358 2359 2360
    return ret;
}

2361 2362 2363 2364 2365 2366 2367
static int
libxlDomainGetMaxVcpus(virDomainPtr dom)
{
    return libxlDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
                                          VIR_DOMAIN_VCPU_MAXIMUM));
}

2368
static int
2369 2370 2371
libxlDomainPinVcpuFlags(virDomainPtr dom, unsigned int vcpu,
                        unsigned char *cpumap, int maplen,
                        unsigned int flags)
2372 2373
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
2374
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2375
    virDomainDefPtr targetDef = NULL;
2376
    virBitmapPtr pcpumap = NULL;
2377
    virDomainVcpuDefPtr vcpuinfo;
2378 2379
    virDomainObjPtr vm;
    int ret = -1;
2380 2381 2382

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
2383

J
Jim Fehlig 已提交
2384
    if (!(vm = libxlDomObjFromDomain(dom)))
2385 2386
        goto cleanup;

2387
    if (virDomainPinVcpuFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
2388 2389
        goto cleanup;

2390 2391 2392
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

2393 2394
    if (virDomainLiveConfigHelperMethod(cfg->caps, driver->xmlopt, vm,
                                        &flags, &targetDef) < 0)
2395
        goto endjob;
2396

2397
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
2398 2399 2400 2401 2402
        targetDef = vm->def;

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

2403 2404
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
2405
        goto endjob;
2406

2407 2408 2409 2410 2411 2412 2413
    if (!(vcpuinfo = virDomainDefGetVcpu(targetDef, vcpu)) ||
        !vcpuinfo->online) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("vcpu '%u' is not active"), vcpu);
        goto endjob;
    }

2414 2415
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        libxl_bitmap map = { .size = maplen, .map = cpumap };
J
Jim Fehlig 已提交
2416
        if (libxl_set_vcpuaffinity(cfg->ctx, vm->def->id, vcpu, &map) != 0) {
2417 2418 2419
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Failed to pin vcpu '%d' with libxenlight"),
                           vcpu);
2420
            goto endjob;
2421
        }
2422
    }
2423

2424 2425 2426
    virBitmapFree(vcpuinfo->cpumask);
    vcpuinfo->cpumask = pcpumap;
    pcpumap = NULL;
2427

2428 2429
    ret = 0;

2430
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2431
        ret = virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps);
2432
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
2433
        ret = virDomainSaveConfig(cfg->configDir, cfg->caps, targetDef);
2434 2435
    }

2436
 endjob:
W
Wang Yufei 已提交
2437
    libxlDomainObjEndJob(driver, vm);
2438

2439
 cleanup:
W
Wang Yufei 已提交
2440
    virDomainObjEndAPI(&vm);
2441
    virBitmapFree(pcpumap);
2442
    virObjectUnref(cfg);
2443 2444 2445
    return ret;
}

2446 2447 2448 2449 2450 2451 2452 2453
static int
libxlDomainPinVcpu(virDomainPtr dom, unsigned int vcpu, unsigned char *cpumap,
                   int maplen)
{
    return libxlDomainPinVcpuFlags(dom, vcpu, cpumap, maplen,
                                   VIR_DOMAIN_AFFECT_LIVE);
}

2454 2455 2456 2457 2458 2459 2460 2461 2462
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;
2463
    int ret = -1;
2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477

    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;

2478
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
2479 2480 2481 2482 2483
        targetDef = vm->def;

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

2484 2485
    ret = virDomainDefGetVcpuPinInfoHelper(targetDef, maplen, ncpumaps, cpumaps,
                                           libxl_get_max_cpus(cfg->ctx), NULL);
2486

2487
 cleanup:
2488 2489 2490 2491 2492
    if (vm)
        virObjectUnlock(vm);
    virObjectUnref(cfg);
    return ret;
}
2493 2494 2495 2496 2497

static int
libxlDomainGetVcpus(virDomainPtr dom, virVcpuInfoPtr info, int maxinfo,
                    unsigned char *cpumaps, int maplen)
{
J
Jim Fehlig 已提交
2498 2499
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2500 2501 2502 2503
    virDomainObjPtr vm;
    int ret = -1;
    libxl_vcpuinfo *vcpuinfo;
    int maxcpu, hostcpus;
2504
    size_t i;
2505 2506
    unsigned char *cpumap;

J
Jim Fehlig 已提交
2507
    if (!(vm = libxlDomObjFromDomain(dom)))
2508 2509
        goto cleanup;

2510 2511 2512
    if (virDomainGetVcpusEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

J
Jim Fehlig 已提交
2518
    if ((vcpuinfo = libxl_list_vcpu(cfg->ctx, vm->def->id, &maxcpu,
2519
                                    &hostcpus)) == NULL) {
2520 2521
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to list vcpus for domain '%d' with libxenlight"),
2522
                       vm->def->id);
2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544
        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 已提交
2545
        libxl_vcpuinfo_dispose(&vcpuinfo[i]);
2546 2547 2548 2549 2550
    }
    VIR_FREE(vcpuinfo);

    ret = maxinfo;

2551
 cleanup:
2552
    if (vm)
2553
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
2554
    virObjectUnref(cfg);
2555 2556 2557
    return ret;
}

J
Jim Fehlig 已提交
2558
static char *
2559
libxlDomainGetXMLDesc(virDomainPtr dom, unsigned int flags)
J
Jim Fehlig 已提交
2560
{
2561 2562
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
2563
    virDomainObjPtr vm;
2564
    virDomainDefPtr def;
J
Jim Fehlig 已提交
2565 2566
    char *ret = NULL;

2567 2568
    /* Flags checked by virDomainDefFormat */

J
Jim Fehlig 已提交
2569
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
2570 2571
        goto cleanup;

2572 2573 2574
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

2575 2576 2577 2578 2579
    if ((flags & VIR_DOMAIN_XML_INACTIVE) && vm->newDef)
        def = vm->newDef;
    else
        def = vm->def;

2580
    ret = virDomainDefFormat(def, cfg->caps,
2581
                             virDomainDefFormatConvertXMLFlags(flags));
J
Jim Fehlig 已提交
2582

2583
 cleanup:
J
Jim Fehlig 已提交
2584
    if (vm)
2585
        virObjectUnlock(vm);
2586
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
2587 2588 2589
    return ret;
}

2590
static char *
2591 2592 2593
libxlConnectDomainXMLFromNative(virConnectPtr conn,
                                const char *nativeFormat,
                                const char *nativeConfig,
2594
                                unsigned int flags)
2595 2596
{
    libxlDriverPrivatePtr driver = conn->privateData;
2597
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2598 2599 2600 2601
    virDomainDefPtr def = NULL;
    virConfPtr conf = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
2602 2603
    virCheckFlags(0, NULL);

2604 2605 2606
    if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0)
        goto cleanup;

2607
    if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XL)) {
J
Ján Tomko 已提交
2608
        if (!(conf = virConfReadString(nativeConfig, 0)))
2609 2610 2611
            goto cleanup;
        if (!(def = xenParseXL(conf,
                               cfg->caps,
2612
                               driver->xmlopt)))
2613
            goto cleanup;
2614
    } else if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XM)) {
J
Ján Tomko 已提交
2615
        if (!(conf = virConfReadString(nativeConfig, 0)))
2616 2617 2618
            goto cleanup;

        if (!(def = xenParseXM(conf,
2619 2620
                               cfg->caps,
                               driver->xmlopt)))
2621
            goto cleanup;
2622
    } else if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_SEXPR)) {
2623 2624 2625
        /* only support latest xend config format */
        if (!(def = xenParseSxprString(nativeConfig,
                                       NULL,
2626 2627 2628
                                       -1,
                                       cfg->caps,
                                       driver->xmlopt))) {
2629 2630 2631 2632 2633
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("parsing sxpr config failed"));
            goto cleanup;
        }
    } else {
2634 2635
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), nativeFormat);
2636 2637 2638
        goto cleanup;
    }

2639
    xml = virDomainDefFormat(def, cfg->caps, VIR_DOMAIN_DEF_FORMAT_INACTIVE);
2640

2641
 cleanup:
2642 2643 2644
    virDomainDefFree(def);
    if (conf)
        virConfFree(conf);
2645
    virObjectUnref(cfg);
2646 2647 2648 2649 2650
    return xml;
}

#define MAX_CONFIG_SIZE (1024 * 65)
static char *
2651 2652 2653
libxlConnectDomainXMLToNative(virConnectPtr conn, const char * nativeFormat,
                              const char * domainXml,
                              unsigned int flags)
2654 2655
{
    libxlDriverPrivatePtr driver = conn->privateData;
2656
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
2657 2658 2659 2660 2661
    virDomainDefPtr def = NULL;
    virConfPtr conf = NULL;
    int len = MAX_CONFIG_SIZE;
    char *ret = NULL;

E
Eric Blake 已提交
2662 2663
    virCheckFlags(0, NULL);

2664 2665 2666
    if (virConnectDomainXMLToNativeEnsureACL(conn) < 0)
        goto cleanup;

2667
    if (!(def = virDomainDefParseString(domainXml,
2668
                                        cfg->caps, driver->xmlopt, NULL,
2669
                                        VIR_DOMAIN_DEF_PARSE_INACTIVE)))
2670 2671
        goto cleanup;

2672
    if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XL)) {
2673
        if (!(conf = xenFormatXL(def, conn)))
2674
            goto cleanup;
2675
    } else if (STREQ(nativeFormat, XEN_CONFIG_FORMAT_XM)) {
2676
        if (!(conf = xenFormatXM(conn, def)))
2677 2678 2679 2680 2681
            goto cleanup;
    } else {

        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), nativeFormat);
2682
        goto cleanup;
2683
    }
2684

2685
    if (VIR_ALLOC_N(ret, len) < 0)
2686 2687 2688 2689 2690 2691 2692
        goto cleanup;

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

2693
 cleanup:
2694 2695 2696
    virDomainDefFree(def);
    if (conf)
        virConfFree(conf);
2697
    virObjectUnref(cfg);
2698 2699 2700
    return ret;
}

J
Jim Fehlig 已提交
2701
static int
2702 2703
libxlConnectListDefinedDomains(virConnectPtr conn,
                               char **const names, int nnames)
J
Jim Fehlig 已提交
2704 2705 2706 2707
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

2708 2709 2710
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        return -1;

2711 2712
    n = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
                                         virConnectListDefinedDomainsCheckACL, conn);
J
Jim Fehlig 已提交
2713 2714 2715 2716
    return n;
}

static int
2717
libxlConnectNumOfDefinedDomains(virConnectPtr conn)
J
Jim Fehlig 已提交
2718 2719 2720 2721
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int n;

2722 2723 2724
    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        return -1;

2725
    n = virDomainObjListNumOfDomains(driver->domains, false,
2726 2727
                                     virConnectNumOfDefinedDomainsCheckACL,
                                     conn);
J
Jim Fehlig 已提交
2728 2729 2730 2731 2732
    return n;
}

static int
libxlDomainCreateWithFlags(virDomainPtr dom,
E
Eric Blake 已提交
2733
                           unsigned int flags)
J
Jim Fehlig 已提交
2734 2735 2736 2737 2738 2739 2740
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_START_PAUSED, -1);

J
Jim Fehlig 已提交
2741
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
2742 2743
        goto cleanup;

2744 2745 2746
    if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2747 2748 2749
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
2750
    if (virDomainObjIsActive(vm)) {
2751 2752
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("Domain is already running"));
2753
        goto endjob;
J
Jim Fehlig 已提交
2754 2755
    }

2756 2757
    ret = libxlDomainStartNew(driver, vm,
                              (flags & VIR_DOMAIN_START_PAUSED) != 0);
2758
    if (ret < 0)
2759
        goto endjob;
2760
    dom->id = vm->def->id;
J
Jim Fehlig 已提交
2761

2762
 endjob:
W
Wang Yufei 已提交
2763
    libxlDomainObjEndJob(driver, vm);
2764

2765
 cleanup:
W
Wang Yufei 已提交
2766
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
2767 2768 2769 2770 2771 2772 2773 2774 2775 2776
    return ret;
}

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

static virDomainPtr
2777
libxlDomainDefineXMLFlags(virConnectPtr conn, const char *xml, unsigned int flags)
J
Jim Fehlig 已提交
2778 2779
{
    libxlDriverPrivatePtr driver = conn->privateData;
2780
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
2781 2782 2783
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    virDomainPtr dom = NULL;
2784
    virObjectEventPtr event = NULL;
2785
    virDomainDefPtr oldDef = NULL;
2786
    unsigned int parse_flags = VIR_DOMAIN_DEF_PARSE_INACTIVE;
J
Jim Fehlig 已提交
2787

2788 2789 2790
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

    if (flags & VIR_DOMAIN_DEFINE_VALIDATE)
2791
        parse_flags |= VIR_DOMAIN_DEF_PARSE_VALIDATE_SCHEMA;
2792

2793
    if (!(def = virDomainDefParseString(xml, cfg->caps, driver->xmlopt,
2794
                                        NULL, parse_flags)))
2795
        goto cleanup;
J
Jim Fehlig 已提交
2796

2797 2798 2799
    if (virXMLCheckIllegalChars("name", def->name, "\n") < 0)
        goto cleanup;

2800
    if (virDomainDefineXMLFlagsEnsureACL(conn, def) < 0)
2801
        goto cleanup;
2802

2803
    if (!(vm = virDomainObjListAdd(driver->domains, def,
2804
                                   driver->xmlopt,
2805 2806
                                   0,
                                   &oldDef)))
2807
        goto cleanup;
2808

J
Jim Fehlig 已提交
2809 2810 2811
    def = NULL;
    vm->persistent = 1;

2812
    if (virDomainSaveConfig(cfg->configDir,
2813
                            cfg->caps,
J
Jim Fehlig 已提交
2814
                            vm->newDef ? vm->newDef : vm->def) < 0) {
2815
        virDomainObjListRemove(driver->domains, vm);
J
Jim Fehlig 已提交
2816 2817 2818 2819
        vm = NULL;
        goto cleanup;
    }

2820
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid, vm->def->id);
J
Jim Fehlig 已提交
2821

2822
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_DEFINED,
2823
                                     !oldDef ?
2824 2825 2826
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);

2827
 cleanup:
J
Jim Fehlig 已提交
2828
    virDomainDefFree(def);
2829
    virDomainDefFree(oldDef);
J
Jim Fehlig 已提交
2830
    if (vm)
2831
        virObjectUnlock(vm);
2832 2833
    if (event)
        libxlDomainEventQueue(driver, event);
2834
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
2835 2836 2837
    return dom;
}

2838 2839 2840 2841 2842 2843
static virDomainPtr
libxlDomainDefineXML(virConnectPtr conn, const char *xml)
{
    return libxlDomainDefineXMLFlags(conn, xml, 0);
}

J
Jim Fehlig 已提交
2844
static int
2845 2846
libxlDomainUndefineFlags(virDomainPtr dom,
                         unsigned int flags)
J
Jim Fehlig 已提交
2847 2848
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
2849
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
J
Jim Fehlig 已提交
2850
    virDomainObjPtr vm;
2851
    virObjectEventPtr event = NULL;
2852
    char *name = NULL;
J
Jim Fehlig 已提交
2853 2854
    int ret = -1;

2855 2856
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE, -1);

J
Jim Fehlig 已提交
2857
    if (!(vm = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
2858 2859
        goto cleanup;

2860 2861 2862
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jim Fehlig 已提交
2863
    if (!vm->persistent) {
2864 2865
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
J
Jim Fehlig 已提交
2866 2867 2868
        goto cleanup;
    }

2869 2870 2871 2872 2873 2874 2875
    name = libxlDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    if (virFileExists(name)) {
        if (flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE) {
            if (unlink(name) < 0) {
2876 2877
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to remove domain managed save image"));
2878 2879 2880
                goto cleanup;
            }
        } else {
2881 2882 2883
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Refusing to undefine while domain managed "
                             "save image exists"));
2884 2885 2886 2887
            goto cleanup;
        }
    }

2888
    if (virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm) < 0)
J
Jim Fehlig 已提交
2889 2890
        goto cleanup;

2891
    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_UNDEFINED,
2892 2893
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);

2894 2895 2896
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
2897
        virDomainObjListRemove(driver->domains, vm);
2898 2899 2900
        vm = NULL;
    }

J
Jim Fehlig 已提交
2901 2902
    ret = 0;

2903
 cleanup:
2904
    VIR_FREE(name);
J
Jim Fehlig 已提交
2905
    if (vm)
2906
        virObjectUnlock(vm);
2907 2908
    if (event)
        libxlDomainEventQueue(driver, event);
2909
    virObjectUnref(cfg);
J
Jim Fehlig 已提交
2910 2911 2912
    return ret;
}

2913 2914 2915 2916 2917 2918
static int
libxlDomainUndefine(virDomainPtr dom)
{
    return libxlDomainUndefineFlags(dom, 0);
}

2919
static int
J
Jim Fehlig 已提交
2920
libxlDomainChangeEjectableMedia(virDomainObjPtr vm, virDomainDiskDefPtr disk)
2921
{
J
Jim Fehlig 已提交
2922
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(libxl_driver);
2923 2924
    virDomainDiskDefPtr origdisk = NULL;
    libxl_device_disk x_disk;
2925
    size_t i;
2926 2927
    int ret = -1;

2928
    for (i = 0; i < vm->def->ndisks; i++) {
2929 2930 2931 2932 2933 2934 2935 2936
        if (vm->def->disks[i]->bus == disk->bus &&
            STREQ(vm->def->disks[i]->dst, disk->dst)) {
            origdisk = vm->def->disks[i];
            break;
        }
    }

    if (!origdisk) {
2937 2938 2939
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No device with bus '%s' and target '%s'"),
                       virDomainDiskBusTypeToString(disk->bus), disk->dst);
2940 2941 2942 2943
        goto cleanup;
    }

    if (origdisk->device != VIR_DOMAIN_DISK_DEVICE_CDROM) {
2944 2945 2946
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Removable media not supported for %s device"),
                       virDomainDiskDeviceTypeToString(disk->device));
2947 2948 2949
        return -1;
    }

J
Jim Fehlig 已提交
2950
    if (libxlMakeDisk(disk, &x_disk) < 0)
2951 2952
        goto cleanup;

J
Jim Fehlig 已提交
2953
    if ((ret = libxl_cdrom_insert(cfg->ctx, vm->def->id, &x_disk, NULL)) < 0) {
2954 2955 2956
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to change media for disk '%s'"),
                       disk->dst);
2957 2958 2959
        goto cleanup;
    }

2960 2961 2962
    if (virDomainDiskSetSource(origdisk, virDomainDiskGetSource(disk)) < 0)
        goto cleanup;
    virDomainDiskSetType(origdisk, virDomainDiskGetType(disk));
2963 2964 2965 2966 2967

    virDomainDiskDefFree(disk);

    ret = 0;

2968
 cleanup:
J
Jim Fehlig 已提交
2969
    virObjectUnref(cfg);
2970 2971 2972 2973
    return ret;
}

static int
J
Jim Fehlig 已提交
2974
libxlDomainAttachDeviceDiskLive(virDomainObjPtr vm, virDomainDeviceDefPtr dev)
2975
{
J
Jim Fehlig 已提交
2976
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(libxl_driver);
2977 2978 2979 2980 2981 2982
    virDomainDiskDefPtr l_disk = dev->data.disk;
    libxl_device_disk x_disk;
    int ret = -1;

    switch (l_disk->device)  {
        case VIR_DOMAIN_DISK_DEVICE_CDROM:
J
Jim Fehlig 已提交
2983
            ret = libxlDomainChangeEjectableMedia(vm, l_disk);
2984 2985 2986
            break;
        case VIR_DOMAIN_DISK_DEVICE_DISK:
            if (l_disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {
2987
                if (virDomainDiskIndexByName(vm->def, l_disk->dst, true) >= 0) {
2988 2989
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("target %s already exists"), l_disk->dst);
2990 2991 2992
                    goto cleanup;
                }

2993
                if (!virDomainDiskGetSource(l_disk)) {
2994 2995
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   "%s", _("disk source path is missing"));
2996 2997 2998
                    goto cleanup;
                }

2999
                if (VIR_REALLOC_N(vm->def->disks, vm->def->ndisks+1) < 0)
3000 3001
                    goto cleanup;

J
Jim Fehlig 已提交
3002
                if (libxlMakeDisk(l_disk, &x_disk) < 0)
3003 3004
                    goto cleanup;

3005 3006 3007 3008 3009
                if (virDomainLockDiskAttach(libxl_driver->lockManager,
                                            "xen:///system",
                                            vm, l_disk) < 0)
                    goto cleanup;

J
Jim Fehlig 已提交
3010
                if ((ret = libxl_device_disk_add(cfg->ctx, vm->def->id,
J
Jim Fehlig 已提交
3011
                                                &x_disk, NULL)) < 0) {
3012 3013 3014
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("libxenlight failed to attach disk '%s'"),
                                   l_disk->dst);
3015 3016 3017 3018 3019
                    if (virDomainLockDiskDetach(libxl_driver->lockManager,
                                                vm, l_disk) < 0) {
                        VIR_WARN("Unable to release lock on %s",
                                 virDomainDiskGetSource(l_disk));
                    }
3020 3021 3022
                    goto cleanup;
                }

3023
                libxlUpdateDiskDef(l_disk, &x_disk);
3024 3025 3026
                virDomainDiskInsertPreAlloced(vm->def, l_disk);

            } else {
3027 3028 3029
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("disk bus '%s' cannot be hotplugged."),
                               virDomainDiskBusTypeToString(l_disk->bus));
3030 3031 3032
            }
            break;
        default:
3033 3034 3035
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("disk device type '%s' cannot be hotplugged"),
                           virDomainDiskDeviceTypeToString(l_disk->device));
3036 3037 3038
            break;
    }

3039
 cleanup:
J
Jim Fehlig 已提交
3040
    virObjectUnref(cfg);
3041 3042 3043
    return ret;
}

3044 3045 3046 3047 3048
static int
libxlDomainAttachHostPCIDevice(libxlDriverPrivatePtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
J
Jim Fehlig 已提交
3049
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3050
    libxl_device_pci pcidev;
3051 3052
    virDomainHostdevDefPtr found;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
3053
    virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;
J
Jim Fehlig 已提交
3054
    int ret = -1;
3055

3056 3057
    libxl_device_pci_init(&pcidev);

3058 3059 3060
    if (virDomainHostdevFind(vm->def, hostdev, &found) >= 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("target pci device %.4x:%.2x:%.2x.%.1x already exists"),
3061 3062
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
J
Jim Fehlig 已提交
3063
        goto cleanup;
3064 3065 3066
    }

    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
J
Jim Fehlig 已提交
3067
        goto cleanup;
3068 3069 3070 3071

    if (virHostdevPreparePCIDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                    vm->def->name, vm->def->uuid,
                                    &hostdev, 1, 0) < 0)
J
Jim Fehlig 已提交
3072
        goto cleanup;
3073

3074
    if (libxlMakePCI(hostdev, &pcidev) < 0)
C
Chunyan Liu 已提交
3075
        goto error;
3076

J
Jim Fehlig 已提交
3077
    if (libxl_device_pci_add(cfg->ctx, vm->def->id, &pcidev, 0) < 0) {
3078 3079
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to attach pci device %.4x:%.2x:%.2x.%.1x"),
3080 3081
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
C
Chunyan Liu 已提交
3082
        goto error;
3083 3084 3085
    }

    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
J
Jim Fehlig 已提交
3086 3087
    ret = 0;
    goto cleanup;
3088

3089
 error:
3090 3091
    virHostdevReAttachPCIDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                 vm->def->name, &hostdev, 1, NULL);
J
Jim Fehlig 已提交
3092 3093 3094

 cleanup:
    virObjectUnref(cfg);
3095
    libxl_device_pci_dispose(&pcidev);
J
Jim Fehlig 已提交
3096
    return ret;
3097 3098
}

3099
#ifdef LIBXL_HAVE_PVUSB
3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153
static int
libxlDomainAttachControllerDevice(libxlDriverPrivatePtr driver,
                                  virDomainObjPtr vm,
                                  virDomainControllerDefPtr controller)
{
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    const char *type = virDomainControllerTypeToString(controller->type);
    libxl_device_usbctrl usbctrl;
    int ret = -1;

    libxl_device_usbctrl_init(&usbctrl);

    if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_USB) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot plugged."),
                       type);
        goto cleanup;
    }

    if (controller->idx == -1)
        controller->idx = virDomainControllerFindUnusedIndex(vm->def,
                                                             controller->type);

    if (controller->opts.usbopts.ports == -1)
        controller->opts.usbopts.ports = 8;

    if (virDomainControllerFind(vm->def, controller->type, controller->idx) >= 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("target %s:%d already exists"),
                       type, controller->idx);
        goto cleanup;
    }

    if (VIR_REALLOC_N(vm->def->controllers, vm->def->ncontrollers + 1) < 0)
        goto cleanup;

    if (libxlMakeUSBController(controller, &usbctrl) < 0)
        goto cleanup;

    if (libxl_device_usbctrl_add(cfg->ctx, vm->def->id, &usbctrl, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxenlight failed to attach USB controller"));
        goto cleanup;
    }

    virDomainControllerInsertPreAlloced(vm->def, controller);
    ret = 0;

 cleanup:
    virObjectUnref(cfg);
    libxl_device_usbctrl_dispose(&usbctrl);
    return ret;
}

3154 3155 3156 3157 3158 3159 3160 3161 3162
static int
libxlDomainAttachHostUSBDevice(libxlDriverPrivatePtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    libxl_device_usbdev usbdev;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
    int ret = -1;
3163 3164
    size_t i;
    int ports = 0, usbdevs = 0;
3165 3166 3167 3168 3169 3170 3171

    libxl_device_usbdev_init(&usbdev);

    if (hostdev->mode != VIR_DOMAIN_HOSTDEV_MODE_SUBSYS ||
        hostdev->source.subsys.type != VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
        goto cleanup;

3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201
    /* search for available controller:port */
    for (i = 0; i < vm->def->ncontrollers; i++)
        ports += vm->def->controllers[i]->opts.usbopts.ports;

    for (i = 0; i < vm->def->nhostdevs; i++) {
        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB)
            usbdevs++;
    }

    if (ports <= usbdevs) {
        /* no free ports, we will create a new usb controller */
        virDomainControllerDefPtr controller;

        if (!(controller = virDomainControllerDefNew(VIR_DOMAIN_CONTROLLER_TYPE_USB)))
            goto cleanup;

        controller->model = VIR_DOMAIN_CONTROLLER_MODEL_USB_QUSB2;
        controller->idx = -1;
        controller->opts.usbopts.ports = 8;

        if (libxlDomainAttachControllerDevice(driver, vm, controller) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("No available USB controller and port, and "
                             "failed to attach a new one"));
            virDomainControllerDefFree(controller);
            goto cleanup;
        }
    }

3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234
    if (VIR_REALLOC_N(vm->def->hostdevs, vm->def->nhostdevs + 1) < 0)
        goto cleanup;

    if (virHostdevPrepareUSBDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                    vm->def->name, &hostdev, 1, 0) < 0)
        goto cleanup;

    if (libxlMakeUSB(hostdev, &usbdev) < 0)
        goto reattach;

    if (libxl_device_usbdev_add(cfg->ctx, vm->def->id, &usbdev, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to attach usb device Busnum:%3x, Devnum:%3x"),
                       hostdev->source.subsys.u.usb.bus,
                       hostdev->source.subsys.u.usb.device);
        goto reattach;
    }

    vm->def->hostdevs[vm->def->nhostdevs++] = hostdev;
    ret = 0;
    goto cleanup;

 reattach:
    virHostdevReAttachUSBDevices(hostdev_mgr, LIBXL_DRIVER_NAME,
                                 vm->def->name, &hostdev, 1);

 cleanup:
    virObjectUnref(cfg);
    libxl_device_usbdev_dispose(&usbdev);
    return ret;
}
#endif

3235 3236 3237
static int
libxlDomainAttachHostDevice(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
3238
                            virDomainHostdevDefPtr hostdev)
3239 3240 3241 3242 3243 3244 3245 3246 3247 3248
{
    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:
J
Jim Fehlig 已提交
3249
        if (libxlDomainAttachHostPCIDevice(driver, vm, hostdev) < 0)
C
Chunyan Liu 已提交
3250
            return -1;
3251 3252
        break;

3253 3254 3255 3256 3257 3258 3259
#ifdef LIBXL_HAVE_PVUSB
    case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
        if (libxlDomainAttachHostUSBDevice(driver, vm, hostdev) < 0)
            return -1;
        break;
#endif

3260 3261 3262 3263
    default:
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("hostdev subsys type '%s' not supported"),
                       virDomainHostdevSubsysTypeToString(hostdev->source.subsys.type));
C
Chunyan Liu 已提交
3264
        return -1;
3265 3266 3267 3268 3269
    }

    return 0;
}

3270
static int
J
Jim Fehlig 已提交
3271
libxlDomainDetachDeviceDiskLive(virDomainObjPtr vm, virDomainDeviceDefPtr dev)
3272
{
J
Jim Fehlig 已提交
3273
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(libxl_driver);
3274 3275
    virDomainDiskDefPtr l_disk = NULL;
    libxl_device_disk x_disk;
3276
    int idx;
3277 3278 3279 3280 3281 3282
    int ret = -1;

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

3283 3284 3285
                if ((idx = virDomainDiskIndexByName(vm->def,
                                                    dev->data.disk->dst,
                                                    false)) < 0) {
3286 3287
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("disk %s not found"), dev->data.disk->dst);
3288 3289 3290
                    goto cleanup;
                }

3291
                l_disk = vm->def->disks[idx];
3292

J
Jim Fehlig 已提交
3293
                if (libxlMakeDisk(l_disk, &x_disk) < 0)
3294 3295
                    goto cleanup;

J
Jim Fehlig 已提交
3296
                if ((ret = libxl_device_disk_remove(cfg->ctx, vm->def->id,
J
Jim Fehlig 已提交
3297
                                                    &x_disk, NULL)) < 0) {
3298 3299 3300
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("libxenlight failed to detach disk '%s'"),
                                   l_disk->dst);
3301 3302 3303
                    goto cleanup;
                }

3304 3305 3306 3307 3308
                if (virDomainLockDiskDetach(libxl_driver->lockManager,
                                            vm, l_disk) < 0)
                    VIR_WARN("Unable to release lock on %s",
                             virDomainDiskGetSource(l_disk));

3309
                virDomainDiskRemove(vm->def, idx);
3310 3311 3312
                virDomainDiskDefFree(l_disk);

            } else {
3313 3314 3315
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("disk bus '%s' cannot be hot unplugged."),
                               virDomainDiskBusTypeToString(dev->data.disk->bus));
3316 3317 3318
            }
            break;
        default:
3319 3320 3321
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot hot unplugged"),
                           virDomainDiskDeviceTypeToString(dev->data.disk->device));
3322 3323 3324
            break;
    }

3325
 cleanup:
J
Jim Fehlig 已提交
3326
    virObjectUnref(cfg);
3327 3328 3329
    return ret;
}

3330 3331 3332 3333 3334
static int
libxlDomainAttachNetDevice(libxlDriverPrivatePtr driver,
                           virDomainObjPtr vm,
                           virDomainNetDefPtr net)
{
J
Jim Fehlig 已提交
3335
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3336
    virDomainNetType actualType;
3337 3338
    libxl_device_nic nic;
    int ret = -1;
3339
    char mac[VIR_MAC_STRING_BUFLEN];
3340

3341 3342
    libxl_device_nic_init(&nic);

3343 3344
    /* preallocate new slot for device */
    if (VIR_REALLOC_N(vm->def->nets, vm->def->nnets + 1) < 0)
3345
        goto cleanup;
3346 3347 3348 3349 3350 3351

    /* 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)
3352
        goto cleanup;
3353 3354 3355

    actualType = virDomainNetGetActualType(net);

3356 3357 3358 3359
    if (virDomainHasNet(vm->def, net)) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("network device with mac %s already exists"),
                       virMacAddrFormat(&net->mac, mac));
3360
        goto cleanup;
3361 3362
    }

3363
    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374
        virDomainHostdevDefPtr hostdev = virDomainNetGetActualHostdev(net);
        virDomainHostdevSubsysPCIPtr pcisrc = &hostdev->source.subsys.u.pci;

        /* For those just allocated from a network pool whose backend is
         * still VIR_DOMAIN_HOSTDEV_PCI_BACKEND_DEFAULT, we need to set
         * backend correctly.
         */
        if (hostdev->mode == VIR_DOMAIN_HOSTDEV_MODE_SUBSYS &&
            hostdev->source.subsys.type == VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_PCI)
            pcisrc->backend = VIR_DOMAIN_HOSTDEV_PCI_BACKEND_XEN;

3375 3376 3377
        /* 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
3378
         * the nets list if successful.
3379
         */
3380
        ret = libxlDomainAttachHostDevice(driver, vm, hostdev);
3381
        goto cleanup;
3382 3383
    }

3384
    if (libxlMakeNic(vm->def, net, &nic, true) < 0)
3385 3386
        goto cleanup;

J
Jim Fehlig 已提交
3387
    if (libxl_device_nic_add(cfg->ctx, vm->def->id, &nic, 0)) {
3388 3389 3390 3391 3392 3393 3394 3395 3396
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxenlight failed to attach network device"));
        goto cleanup;
    }

    ret = 0;

 cleanup:
    libxl_device_nic_dispose(&nic);
3397 3398 3399
    if (!ret) {
        vm->def->nets[vm->def->nnets++] = net;
    } else {
3400 3401 3402
        virDomainNetRemoveHostdev(vm->def, net);
        networkReleaseActualDevice(vm->def, net);
    }
J
Jim Fehlig 已提交
3403
    virObjectUnref(cfg);
3404 3405 3406
    return ret;
}

3407
static int
3408 3409
libxlDomainAttachDeviceLive(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
3410 3411 3412 3413 3414 3415
                            virDomainDeviceDefPtr dev)
{
    int ret = -1;

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
J
Jim Fehlig 已提交
3416
            ret = libxlDomainAttachDeviceDiskLive(vm, dev);
3417 3418 3419 3420
            if (!ret)
                dev->data.disk = NULL;
            break;

3421
#ifdef LIBXL_HAVE_PVUSB
3422 3423 3424 3425 3426
        case VIR_DOMAIN_DEVICE_CONTROLLER:
            ret = libxlDomainAttachControllerDevice(driver, vm, dev->data.controller);
            if (!ret)
                dev->data.controller = NULL;
            break;
3427
#endif
3428

3429
        case VIR_DOMAIN_DEVICE_NET:
J
Jim Fehlig 已提交
3430
            ret = libxlDomainAttachNetDevice(driver, vm,
3431 3432 3433 3434 3435
                                             dev->data.net);
            if (!ret)
                dev->data.net = NULL;
            break;

3436
        case VIR_DOMAIN_DEVICE_HOSTDEV:
J
Jim Fehlig 已提交
3437
            ret = libxlDomainAttachHostDevice(driver, vm,
3438
                                              dev->data.hostdev);
3439 3440 3441 3442
            if (!ret)
                dev->data.hostdev = NULL;
            break;

3443
        default:
3444 3445 3446
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot be attached"),
                           virDomainDeviceTypeToString(dev->type));
3447 3448 3449 3450 3451 3452 3453 3454 3455 3456
            break;
    }

    return ret;
}

static int
libxlDomainAttachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
{
    virDomainDiskDefPtr disk;
3457
    virDomainNetDefPtr net;
3458
    virDomainHostdevDefPtr hostdev;
3459
    virDomainControllerDefPtr controller;
3460
    virDomainHostdevDefPtr found;
3461
    char mac[VIR_MAC_STRING_BUFLEN];
3462 3463 3464 3465

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
            disk = dev->data.disk;
3466
            if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
3467 3468
                virReportError(VIR_ERR_INVALID_ARG,
                               _("target %s already exists."), disk->dst);
3469 3470
                return -1;
            }
3471
            if (virDomainDiskInsert(vmdef, disk))
3472 3473 3474 3475
                return -1;
            /* vmdef has the pointer. Generic codes for vmdef will do all jobs */
            dev->data.disk = NULL;
            break;
3476

3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491
        case VIR_DOMAIN_DEVICE_CONTROLLER:
            controller = dev->data.controller;
            if (controller->idx != -1 &&
                virDomainControllerFind(vmdef, controller->type,
                                        controller->idx) >= 0) {
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("Target already exists"));
                return -1;
            }

            if (virDomainControllerInsert(vmdef, controller) < 0)
                return -1;
            dev->data.controller = NULL;
            break;

3492 3493
        case VIR_DOMAIN_DEVICE_NET:
            net = dev->data.net;
3494 3495 3496 3497 3498 3499
            if (virDomainHasNet(vmdef, net)) {
                virReportError(VIR_ERR_INVALID_ARG,
                               _("network device with mac %s already exists"),
                               virMacAddrFormat(&net->mac, mac));
                return -1;
            }
3500 3501 3502 3503 3504
            if (virDomainNetInsert(vmdef, net))
                return -1;
            dev->data.net = NULL;
            break;

3505 3506 3507
        case VIR_DOMAIN_DEVICE_HOSTDEV:
            hostdev = dev->data.hostdev;

3508 3509 3510 3511 3512 3513
            switch (hostdev->source.subsys.type) {
            case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_SCSI:
#ifndef LIBXL_HAVE_PVUSB
            case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
#endif
            case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_LAST:
3514
                return -1;
3515
            }
3516 3517

            if (virDomainHostdevFind(vmdef, hostdev, &found) >= 0) {
3518 3519
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("device is already in the domain configuration"));
3520 3521 3522
                return -1;
            }

3523 3524
            if (virDomainHostdevInsert(vmdef, hostdev) < 0)
                return -1;
3525
            dev->data.hostdev = NULL;
3526
            break;
3527 3528

        default:
3529 3530
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("persistent attach of device is not supported"));
3531 3532 3533 3534 3535 3536
            return -1;
    }
    return 0;
}

static int
3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569
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,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
J
Jim Fehlig 已提交
3570
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3571
    virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
3572
    virDomainHostdevSubsysPCIPtr pcisrc = &subsys->u.pci;
3573 3574 3575 3576
    libxl_device_pci pcidev;
    virDomainHostdevDefPtr detach;
    int idx;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
J
Jim Fehlig 已提交
3577
    int ret = -1;
3578

3579 3580
    libxl_device_pci_init(&pcidev);

3581 3582 3583 3584
    idx = virDomainHostdevFind(vm->def, hostdev, &detach);
    if (idx < 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("host pci device %.4x:%.2x:%.2x.%.1x not found"),
3585 3586
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
J
Jim Fehlig 已提交
3587
        goto cleanup;
3588 3589 3590 3591 3592
    }

    if (libxlIsMultiFunctionDevice(vm->def, detach->info)) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("cannot hot unplug multifunction PCI device: %.4x:%.2x:%.2x.%.1x"),
3593 3594
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
C
Chunyan Liu 已提交
3595
        goto error;
3596 3597 3598
    }


3599
    if (libxlMakePCI(detach, &pcidev) < 0)
C
Chunyan Liu 已提交
3600
        goto error;
3601

J
Jim Fehlig 已提交
3602
    if (libxl_device_pci_remove(cfg->ctx, vm->def->id, &pcidev, 0) < 0) {
3603 3604 3605
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to detach pci device\
                          %.4x:%.2x:%.2x.%.1x"),
3606 3607
                       pcisrc->addr.domain, pcisrc->addr.bus,
                       pcisrc->addr.slot, pcisrc->addr.function);
C
Chunyan Liu 已提交
3608
        goto error;
3609 3610 3611 3612 3613 3614 3615 3616
    }


    virDomainHostdevRemove(vm->def, idx);

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

J
Jim Fehlig 已提交
3617
    ret = 0;
3618

3619
 error:
3620
    virDomainHostdevDefFree(detach);
J
Jim Fehlig 已提交
3621 3622 3623

 cleanup:
    virObjectUnref(cfg);
3624
    libxl_device_pci_dispose(&pcidev);
J
Jim Fehlig 已提交
3625
    return ret;
3626 3627
}

3628
#ifdef LIBXL_HAVE_PVUSB
3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 3676 3677 3678 3679
static int
libxlDomainDetachControllerDevice(libxlDriverPrivatePtr driver,
                                  virDomainObjPtr vm,
                                  virDomainDeviceDefPtr dev)
{
    int idx, ret = -1;
    virDomainControllerDefPtr detach = NULL;
    virDomainControllerDefPtr controller = dev->data.controller;
    const char *type = virDomainControllerTypeToString(controller->type);
    libxl_device_usbctrl usbctrl;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);

    libxl_device_usbctrl_init(&usbctrl);

    if (controller->type != VIR_DOMAIN_CONTROLLER_TYPE_USB) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot plugged."),
                       type);
        goto cleanup;
    }

    if ((idx = virDomainControllerFind(vm->def,
                                       controller->type,
                                       controller->idx)) < 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("controller %s:%d not found"),
                       type, controller->idx);
        goto cleanup;
    }

    detach = vm->def->controllers[idx];

    if (libxlMakeUSBController(controller, &usbctrl) < 0)
        goto cleanup;

    if (libxl_device_usbctrl_remove(cfg->ctx, vm->def->id, &usbctrl, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxenlight failed to detach USB controller"));
        goto cleanup;
    }

    virDomainControllerRemove(vm->def, idx);
    ret = 0;

 cleanup:
    virDomainControllerDefFree(detach);
    virObjectUnref(cfg);
    libxl_device_usbctrl_dispose(&usbctrl);
    return ret;
}

3680 3681 3682 3683 3684 3685 3686 3687 3688 3689 3690 3691 3692 3693 3694 3695 3696 3697 3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748
static int
libxlDomainDetachHostUSBDevice(libxlDriverPrivatePtr driver,
                               virDomainObjPtr vm,
                               virDomainHostdevDefPtr hostdev)
{
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
    virDomainHostdevSubsysUSBPtr usbsrc = &subsys->u.usb;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
    libxl_device_usbdev usbdev;
    libxl_device_usbdev *usbdevs = NULL;
    int num = 0;
    virDomainHostdevDefPtr detach;
    int idx;
    size_t i;
    bool found = false;
    int ret = -1;

    libxl_device_usbdev_init(&usbdev);

    idx = virDomainHostdevFind(vm->def, hostdev, &detach);
    if (idx < 0) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("host USB device Busnum: %3x, Devnum: %3x not found"),
                       usbsrc->bus, usbsrc->device);
        goto cleanup;
    }

    usbdevs = libxl_device_usbdev_list(cfg->ctx, vm->def->id, &num);
    for (i = 0; i < num; i++) {
        if (usbdevs[i].u.hostdev.hostbus == usbsrc->bus &&
            usbdevs[i].u.hostdev.hostaddr == usbsrc->device) {
            libxl_device_usbdev_copy(cfg->ctx, &usbdev, &usbdevs[i]);
            found = true;
            break;
        }
    }
    libxl_device_usbdev_list_free(usbdevs, num);

    if (!found) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("host USB device Busnum: %3x, Devnum: %3x not found"),
                       usbsrc->bus, usbsrc->device);
        goto cleanup;
    }

    if (libxl_device_usbdev_remove(cfg->ctx, vm->def->id, &usbdev, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxenlight failed to detach USB device\
                          Busnum: %3x, Devnum: %3x"),
                       usbsrc->bus, usbsrc->device);
        goto cleanup;
    }

    virDomainHostdevRemove(vm->def, idx);

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

    ret = 0;

 cleanup:
    virDomainHostdevDefFree(detach);
    virObjectUnref(cfg);
    libxl_device_usbdev_dispose(&usbdev);
    return ret;
}
#endif

3749 3750 3751
static int
libxlDomainDetachHostDevice(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
3752
                            virDomainHostdevDefPtr hostdev)
3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763 3764
{
    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:
J
Jim Fehlig 已提交
3765
            return libxlDomainDetachHostPCIDevice(driver, vm, hostdev);
3766

3767 3768 3769 3770 3771
#ifdef LIBXL_HAVE_PVUSB
        case VIR_DOMAIN_HOSTDEV_SUBSYS_TYPE_USB:
            return libxlDomainDetachHostUSBDevice(driver, vm, hostdev);
#endif

3772 3773 3774 3775 3776 3777 3778 3779 3780
        default:
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unexpected hostdev type %d"), subsys->type);
            break;
    }

    return -1;
}

3781 3782 3783 3784 3785
static int
libxlDomainDetachNetDevice(libxlDriverPrivatePtr driver,
                           virDomainObjPtr vm,
                           virDomainNetDefPtr net)
{
J
Jim Fehlig 已提交
3786
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3787 3788 3789 3790 3791 3792
    int detachidx;
    virDomainNetDefPtr detach = NULL;
    libxl_device_nic nic;
    char mac[VIR_MAC_STRING_BUFLEN];
    int ret = -1;

3793 3794
    libxl_device_nic_init(&nic);

3795
    if ((detachidx = virDomainNetFindIdx(vm->def, net)) < 0)
3796
        goto cleanup;
3797 3798 3799 3800 3801 3802 3803

    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.
         */
J
Jim Fehlig 已提交
3804
        ret = libxlDomainDetachHostDevice(driver, vm,
3805
                                          virDomainNetGetActualHostdev(detach));
3806
        goto cleanup;
3807 3808
    }

J
Jim Fehlig 已提交
3809
    if (libxl_mac_to_device_nic(cfg->ctx, vm->def->id,
3810 3811 3812
                                virMacAddrFormat(&detach->mac, mac), &nic))
        goto cleanup;

J
Jim Fehlig 已提交
3813
    if (libxl_device_nic_remove(cfg->ctx, vm->def->id, &nic, 0)) {
3814 3815 3816 3817 3818 3819 3820 3821 3822
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxenlight failed to detach network device"));
        goto cleanup;
    }

    ret = 0;

 cleanup:
    libxl_device_nic_dispose(&nic);
J
Jim Fehlig 已提交
3823 3824 3825 3826
    if (!ret) {
        networkReleaseActualDevice(vm->def, detach);
        virDomainNetRemove(vm->def, detachidx);
    }
J
Jim Fehlig 已提交
3827
    virObjectUnref(cfg);
3828 3829 3830
    return ret;
}

3831 3832 3833
static int
libxlDomainDetachDeviceLive(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
3834 3835
                            virDomainDeviceDefPtr dev)
{
3836
    virDomainHostdevDefPtr hostdev;
3837 3838 3839 3840
    int ret = -1;

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
J
Jim Fehlig 已提交
3841
            ret = libxlDomainDetachDeviceDiskLive(vm, dev);
3842 3843
            break;

3844
#ifdef LIBXL_HAVE_PVUSB
3845 3846 3847
        case VIR_DOMAIN_DEVICE_CONTROLLER:
            ret = libxlDomainDetachControllerDevice(driver, vm, dev);
            break;
3848
#endif
3849

3850
        case VIR_DOMAIN_DEVICE_NET:
J
Jim Fehlig 已提交
3851
            ret = libxlDomainDetachNetDevice(driver, vm,
3852 3853 3854
                                             dev->data.net);
            break;

3855
        case VIR_DOMAIN_DEVICE_HOSTDEV:
3856 3857 3858 3859 3860 3861 3862 3863 3864 3865
            hostdev = dev->data.hostdev;

            /* If this is a network hostdev, we need to use the higher-level
             * detach function so that mac address / virtualport are reset
             */
            if (hostdev->parent.type == VIR_DOMAIN_DEVICE_NET)
                ret = libxlDomainDetachNetDevice(driver, vm,
                                                 hostdev->parent.data.net);
            else
                ret = libxlDomainDetachHostDevice(driver, vm, hostdev);
3866 3867
            break;

3868
        default:
3869 3870 3871
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot be detached"),
                           virDomainDeviceTypeToString(dev->type));
3872 3873 3874 3875 3876 3877
            break;
    }

    return ret;
}

3878

3879 3880 3881
static int
libxlDomainDetachDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
{
3882
    virDomainDiskDefPtr disk, detach;
3883
    virDomainHostdevDefPtr hostdev, det_hostdev;
3884
    virDomainControllerDefPtr cont, det_cont;
3885
    virDomainNetDefPtr net;
3886
    int idx;
3887 3888 3889 3890

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
            disk = dev->data.disk;
3891
            if (!(detach = virDomainDiskRemoveByName(vmdef, disk->dst))) {
3892 3893
                virReportError(VIR_ERR_INVALID_ARG,
                               _("no target device %s"), disk->dst);
3894
                return -1;
3895
            }
3896
            virDomainDiskDefFree(detach);
3897
            break;
3898

3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910
        case VIR_DOMAIN_DEVICE_CONTROLLER:
            cont = dev->data.controller;
            if ((idx = virDomainControllerFind(vmdef, cont->type,
                                               cont->idx)) < 0) {
                virReportError(VIR_ERR_INVALID_ARG, "%s",
                               _("device not present in domain configuration"));
                return -1;
            }
            det_cont = virDomainControllerRemove(vmdef, idx);
            virDomainControllerDefFree(det_cont);
            break;

3911 3912 3913 3914 3915 3916 3917 3918 3919
        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;

3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931
        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;
        }

3932
        default:
3933 3934
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("persistent detach of device is not supported"));
3935
            return -1;
3936 3937
    }

3938
    return 0;
3939 3940 3941
}

static int
J
Jim Fehlig 已提交
3942
libxlDomainUpdateDeviceLive(virDomainObjPtr vm, virDomainDeviceDefPtr dev)
3943 3944 3945 3946 3947 3948 3949 3950 3951
{
    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:
J
Jim Fehlig 已提交
3952
                    ret = libxlDomainChangeEjectableMedia(vm, disk);
3953 3954 3955 3956
                    if (ret == 0)
                        dev->data.disk = NULL;
                    break;
                default:
3957 3958 3959
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("disk bus '%s' cannot be updated."),
                                   virDomainDiskBusTypeToString(disk->bus));
3960 3961 3962 3963
                    break;
            }
            break;
        default:
3964 3965 3966
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot be updated"),
                           virDomainDeviceTypeToString(dev->type));
3967 3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982
            break;
    }

    return ret;
}

static int
libxlDomainUpdateDeviceConfig(virDomainDefPtr vmdef, virDomainDeviceDefPtr dev)
{
    virDomainDiskDefPtr orig;
    virDomainDiskDefPtr disk;
    int ret = -1;

    switch (dev->type) {
        case VIR_DOMAIN_DEVICE_DISK:
            disk = dev->data.disk;
3983
            if (!(orig = virDomainDiskByName(vmdef, disk->dst, false))) {
3984 3985
                virReportError(VIR_ERR_INVALID_ARG,
                               _("target %s doesn't exist."), disk->dst);
3986 3987 3988
                goto cleanup;
            }
            if (!(orig->device == VIR_DOMAIN_DISK_DEVICE_CDROM)) {
3989 3990
                virReportError(VIR_ERR_INVALID_ARG, "%s",
                               _("this disk doesn't support update"));
3991 3992 3993
                goto cleanup;
            }

3994 3995 3996 3997 3998 3999
            if (virDomainDiskSetSource(orig, virDomainDiskGetSource(disk)) < 0)
                goto cleanup;
            virDomainDiskSetType(orig, virDomainDiskGetType(disk));
            virDomainDiskSetFormat(orig, virDomainDiskGetFormat(disk));
            if (virDomainDiskSetDriver(orig, virDomainDiskGetDriver(disk)) < 0)
                goto cleanup;
4000 4001
            break;
        default:
4002 4003
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("persistent update of device is not supported"));
4004 4005 4006 4007 4008
            goto cleanup;
    }

    ret = 0;

4009
 cleanup:
4010 4011 4012 4013 4014
    return ret;
}


static int
4015 4016
libxlDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                             unsigned int flags)
4017 4018
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4019
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4020 4021 4022 4023 4024 4025 4026 4027
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

J
Jim Fehlig 已提交
4028
    if (!(vm = libxlDomObjFromDomain(dom)))
4029 4030
        goto cleanup;

4031 4032 4033
    if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4034 4035 4036
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

4037 4038
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;
4039 4040

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
4041
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
4042
                                            cfg->caps, driver->xmlopt,
4043
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
4044
            goto endjob;
4045 4046

        /* Make a copy for updated domain. */
4047
        if (!(vmdef = virDomainObjCopyPersistentDef(vm, cfg->caps,
4048
                                                    driver->xmlopt)))
4049
            goto endjob;
4050

4051
        if (libxlDomainAttachDeviceConfig(vmdef, dev) < 0)
4052
            goto endjob;
4053
    }
4054 4055 4056 4057

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

J
Jim Fehlig 已提交
4063
        if (libxlDomainAttachDeviceLive(driver, vm, dev) < 0)
4064
            goto endjob;
4065

4066 4067 4068 4069
        /*
         * update domain status forcibly because the domain status may be
         * changed even if we attach the device failed.
         */
4070
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
4071
            goto endjob;
4072 4073
    }

4074 4075
    ret = 0;

4076
    /* Finally, if no error until here, we can save config. */
4077
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
4078
        ret = virDomainSaveConfig(cfg->configDir, cfg->caps, vmdef);
4079
        if (!ret) {
4080
            virDomainObjAssignDef(vm, vmdef, false, NULL);
4081 4082 4083 4084
            vmdef = NULL;
        }
    }

4085
 endjob:
W
Wang Yufei 已提交
4086
    libxlDomainObjEndJob(driver, vm);
4087

4088
 cleanup:
4089 4090
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
W
Wang Yufei 已提交
4091
    virDomainObjEndAPI(&vm);
4092
    virObjectUnref(cfg);
4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106
    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)
{
4107
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4108
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4109 4110 4111 4112 4113 4114 4115 4116
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

J
Jim Fehlig 已提交
4117
    if (!(vm = libxlDomObjFromDomain(dom)))
4118 4119
        goto cleanup;

4120 4121 4122
    if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4123 4124 4125
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

4126 4127
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto endjob;
4128 4129 4130

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
4131
                                            cfg->caps, driver->xmlopt,
4132 4133
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                            VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
4134
            goto endjob;
4135 4136

        /* Make a copy for updated domain. */
4137
        if (!(vmdef = virDomainObjCopyPersistentDef(vm, cfg->caps,
4138
                                                    driver->xmlopt)))
4139
            goto endjob;
4140

4141
        if (libxlDomainDetachDeviceConfig(vmdef, dev) < 0)
4142
            goto endjob;
4143 4144 4145 4146 4147 4148
    }

    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,
4149
                                            cfg->caps, driver->xmlopt,
4150 4151
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE |
                                            VIR_DOMAIN_DEF_PARSE_SKIP_VALIDATE)))
4152
            goto endjob;
4153

J
Jim Fehlig 已提交
4154
        if (libxlDomainDetachDeviceLive(driver, vm, dev) < 0)
4155
            goto endjob;
4156 4157 4158 4159 4160

        /*
         * update domain status forcibly because the domain status may be
         * changed even if we attach the device failed.
         */
4161
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
4162
            goto endjob;
4163 4164
    }

4165 4166
    ret = 0;

4167
    /* Finally, if no error until here, we can save config. */
4168
    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
4169
        ret = virDomainSaveConfig(cfg->configDir, cfg->caps, vmdef);
4170 4171 4172 4173 4174 4175
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

4176
 endjob:
W
Wang Yufei 已提交
4177
    libxlDomainObjEndJob(driver, vm);
4178

4179
 cleanup:
4180 4181
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
W
Wang Yufei 已提交
4182
    virDomainObjEndAPI(&vm);
4183
    virObjectUnref(cfg);
4184
    return ret;
4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197
}

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)
{
4198
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4199
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4200 4201 4202 4203 4204 4205 4206 4207
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_DEVICE_MODIFY_LIVE |
                  VIR_DOMAIN_DEVICE_MODIFY_CONFIG, -1);

J
Jim Fehlig 已提交
4208
    if (!(vm = libxlDomObjFromDomain(dom)))
4209 4210
        goto cleanup;

4211 4212 4213
    if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4214 4215
    if (virDomainObjUpdateModificationImpact(vm, &flags) < 0)
        goto cleanup;
4216 4217 4218

    if (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG) {
        if (!(dev = virDomainDeviceDefParse(xml, vm->def,
4219
                                            cfg->caps, driver->xmlopt,
4220
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
4221 4222 4223
            goto cleanup;

        /* Make a copy for updated domain. */
4224
        if (!(vmdef = virDomainObjCopyPersistentDef(vm, cfg->caps,
4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237
                                                    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,
4238
                                            cfg->caps, driver->xmlopt,
4239
                                            VIR_DOMAIN_DEF_PARSE_INACTIVE)))
4240 4241
            goto cleanup;

J
Jim Fehlig 已提交
4242
        if ((ret = libxlDomainUpdateDeviceLive(vm, dev)) < 0)
4243 4244 4245 4246 4247 4248
            goto cleanup;

        /*
         * update domain status forcibly because the domain status may be
         * changed even if we attach the device failed.
         */
4249
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm, cfg->caps) < 0)
4250 4251 4252 4253 4254
            ret = -1;
    }

    /* Finally, if no error until here, we can save config. */
    if (!ret && (flags & VIR_DOMAIN_DEVICE_MODIFY_CONFIG)) {
4255
        ret = virDomainSaveConfig(cfg->configDir, cfg->caps, vmdef);
4256 4257 4258 4259 4260 4261
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

4262
 cleanup:
4263 4264 4265 4266
    virDomainDefFree(vmdef);
    virDomainDeviceDefFree(dev);
    if (vm)
        virObjectUnlock(vm);
4267
    virObjectUnref(cfg);
4268
    return ret;
4269 4270
}

4271 4272 4273 4274 4275
static unsigned long long
libxlNodeGetFreeMemory(virConnectPtr conn)
{
    libxl_physinfo phy_info;
    libxlDriverPrivatePtr driver = conn->privateData;
4276 4277
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
    unsigned long long ret = 0;
4278

4279
    libxl_physinfo_init(&phy_info);
4280
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
4281
        goto cleanup;
4282

4283
    if (libxl_get_physinfo(cfg->ctx, &phy_info)) {
4284 4285
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxl_get_physinfo_info failed"));
4286
        goto cleanup;
4287 4288
    }

4289 4290
    ret = phy_info.free_pages * cfg->verInfo->pagesize;

4291
 cleanup:
4292
    libxl_physinfo_dispose(&phy_info);
4293 4294
    virObjectUnref(cfg);
    return ret;
4295 4296
}

4297 4298 4299 4300 4301 4302 4303 4304 4305 4306
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;
4307
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4308 4309

    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
4310
        goto cleanup;
4311

4312
    numa_info = libxl_get_numainfo(cfg->ctx, &nr_nodes);
4313
    if (numa_info == NULL || nr_nodes == 0) {
4314 4315 4316
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("libxl_get_numainfo failed"));
        goto cleanup;
4317 4318 4319
    }

    /* Check/sanitize the cell range */
4320
    if (startCell >= nr_nodes) {
4321 4322
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("start cell %d out of range (0-%d)"),
4323
                       startCell, nr_nodes - 1);
4324 4325 4326
        goto cleanup;
    }
    lastCell = startCell + maxCells - 1;
4327 4328
    if (lastCell >= nr_nodes)
        lastCell = nr_nodes - 1;
4329 4330 4331 4332 4333 4334 4335

    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;
    }
4336

4337 4338
    ret = numCells;

4339
 cleanup:
4340
    libxl_numainfo_list_free(numa_info, nr_nodes);
4341
    virObjectUnref(cfg);
4342 4343 4344
    return ret;
}

4345
static int
4346
libxlConnectDomainEventRegister(virConnectPtr conn,
4347 4348
                                virConnectDomainEventCallback callback,
                                void *opaque,
4349
                                virFreeCallback freecb)
4350 4351 4352
{
    libxlDriverPrivatePtr driver = conn->privateData;

4353 4354 4355
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        return -1;

4356 4357 4358 4359
    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        return -1;
4360

4361
    return 0;
4362 4363 4364 4365
}


static int
4366 4367
libxlConnectDomainEventDeregister(virConnectPtr conn,
                                  virConnectDomainEventCallback callback)
4368 4369 4370
{
    libxlDriverPrivatePtr driver = conn->privateData;

4371 4372 4373
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        return -1;

4374 4375 4376 4377
    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        return -1;
4378

4379
    return 0;
4380 4381
}

4382 4383 4384 4385 4386 4387
static int
libxlDomainGetAutostart(virDomainPtr dom, int *autostart)
{
    virDomainObjPtr vm;
    int ret = -1;

J
Jim Fehlig 已提交
4388
    if (!(vm = libxlDomObjFromDomain(dom)))
4389 4390
        goto cleanup;

4391 4392 4393
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4394 4395 4396
    *autostart = vm->autostart;
    ret = 0;

4397
 cleanup:
4398
    if (vm)
4399
        virObjectUnlock(vm);
4400 4401 4402 4403 4404 4405 4406
    return ret;
}

static int
libxlDomainSetAutostart(virDomainPtr dom, int autostart)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4407
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4408 4409 4410 4411
    virDomainObjPtr vm;
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;

J
Jim Fehlig 已提交
4412
    if (!(vm = libxlDomObjFromDomain(dom)))
4413 4414
        goto cleanup;

J
Jim Fehlig 已提交
4415 4416
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

4417 4418 4419
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4420 4421 4422
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

4423
    if (!vm->persistent) {
4424 4425
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient domain"));
4426
        goto endjob;
4427 4428 4429 4430 4431
    }

    autostart = (autostart != 0);

    if (vm->autostart != autostart) {
4432
        if (!(configFile = virDomainConfigFile(cfg->configDir, vm->def->name)))
4433
            goto endjob;
4434
        if (!(autostartLink = virDomainConfigFile(cfg->autostartDir, vm->def->name)))
4435
            goto endjob;
4436 4437

        if (autostart) {
4438
            if (virFileMakePath(cfg->autostartDir) < 0) {
4439
                virReportSystemError(errno,
4440
                                     _("cannot create autostart directory %s"),
4441
                                     cfg->autostartDir);
4442
                goto endjob;
4443 4444 4445 4446 4447 4448
            }

            if (symlink(configFile, autostartLink) < 0) {
                virReportSystemError(errno,
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
4449
                goto endjob;
4450 4451 4452 4453 4454 4455
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
                virReportSystemError(errno,
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
4456
                goto endjob;
4457 4458 4459 4460 4461 4462 4463
            }
        }

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

4464
 endjob:
W
Wang Yufei 已提交
4465
    libxlDomainObjEndJob(driver, vm);
4466

4467
 cleanup:
4468 4469
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
W
Wang Yufei 已提交
4470
    virDomainObjEndAPI(&vm);
4471
    virObjectUnref(cfg);
4472 4473 4474
    return ret;
}

4475 4476 4477
static char *
libxlDomainGetSchedulerType(virDomainPtr dom, int *nparams)
{
J
Jim Fehlig 已提交
4478 4479
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4480 4481
    virDomainObjPtr vm;
    char * ret = NULL;
4482
    const char *name = NULL;
J
Jim Fehlig 已提交
4483
    libxl_scheduler sched_id;
4484

J
Jim Fehlig 已提交
4485
    if (!(vm = libxlDomObjFromDomain(dom)))
4486 4487
        goto cleanup;

4488 4489 4490
    if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

J
Jim Fehlig 已提交
4496
    sched_id = libxl_get_scheduler(cfg->ctx);
4497

4498 4499
    if (nparams)
        *nparams = 0;
4500
    switch (sched_id) {
J
Jim Fehlig 已提交
4501
    case LIBXL_SCHEDULER_SEDF:
4502
        name = "sedf";
4503
        break;
J
Jim Fehlig 已提交
4504
    case LIBXL_SCHEDULER_CREDIT:
4505
        name = "credit";
4506 4507
        if (nparams)
            *nparams = XEN_SCHED_CREDIT_NPARAM;
4508
        break;
J
Jim Fehlig 已提交
4509
    case LIBXL_SCHEDULER_CREDIT2:
4510
        name = "credit2";
4511
        break;
J
Jim Fehlig 已提交
4512
    case LIBXL_SCHEDULER_ARINC653:
4513
        name = "arinc653";
4514 4515
        break;
    default:
J
Jim Fehlig 已提交
4516 4517
        virReportError(VIR_ERR_INTERNAL_ERROR,
                   _("Failed to get scheduler id for domain '%d'"
4518
                     " with libxenlight"), vm->def->id);
4519 4520 4521
        goto cleanup;
    }

4522
    ignore_value(VIR_STRDUP(ret, name));
4523

4524
 cleanup:
4525
    if (vm)
4526
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
4527
    virObjectUnref(cfg);
4528 4529 4530
    return ret;
}

4531
static int
4532 4533 4534 4535
libxlDomainGetSchedulerParametersFlags(virDomainPtr dom,
                                       virTypedParameterPtr params,
                                       int *nparams,
                                       unsigned int flags)
4536
{
J
Jim Fehlig 已提交
4537 4538
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4539
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
4540 4541
    libxl_domain_sched_params sc_info;
    libxl_scheduler sched_id;
4542 4543
    int ret = -1;

4544 4545 4546 4547
    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

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

J
Jim Fehlig 已提交
4549
    if (!(vm = libxlDomObjFromDomain(dom)))
4550 4551
        goto cleanup;

4552 4553 4554
    if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4555
    if (!virDomainObjIsActive(vm)) {
J
Jim Fehlig 已提交
4556 4557
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Domain is not running"));
4558 4559 4560
        goto cleanup;
    }

J
Jim Fehlig 已提交
4561
    sched_id = libxl_get_scheduler(cfg->ctx);
4562

J
Jim Fehlig 已提交
4563
    if (sched_id != LIBXL_SCHEDULER_CREDIT) {
4564 4565
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Only 'credit' scheduler is supported"));
4566 4567 4568
        goto cleanup;
    }

J
Jim Fehlig 已提交
4569
    if (libxl_domain_sched_params_get(cfg->ctx, vm->def->id, &sc_info) != 0) {
4570 4571
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to get scheduler parameters for domain '%d'"
4572
                         " with libxenlight"), vm->def->id);
4573 4574 4575
        goto cleanup;
    }

4576 4577
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_WEIGHT,
                                VIR_TYPED_PARAM_UINT, sc_info.weight) < 0)
4578 4579
        goto cleanup;

4580
    if (*nparams > 1) {
4581
        if (virTypedParameterAssign(&params[1], VIR_DOMAIN_SCHEDULER_CAP,
4582
                                    VIR_TYPED_PARAM_UINT, sc_info.cap) < 0)
4583
            goto cleanup;
4584 4585
    }

4586 4587
    if (*nparams > XEN_SCHED_CREDIT_NPARAM)
        *nparams = XEN_SCHED_CREDIT_NPARAM;
4588 4589
    ret = 0;

4590
 cleanup:
4591
    if (vm)
4592
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
4593
    virObjectUnref(cfg);
4594 4595 4596 4597
    return ret;
}

static int
4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608
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)
4609
{
4610
    libxlDriverPrivatePtr driver = dom->conn->privateData;
J
Jim Fehlig 已提交
4611
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4612
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
4613
    libxl_domain_sched_params sc_info;
4614
    int sched_id;
4615
    size_t i;
4616 4617
    int ret = -1;

4618
    virCheckFlags(0, -1);
4619 4620 4621 4622 4623 4624
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_SCHEDULER_WEIGHT,
                               VIR_TYPED_PARAM_UINT,
                               VIR_DOMAIN_SCHEDULER_CAP,
                               VIR_TYPED_PARAM_UINT,
                               NULL) < 0)
4625
        return -1;
4626

J
Jim Fehlig 已提交
4627
    if (!(vm = libxlDomObjFromDomain(dom)))
4628 4629
        goto cleanup;

4630 4631 4632
    if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4633 4634 4635
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0)
        goto cleanup;

4636
    if (!virDomainObjIsActive(vm)) {
4637
        virReportError(VIR_ERR_OPERATION_INVALID, "%s", _("Domain is not running"));
4638
        goto endjob;
4639 4640
    }

J
Jim Fehlig 已提交
4641
    sched_id = libxl_get_scheduler(cfg->ctx);
4642

J
Jim Fehlig 已提交
4643
    if (sched_id != LIBXL_SCHEDULER_CREDIT) {
4644 4645
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Only 'credit' scheduler is supported"));
4646
        goto endjob;
4647 4648
    }

J
Jim Fehlig 已提交
4649
    if (libxl_domain_sched_params_get(cfg->ctx, vm->def->id, &sc_info) != 0) {
4650 4651
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to get scheduler parameters for domain '%d'"
4652
                         " with libxenlight"), vm->def->id);
4653
        goto endjob;
4654 4655 4656
    }

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

4659
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_WEIGHT))
4660
            sc_info.weight = params[i].value.ui;
4661
        else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CAP))
4662 4663 4664
            sc_info.cap = params[i].value.ui;
    }

J
Jim Fehlig 已提交
4665
    if (libxl_domain_sched_params_set(cfg->ctx, vm->def->id, &sc_info) != 0) {
4666 4667
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to set scheduler parameters for domain '%d'"
4668
                         " with libxenlight"), vm->def->id);
4669
        goto endjob;
4670 4671 4672 4673
    }

    ret = 0;

4674
 endjob:
W
Wang Yufei 已提交
4675
    libxlDomainObjEndJob(driver, vm);
4676

4677
 cleanup:
W
Wang Yufei 已提交
4678
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
4679
    virObjectUnref(cfg);
4680 4681 4682
    return ret;
}

B
Bamvor Jian Zhang 已提交
4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696

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);

J
Jim Fehlig 已提交
4697
    if (!(vm = libxlDomObjFromDomain(dom)))
B
Bamvor Jian Zhang 已提交
4698 4699
        goto cleanup;

J
Jim Fehlig 已提交
4700 4701
    LIBXL_CHECK_DOM0_GOTO(vm->def->name, cleanup);

B
Bamvor Jian Zhang 已提交
4702 4703 4704 4705 4706 4707 4708 4709 4710 4711
    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;
B
Bob Liu 已提交
4712 4713
    if (dev_name) {
        size_t i;
B
Bamvor Jian Zhang 已提交
4714

B
Bob Liu 已提交
4715 4716 4717 4718 4719 4720 4721
        for (i = 0; !chr && i < vm->def->nserials; i++) {
            if (STREQ(dev_name, vm->def->serials[i]->info.alias)) {
                chr = vm->def->serials[i];
                break;
            }
        }
    } else if (vm->def->nconsoles) {
I
Ian Campbell 已提交
4722
        chr = vm->def->consoles[0];
4723 4724 4725
        if (chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
            chr = vm->def->serials[0];
    }
B
Bamvor Jian Zhang 已提交
4726 4727 4728 4729 4730 4731 4732 4733

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

4734
    if (chr->source->type != VIR_DOMAIN_CHR_TYPE_PTY) {
B
Bamvor Jian Zhang 已提交
4735 4736
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("character device %s is not using a PTY"),
4737
                       dev_name ? dev_name : NULLSTR(chr->info.alias));
B
Bamvor Jian Zhang 已提交
4738 4739 4740 4741 4742
        goto cleanup;
    }

    /* handle mutually exclusive access to console devices */
    ret = virChrdevOpen(priv->devs,
4743
                        chr->source,
B
Bamvor Jian Zhang 已提交
4744 4745 4746 4747 4748 4749 4750 4751 4752
                        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;
    }

4753
 cleanup:
B
Bamvor Jian Zhang 已提交
4754 4755 4756 4757 4758
    if (vm)
        virObjectUnlock(vm);
    return ret;
}

4759 4760 4761 4762 4763 4764 4765
static int
libxlDomainSetSchedulerParameters(virDomainPtr dom, virTypedParameterPtr params,
                                  int nparams)
{
    return libxlDomainSetSchedulerParametersFlags(dom, params, nparams, 0);
}

4766 4767 4768 4769 4770 4771 4772 4773 4774 4775 4776 4777 4778
/* 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)
{
J
Jim Fehlig 已提交
4779 4780
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796
    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;

4797 4798
    libxl_bitmap_init(&nodemap);

J
Jim Fehlig 已提交
4799
    if (!(vm = libxlDomObjFromDomain(dom)))
4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818
        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;
    }

    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];
4819
        int numnodes;
4820 4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837

        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 */
J
Jim Fehlig 已提交
4838
            numnodes = libxl_get_max_nodes(cfg->ctx);
4839 4840 4841
            if (numnodes <= 0)
                goto cleanup;

J
Jim Fehlig 已提交
4842
            if (libxl_node_bitmap_alloc(cfg->ctx, &nodemap, 0)) {
4843 4844 4845
                virReportOOMError();
                goto cleanup;
            }
J
Ján Tomko 已提交
4846 4847
            if (!(nodes = virBitmapNew(numnodes)))
                goto cleanup;
4848

J
Jim Fehlig 已提交
4849
            rc = libxl_domain_get_nodeaffinity(cfg->ctx,
4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861 4862 4863 4864 4865 4866 4867 4868
                                               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;
                }
            }

4869
            if (!(nodeset = virBitmapFormat(nodes)))
4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 4884 4885
                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;

4886
 cleanup:
4887 4888 4889 4890 4891
    VIR_FREE(nodeset);
    virBitmapFree(nodes);
    libxl_bitmap_dispose(&nodemap);
    if (vm)
        virObjectUnlock(vm);
J
Jim Fehlig 已提交
4892
    virObjectUnref(cfg);
4893 4894 4895 4896
    return ret;
}
#endif

J
Jim Fehlig 已提交
4897 4898 4899 4900 4901 4902
static int
libxlDomainIsActive(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

J
Jim Fehlig 已提交
4903
    if (!(obj = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
4904
        goto cleanup;
4905 4906 4907 4908

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

J
Jim Fehlig 已提交
4909 4910
    ret = virDomainObjIsActive(obj);

4911
 cleanup:
J
Jim Fehlig 已提交
4912
    if (obj)
4913
        virObjectUnlock(obj);
J
Jim Fehlig 已提交
4914 4915 4916 4917 4918 4919 4920 4921 4922
    return ret;
}

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

J
Jim Fehlig 已提交
4923
    if (!(obj = libxlDomObjFromDomain(dom)))
J
Jim Fehlig 已提交
4924
        goto cleanup;
4925 4926 4927 4928

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

J
Jim Fehlig 已提交
4929 4930
    ret = obj->persistent;

4931
 cleanup:
J
Jim Fehlig 已提交
4932
    if (obj)
4933
        virObjectUnlock(obj);
J
Jim Fehlig 已提交
4934 4935 4936
    return ret;
}

4937 4938 4939 4940 4941 4942
static int
libxlDomainIsUpdated(virDomainPtr dom)
{
    virDomainObjPtr vm;
    int ret = -1;

J
Jim Fehlig 已提交
4943
    if (!(vm = libxlDomObjFromDomain(dom)))
4944
        goto cleanup;
4945 4946 4947 4948

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

4949 4950
    ret = vm->updated;

4951
 cleanup:
4952
    if (vm)
4953
        virObjectUnlock(vm);
4954 4955 4956
    return ret;
}

4957 4958
static int
libxlDomainInterfaceStats(virDomainPtr dom,
4959
                          const char *device,
4960 4961 4962 4963
                          virDomainInterfaceStatsPtr stats)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
M
Michal Privoznik 已提交
4964
    virDomainNetDefPtr net = NULL;
4965 4966 4967 4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981
    int ret = -1;

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

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

    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_QUERY) < 0)
        goto cleanup;

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

4982
    if (!(net = virDomainNetFind(vm->def, device)))
M
Michal Privoznik 已提交
4983 4984
        goto endjob;

4985
    if (virNetDevTapInterfaceStats(net->ifname, stats,
4986
                                   !virDomainNetTypeSharesHostView(net)) < 0)
M
Michal Privoznik 已提交
4987 4988 4989
        goto endjob;

    ret = 0;
4990 4991

 endjob:
W
Wang Yufei 已提交
4992
    libxlDomainObjEndJob(driver, vm);
4993 4994

 cleanup:
W
Wang Yufei 已提交
4995
    virDomainObjEndAPI(&vm);
4996 4997 4998
    return ret;
}

4999 5000 5001 5002 5003 5004
static int
libxlDomainGetTotalCPUStats(libxlDriverPrivatePtr driver,
                            virDomainObjPtr vm,
                            virTypedParameterPtr params,
                            unsigned int nparams)
{
J
Jim Fehlig 已提交
5005
    libxlDriverConfigPtr cfg;
5006 5007 5008 5009 5010 5011
    libxl_dominfo d_info;
    int ret = -1;

    if (nparams == 0)
        return LIBXL_NB_TOTAL_CPU_STAT_PARAM;

J
Jim Fehlig 已提交
5012 5013 5014
    libxl_dominfo_init(&d_info);
    cfg = libxlDriverConfigGet(driver);

5015 5016 5017 5018
    if (libxl_domain_info(cfg->ctx, &d_info, vm->def->id) != 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxl_domain_info failed for domain '%d'"),
                       vm->def->id);
J
Jim Fehlig 已提交
5019
        goto cleanup;
5020 5021 5022 5023 5024 5025 5026 5027 5028 5029
    }

    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_CPU_STATS_CPUTIME,
                                VIR_TYPED_PARAM_ULLONG, d_info.cpu_time) < 0)
        goto cleanup;

    ret = nparams;

 cleanup:
    libxl_dominfo_dispose(&d_info);
J
Jim Fehlig 已提交
5030
    virObjectUnref(cfg);
5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044
    return ret;
}

static int
libxlDomainGetPerCPUStats(libxlDriverPrivatePtr driver,
                          virDomainObjPtr vm,
                          virTypedParameterPtr params,
                          unsigned int nparams,
                          int start_cpu,
                          unsigned int ncpus)
{
    libxl_vcpuinfo *vcpuinfo;
    int maxcpu, hostcpus;
    size_t i;
J
Jim Fehlig 已提交
5045
    libxlDriverConfigPtr cfg;
5046 5047 5048 5049 5050
    int ret = -1;

    if (nparams == 0 && ncpus != 0)
        return LIBXL_NB_TOTAL_CPU_STAT_PARAM;
    else if (nparams == 0)
5051
        return virDomainDefGetVcpusMax(vm->def);
5052

J
Jim Fehlig 已提交
5053
    cfg = libxlDriverConfigGet(driver);
5054 5055 5056 5057 5058
    if ((vcpuinfo = libxl_list_vcpu(cfg->ctx, vm->def->id, &maxcpu,
                                    &hostcpus)) == NULL) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Failed to list vcpus for domain '%d' with libxenlight"),
                       vm->def->id);
J
Jim Fehlig 已提交
5059
        goto cleanup;
5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071
    }

    for (i = start_cpu; i < maxcpu && i < ncpus; ++i) {
        if (virTypedParameterAssign(&params[(i-start_cpu)],
                                    VIR_DOMAIN_CPU_STATS_CPUTIME,
                                    VIR_TYPED_PARAM_ULLONG,
                                    vcpuinfo[i].vcpu_time) < 0)
            goto cleanup;
    }
    ret = nparams;

 cleanup:
J
Jim Fehlig 已提交
5072 5073 5074
    if (vcpuinfo)
        libxl_vcpuinfo_list_free(vcpuinfo, maxcpu);
    virObjectUnref(cfg);
5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115
    return ret;
}

static int
libxlDomainGetCPUStats(virDomainPtr dom,
                       virTypedParameterPtr params,
                       unsigned int nparams,
                       int start_cpu,
                       unsigned int ncpus,
                       unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

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

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

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

    if (start_cpu == -1)
        ret = libxlDomainGetTotalCPUStats(driver, vm, params, nparams);
    else
        ret = libxlDomainGetPerCPUStats(driver, vm, params, nparams,
                                          start_cpu, ncpus);

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

5116 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129
#define LIBXL_SET_MEMSTAT(TAG, VAL) \
        if (i < nr_stats) { \
            stats[i].tag = TAG; \
            stats[i].val = VAL; \
            i++; \
        }

static int
libxlDomainMemoryStats(virDomainPtr dom,
                       virDomainMemoryStatPtr stats,
                       unsigned int nr_stats,
                       unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
J
Jim Fehlig 已提交
5130
    libxlDriverConfigPtr cfg;
5131 5132 5133 5134 5135 5136 5137 5138
    virDomainObjPtr vm;
    libxl_dominfo d_info;
    unsigned mem, maxmem;
    size_t i = 0;
    int ret = -1;

    virCheckFlags(0, -1);

5139
    libxl_dominfo_init(&d_info);
J
Jim Fehlig 已提交
5140 5141
    cfg = libxlDriverConfigGet(driver);

5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163
    if (!(vm = libxlDomObjFromDomain(dom)))
        goto cleanup;

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

    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_QUERY) < 0)
        goto cleanup;

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

    if (libxl_domain_info(cfg->ctx, &d_info, vm->def->id) != 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("libxl_domain_info failed for domain '%d'"),
                       vm->def->id);
        goto endjob;
    }
    mem = d_info.current_memkb;
5164
    maxmem = virDomainDefGetMemoryTotal(vm->def);
5165 5166 5167 5168 5169 5170 5171

    LIBXL_SET_MEMSTAT(VIR_DOMAIN_MEMORY_STAT_ACTUAL_BALLOON, mem);
    LIBXL_SET_MEMSTAT(VIR_DOMAIN_MEMORY_STAT_AVAILABLE, maxmem);

    ret = i;

 endjob:
W
Wang Yufei 已提交
5172
    libxlDomainObjEndJob(driver, vm);
5173 5174

 cleanup:
5175
    libxl_dominfo_dispose(&d_info);
W
Wang Yufei 已提交
5176
    virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
5177
    virObjectUnref(cfg);
5178 5179 5180 5181 5182
    return ret;
}

#undef LIBXL_SET_MEMSTAT

5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219
static int
libxlDomainGetJobInfo(virDomainPtr dom,
                      virDomainJobInfoPtr info)
{
    libxlDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;

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

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

    priv = vm->privateData;
    if (!priv->job.active) {
        memset(info, 0, sizeof(*info));
        info->type = VIR_DOMAIN_JOB_NONE;
        ret = 0;
        goto cleanup;
    }

    /* In libxl we don't have an estimated completion time
     * thus we always set to unbounded and update time
     * for the active job. */
    if (libxlDomainJobUpdateTime(&priv->job) < 0)
        goto cleanup;

    memcpy(info, priv->job.current, sizeof(virDomainJobInfo));
    ret = 0;

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

5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270
static int
libxlDomainGetJobStats(virDomainPtr dom,
                       int *type,
                       virTypedParameterPtr *params,
                       int *nparams,
                       unsigned int flags)
{
    libxlDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    virDomainJobInfoPtr jobInfo;
    int ret = -1;
    int maxparams = 0;

    /* VIR_DOMAIN_JOB_STATS_COMPLETED not supported yet */
    virCheckFlags(0, -1);

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

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

    priv = vm->privateData;
    jobInfo = priv->job.current;
    if (!priv->job.active) {
        *type = VIR_DOMAIN_JOB_NONE;
        *params = NULL;
        *nparams = 0;
        ret = 0;
        goto cleanup;
    }

    /* In libxl we don't have an estimated completion time
     * thus we always set to unbounded and update time
     * for the active job. */
    if (libxlDomainJobUpdateTime(&priv->job) < 0)
        goto cleanup;

    if (virTypedParamsAddULLong(params, nparams, &maxparams,
                                VIR_DOMAIN_JOB_TIME_ELAPSED,
                                jobInfo->timeElapsed) < 0)
        goto cleanup;

    *type = jobInfo->type;
    ret = 0;

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

R
Roman Bogorodskiy 已提交
5272
#ifdef __linux__
5273 5274 5275 5276 5277 5278 5279 5280 5281 5282 5283 5284 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319
static int
libxlDiskPathToID(const char *virtpath)
{
    static char const* drive_prefix[] = {"xvd", "hd", "sd"};
    int disk, partition, chrused;
    int fmt, id;
    size_t i;

    fmt = id = -1;

    /* Find any disk prefixes we know about */
    for (i = 0; i < ARRAY_CARDINALITY(drive_prefix); i++) {
        if (STRPREFIX(virtpath, drive_prefix[i]) &&
            !virDiskNameParse(virtpath, &disk, &partition)) {
            fmt = i;
            break;
        }
    }

    /* Handle it same way as xvd */
    if (fmt < 0 &&
        (sscanf(virtpath, "d%ip%i%n", &disk, &partition, &chrused) >= 2
         && chrused == strlen(virtpath)))
        fmt = 0;

    /* Test indexes ranges and calculate the device id */
    switch (fmt) {
    case 0: /* xvd */
        if (disk <= 15 && partition <= 15)
            id = (202 << 8) | (disk << 4) | partition;
        else if ((disk <= ((1<<20)-1)) || partition <= 255)
            id = (1 << 28) | (disk << 8) | partition;
        break;
    case 1: /* hd */
        if (disk <= 3 && partition <= 63)
            id = ((disk < 2 ? 3 : 22) << 8) | ((disk & 1) << 6) | partition;
        break;
    case 2: /* sd */
        if (disk <= 15 && (partition <= 15))
            id = (8 << 8) | (disk << 4) | partition;
        break;
    default: /* invalid */
        break;
    }
    return id;
}

5320
# define LIBXL_VBD_SECTOR_SIZE 512
5321 5322 5323 5324 5325 5326 5327 5328 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 5367 5368 5369 5370

static int
libxlDiskSectorSize(int domid, int devno)
{
    char *path, *val;
    struct xs_handle *handle;
    int ret = LIBXL_VBD_SECTOR_SIZE;
    unsigned int len;

    handle = xs_daemon_open_readonly();
    if (!handle) {
        VIR_WARN("cannot read sector size");
        return ret;
    }

    path = val = NULL;
    if (virAsprintf(&path, "/local/domain/%d/device/vbd/%d/backend",
                    domid, devno) < 0)
        goto cleanup;

    if ((val = xs_read(handle, XBT_NULL, path, &len)) == NULL)
        goto cleanup;

    VIR_FREE(path);
    if (virAsprintf(&path, "%s/physical-sector-size", val) < 0)
        goto cleanup;

    VIR_FREE(val);
    if ((val = xs_read(handle, XBT_NULL, path, &len)) == NULL)
        goto cleanup;

    if (sscanf(val, "%d", &ret) != 1)
        ret = LIBXL_VBD_SECTOR_SIZE;

 cleanup:
    VIR_FREE(val);
    VIR_FREE(path);
    xs_daemon_close(handle);
    return ret;
}

static int
libxlDomainBlockStatsVBD(virDomainObjPtr vm,
                         const char *dev,
                         libxlBlockStatsPtr stats)
{
    int ret = -1;
    int devno = libxlDiskPathToID(dev);
    int size;
    char *path, *name, *val;
5371
    unsigned long long status;
5372 5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395 5396 5397

    path = name = val = NULL;
    if (devno < 0) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot find device number"));
        return ret;
    }

    size = libxlDiskSectorSize(vm->def->id, devno);

    if (VIR_STRDUP(stats->backend, "vbd") < 0)
        return ret;

    if (virAsprintf(&path, "/sys/bus/xen-backend/devices/vbd-%d-%d/statistics",
                    vm->def->id, devno) < 0)
        return ret;

    if (!virFileExists(path)) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("cannot open bus path"));
        goto cleanup;
    }

# define LIBXL_SET_VBDSTAT(FIELD, VAR, MUL)           \
    if ((virAsprintf(&name, "%s/"FIELD, path) < 0) || \
        (virFileReadAll(name, 256, &val) < 0) ||      \
5398
        (sscanf(val, "%llu", &status) != 1)) {        \
5399 5400 5401 5402
        virReportError(VIR_ERR_OPERATION_FAILED,      \
                       _("cannot read %s"), name);    \
        goto cleanup;                                 \
    }                                                 \
5403
    VAR += (status * MUL);                            \
5404 5405 5406 5407 5408 5409 5410 5411 5412 5413 5414 5415 5416 5417 5418 5419 5420 5421 5422 5423 5424 5425 5426 5427 5428 5429 5430 5431 5432 5433 5434 5435 5436 5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457
    VIR_FREE(name);                                   \
    VIR_FREE(val);

    LIBXL_SET_VBDSTAT("f_req",  stats->f_req,  1)
    LIBXL_SET_VBDSTAT("wr_req", stats->wr_req, 1)
    LIBXL_SET_VBDSTAT("rd_req", stats->rd_req, 1)
    LIBXL_SET_VBDSTAT("wr_sect", stats->wr_bytes, size)
    LIBXL_SET_VBDSTAT("rd_sect", stats->rd_bytes, size)

    LIBXL_SET_VBDSTAT("ds_req", stats->u.vbd.ds_req, size)
    LIBXL_SET_VBDSTAT("oo_req", stats->u.vbd.oo_req, 1)
    ret = 0;

 cleanup:
    VIR_FREE(name);
    VIR_FREE(path);
    VIR_FREE(val);

# undef LIBXL_SET_VBDSTAT

    return ret;
}
#else
static int
libxlDomainBlockStatsVBD(virDomainObjPtr vm ATTRIBUTE_UNUSED,
                         const char *dev ATTRIBUTE_UNUSED,
                         libxlBlockStatsPtr stats ATTRIBUTE_UNUSED)
{
    virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                   "%s", _("platform unsupported"));
    return -1;
}
#endif

static int
libxlDomainBlockStatsGatherSingle(virDomainObjPtr vm,
                                  const char *path,
                                  libxlBlockStatsPtr stats)
{
    virDomainDiskDefPtr disk;
    const char *disk_drv;
    int ret = -1, disk_fmt;

    if (!(disk = virDomainDiskByName(vm->def, path, false))) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("invalid path: %s"), path);
        return ret;
    }

    disk_fmt = virDomainDiskGetFormat(disk);
    if (!(disk_drv = virDomainDiskGetDriver(disk)))
        disk_drv = "qemu";

    if (STREQ(disk_drv, "phy")) {
5458
        if (disk_fmt != VIR_STORAGE_FILE_RAW) {
5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 5506 5507 5508 5509 5510 5511 5512 5513 5514 5515 5516 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                           _("unsupported format %s"),
                           virStorageFileFormatTypeToString(disk_fmt));
            return ret;
        }

        ret = libxlDomainBlockStatsVBD(vm, disk->dst, stats);
    } else {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("unsupported disk driver %s"),
                       disk_drv);
    }
    return ret;
}

static int
libxlDomainBlockStatsGather(virDomainObjPtr vm,
                            const char *path,
                            libxlBlockStatsPtr stats)
{
    int ret = -1;

    if (*path) {
        if (libxlDomainBlockStatsGatherSingle(vm, path, stats) < 0)
            return ret;
    } else {
        size_t i;

        for (i = 0; i < vm->def->ndisks; ++i) {
            if (libxlDomainBlockStatsGatherSingle(vm, vm->def->disks[i]->dst,
                                                  stats) < 0)
                return ret;
        }
    }
    return 0;
}

static int
libxlDomainBlockStats(virDomainPtr dom,
                      const char *path,
                      virDomainBlockStatsPtr stats)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    libxlBlockStats blkstats;
    int ret = -1;

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

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

    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_QUERY) < 0)
        goto cleanup;

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

    memset(&blkstats, 0, sizeof(libxlBlockStats));
    if ((ret = libxlDomainBlockStatsGather(vm, path, &blkstats)) < 0)
        goto endjob;

    stats->rd_req = blkstats.rd_req;
    stats->rd_bytes = blkstats.rd_bytes;
    stats->wr_req = blkstats.wr_req;
    stats->wr_bytes = blkstats.wr_bytes;
    if (STREQ_NULLABLE(blkstats.backend, "vbd"))
        stats->errs = blkstats.u.vbd.oo_req;
    else
        stats->errs = -1;

 endjob:
    libxlDomainObjEndJob(driver, vm);

 cleanup:
    virDomainObjEndAPI(&vm);
    return ret;
}

static int
libxlDomainBlockStatsFlags(virDomainPtr dom,
                           const char *path,
                           virTypedParameterPtr params,
                           int *nparams,
                           unsigned int flags)
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    libxlBlockStats blkstats;
    int nstats;
    int ret = -1;

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

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

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

    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_QUERY) < 0)
        goto cleanup;

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

    /* return count of supported stats */
    if (*nparams == 0) {
        *nparams = LIBXL_NB_TOTAL_BLK_STAT_PARAM;
        ret = 0;
        goto endjob;
    }

    memset(&blkstats, 0, sizeof(libxlBlockStats));
    if ((ret = libxlDomainBlockStatsGather(vm, path, &blkstats)) < 0)
        goto endjob;

    nstats = 0;

#define LIBXL_BLKSTAT_ASSIGN_PARAM(VAR, NAME)                              \
    if (nstats < *nparams && (blkstats.VAR) != -1) {                       \
        if (virTypedParameterAssign(params + nstats, NAME,                 \
                                    VIR_TYPED_PARAM_LLONG, (blkstats.VAR)) < 0) \
            goto endjob;                                                   \
        nstats++;                                                          \
    }

    LIBXL_BLKSTAT_ASSIGN_PARAM(wr_bytes, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES);
    LIBXL_BLKSTAT_ASSIGN_PARAM(wr_req, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ);

    LIBXL_BLKSTAT_ASSIGN_PARAM(rd_bytes, VIR_DOMAIN_BLOCK_STATS_READ_BYTES);
    LIBXL_BLKSTAT_ASSIGN_PARAM(rd_req, VIR_DOMAIN_BLOCK_STATS_READ_REQ);

    LIBXL_BLKSTAT_ASSIGN_PARAM(f_req, VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ);

    if (STREQ_NULLABLE(blkstats.backend, "vbd"))
        LIBXL_BLKSTAT_ASSIGN_PARAM(u.vbd.oo_req, VIR_DOMAIN_BLOCK_STATS_ERRS);

    *nparams = nstats;

#undef LIBXL_BLKSTAT_ASSIGN_PARAM

 endjob:
    libxlDomainObjEndJob(driver, vm);

 cleanup:
    virDomainObjEndAPI(&vm);
    return ret;
}

5618
static int
5619 5620 5621
libxlConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID,
                                   virConnectDomainEventGenericCallback callback,
                                   void *opaque, virFreeCallback freecb)
5622 5623 5624 5625
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int ret;

5626 5627 5628
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

5629 5630 5631 5632
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID, callback, opaque,
                                      freecb, &ret) < 0)
5633
        ret = -1;
5634 5635 5636 5637 5638 5639

    return ret;
}


static int
5640
libxlConnectDomainEventDeregisterAny(virConnectPtr conn, int callbackID)
5641 5642 5643
{
    libxlDriverPrivatePtr driver = conn->privateData;

5644 5645 5646
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

5647 5648
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
5649
                                        callbackID, true) < 0)
5650
        return -1;
5651

5652
    return 0;
5653 5654
}

J
Jim Fehlig 已提交
5655

5656
static int
5657
libxlConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
5658 5659 5660 5661
{
    return 1;
}

5662
static int
5663 5664 5665
libxlConnectListAllDomains(virConnectPtr conn,
                           virDomainPtr **domains,
                           unsigned int flags)
5666 5667 5668 5669
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
5670
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
5671

5672 5673 5674
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

5675 5676
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
5677 5678 5679 5680

    return ret;
}

5681 5682 5683 5684 5685 5686 5687 5688
/* Which features are supported by this driver? */
static int
libxlConnectSupportsFeature(virConnectPtr conn, int feature)
{
    if (virConnectSupportsFeatureEnsureACL(conn) < 0)
        return -1;

    switch (feature) {
5689
    case VIR_DRV_FEATURE_MIGRATION_V3:
5690
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
J
Jim Fehlig 已提交
5691
    case VIR_DRV_FEATURE_MIGRATION_PARAMS:
J
Joao Martins 已提交
5692
    case VIR_DRV_FEATURE_MIGRATION_P2P:
5693 5694 5695 5696 5697
        return 1;
    default:
        return 0;
    }
}
5698

5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709
static int
libxlNodeDeviceGetPCIInfo(virNodeDeviceDefPtr def,
                          unsigned *domain,
                          unsigned *bus,
                          unsigned *slot,
                          unsigned *function)
{
    virNodeDevCapsDefPtr cap;

    cap = def->caps;
    while (cap) {
5710
        if (cap->data.type == VIR_NODE_DEV_CAP_PCI_DEV) {
5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723
            *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 已提交
5724
        return -1;
5725 5726
    }

C
Chunyan Liu 已提交
5727
    return 0;
5728 5729 5730 5731 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763
}

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")) {
5764
        virPCIDeviceSetStubDriver(pci, VIR_PCI_STUB_DRIVER_XEN);
5765 5766 5767 5768 5769 5770 5771 5772 5773 5774
    } else {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported driver name '%s'"), driverName);
        goto cleanup;
    }

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

    ret = 0;
5775
 cleanup:
5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817
    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 已提交
5818
        goto cleanup;
5819 5820

    ret = 0;
C
Chunyan Liu 已提交
5821

5822
 cleanup:
C
Chunyan Liu 已提交
5823
    virPCIDeviceFree(pci);
5824 5825 5826 5827 5828 5829 5830 5831
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
libxlNodeDeviceReset(virNodeDevicePtr dev)
{
C
Chunyan Liu 已提交
5832
    virPCIDevicePtr pci = NULL;
5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 5848 5849 5850 5851 5852 5853 5854 5855 5856 5857 5858
    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 已提交
5859
        goto cleanup;
5860 5861

    ret = 0;
C
Chunyan Liu 已提交
5862

5863
 cleanup:
C
Chunyan Liu 已提交
5864
    virPCIDeviceFree(pci);
5865 5866 5867 5868 5869
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

J
Jim Fehlig 已提交
5870 5871 5872 5873
static char *
libxlDomainMigrateBegin3Params(virDomainPtr domain,
                               virTypedParameterPtr params,
                               int nparams,
5874 5875
                               char **cookieout,
                               int *cookieoutlen,
J
Jim Fehlig 已提交
5876 5877 5878 5879 5880
                               unsigned int flags)
{
    const char *xmlin = NULL;
    virDomainObjPtr vm = NULL;

5881 5882 5883 5884 5885
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return NULL;
#endif

J
Jim Fehlig 已提交
5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897
    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;

J
Jim Fehlig 已提交
5898 5899 5900 5901 5902 5903
    if (STREQ_NULLABLE(vm->def->name, "Domain-0")) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Domain-0 cannot be migrated"));
            return NULL;
    }

J
Jim Fehlig 已提交
5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915
    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;
    }

5916 5917
    return libxlDomainMigrationBegin(domain->conn, vm, xmlin,
                                     cookieout, cookieoutlen);
J
Jim Fehlig 已提交
5918 5919
}

B
Bob Liu 已提交
5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974
static int
libxlDomainMigratePrepareTunnel3Params(virConnectPtr dconn,
                                       virStreamPtr st,
                                       virTypedParameterPtr params,
                                       int nparams,
                                       const char *cookiein,
                                       int cookieinlen,
                                       char **cookieout ATTRIBUTE_UNUSED,
                                       int *cookieoutlen ATTRIBUTE_UNUSED,
                                       unsigned int flags)
{
    libxlDriverPrivatePtr driver = dconn->privateData;
    virDomainDefPtr def = NULL;
    const char *dom_xml = NULL;
    const char *dname = NULL;
    const char *uri_in = NULL;

#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

    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 (virDomainMigratePrepareTunnel3ParamsEnsureACL(dconn, def) < 0)
        goto error;

    if (libxlDomainMigrationPrepareTunnel3(dconn, st, &def, cookiein,
                                           cookieinlen, flags) < 0)
        goto error;

    return 0;

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

J
Jim Fehlig 已提交
5975 5976 5977 5978
static int
libxlDomainMigratePrepare3Params(virConnectPtr dconn,
                                 virTypedParameterPtr params,
                                 int nparams,
5979 5980
                                 const char *cookiein,
                                 int cookieinlen,
J
Jim Fehlig 已提交
5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991
                                 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;

5992 5993 5994 5995 5996
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018
    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;

6019 6020
    if (libxlDomainMigrationPrepare(dconn, &def, uri_in, uri_out,
                                    cookiein, cookieinlen, flags) < 0)
J
Jim Fehlig 已提交
6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 6033 6034 6035 6036 6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047
        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;

6048 6049 6050 6051 6052
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074
    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;

B
Bob Liu 已提交
6075
    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
J
Joao Martins 已提交
6076 6077 6078 6079 6080 6081 6082 6083
        if (libxlDomainMigrationPerformP2P(driver, vm, dom->conn, dom_xml,
                                           dconnuri, uri, dname, flags) < 0)
            goto cleanup;
    } else {
        if (libxlDomainMigrationPerform(driver, vm, dom_xml, dconnuri,
                                        uri, dname, flags) < 0)
            goto cleanup;
    }
J
Jim Fehlig 已提交
6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106

    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;
6107
    virDomainPtr ret = NULL;
J
Jim Fehlig 已提交
6108

6109 6110 6111 6112 6113
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return NULL;
#endif

J
Jim Fehlig 已提交
6114 6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133
    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) {
6134
        virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
6135 6136 6137
        return NULL;
    }

6138
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) {
6139
        virDomainObjEndAPI(&vm);
6140 6141 6142 6143 6144
        return NULL;
    }

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

W
Wang Yufei 已提交
6145
    libxlDomainObjEndJob(driver, vm);
6146

6147
    virDomainObjEndAPI(&vm);
6148 6149

    return ret;
J
Jim Fehlig 已提交
6150 6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163
}

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;

6164 6165 6166 6167 6168
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
6169 6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183
    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);
}

6184 6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200
static int libxlNodeGetSecurityModel(virConnectPtr conn,
                                     virSecurityModelPtr secmodel)
{
    memset(secmodel, 0, sizeof(*secmodel));

    if (virNodeGetSecurityModelEnsureACL(conn) < 0)
        return -1;

    /*
     * Currently the libxl driver does not support security model.
     * Similar to the qemu driver, treat this as success and simply
     * return no data in secmodel.  Avoids spamming the libvirt log
     * with "this function is not supported by the connection driver:
     * virNodeGetSecurityModel"
     */
    return 0;
}
6201

6202 6203 6204 6205 6206 6207 6208 6209 6210 6211 6212 6213 6214 6215 6216 6217 6218 6219 6220 6221 6222 6223 6224 6225 6226 6227 6228 6229 6230 6231 6232 6233 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257 6258 6259 6260 6261 6262 6263 6264 6265 6266 6267 6268 6269 6270 6271 6272 6273 6274 6275 6276 6277 6278 6279 6280 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309 6310 6311 6312 6313 6314 6315 6316 6317 6318 6319 6320 6321 6322 6323 6324 6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337 6338 6339 6340
static int
libxlGetDHCPInterfaces(virDomainPtr dom,
                       virDomainObjPtr vm,
                       virDomainInterfacePtr **ifaces)
{
    int rv = -1;
    int n_leases = 0;
    size_t i, j;
    size_t ifaces_count = 0;
    virNetworkPtr network = NULL;
    char macaddr[VIR_MAC_STRING_BUFLEN];
    virDomainInterfacePtr iface = NULL;
    virNetworkDHCPLeasePtr *leases = NULL;
    virDomainInterfacePtr *ifaces_ret = NULL;

    if (!dom->conn->networkDriver ||
        !dom->conn->networkDriver->networkGetDHCPLeases) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Network driver does not support DHCP lease query"));
        return -1;
    }

    for (i = 0; i < vm->def->nnets; i++) {
        if (vm->def->nets[i]->type != VIR_DOMAIN_NET_TYPE_NETWORK)
            continue;

        virMacAddrFormat(&(vm->def->nets[i]->mac), macaddr);
        virObjectUnref(network);
        network = virNetworkLookupByName(dom->conn,
                                         vm->def->nets[i]->data.network.name);

        if ((n_leases = virNetworkGetDHCPLeases(network, macaddr,
                                                &leases, 0)) < 0)
            goto error;

        if (n_leases) {
            if (VIR_EXPAND_N(ifaces_ret, ifaces_count, 1) < 0)
                goto error;

            if (VIR_ALLOC(ifaces_ret[ifaces_count - 1]) < 0)
                goto error;

            iface = ifaces_ret[ifaces_count - 1];
            /* Assuming each lease corresponds to a separate IP */
            iface->naddrs = n_leases;

            if (VIR_ALLOC_N(iface->addrs, iface->naddrs) < 0)
                goto error;

            if (VIR_STRDUP(iface->name, vm->def->nets[i]->ifname) < 0)
                goto cleanup;

            if (VIR_STRDUP(iface->hwaddr, macaddr) < 0)
                goto cleanup;
        }

        for (j = 0; j < n_leases; j++) {
            virNetworkDHCPLeasePtr lease = leases[j];
            virDomainIPAddressPtr ip_addr = &iface->addrs[j];

            if (VIR_STRDUP(ip_addr->addr, lease->ipaddr) < 0)
                goto cleanup;

            ip_addr->type = lease->type;
            ip_addr->prefix = lease->prefix;
        }

        for (j = 0; j < n_leases; j++)
            virNetworkDHCPLeaseFree(leases[j]);

        VIR_FREE(leases);
    }

    *ifaces = ifaces_ret;
    ifaces_ret = NULL;
    rv = ifaces_count;

 cleanup:
    virObjectUnref(network);
    if (leases) {
        for (i = 0; i < n_leases; i++)
            virNetworkDHCPLeaseFree(leases[i]);
    }
    VIR_FREE(leases);

    return rv;

 error:
    if (ifaces_ret) {
        for (i = 0; i < ifaces_count; i++)
            virDomainInterfaceFree(ifaces_ret[i]);
    }
    VIR_FREE(ifaces_ret);

    goto cleanup;
}


static int
libxlDomainInterfaceAddresses(virDomainPtr dom,
                              virDomainInterfacePtr **ifaces,
                              unsigned int source,
                              unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;

    virCheckFlags(0, -1);

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

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

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

    switch (source) {
    case VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_LEASE:
        ret = libxlGetDHCPInterfaces(dom, vm, ifaces);
        break;

    default:
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED,
                       _("Unsupported IP address data source %d"),
                       source);
        break;
    }

 cleanup:
    virDomainObjEndAPI(&vm);
    return ret;
}


6341 6342 6343 6344 6345 6346 6347 6348 6349 6350 6351 6352 6353 6354 6355 6356 6357 6358 6359 6360 6361 6362 6363 6364 6365 6366 6367 6368 6369 6370 6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385 6386 6387 6388 6389 6390 6391 6392 6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412 6413
static char *
libxlConnectGetDomainCapabilities(virConnectPtr conn,
                                  const char *emulatorbin,
                                  const char *arch_str,
                                  const char *machine,
                                  const char *virttype_str,
                                  unsigned int flags)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    libxlDriverConfigPtr cfg;
    char *ret = NULL;
    int virttype = VIR_DOMAIN_VIRT_XEN;
    virDomainCapsPtr domCaps = NULL;
    int arch = virArchFromHost(); /* virArch */

    virCheckFlags(0, ret);

    if (virConnectGetDomainCapabilitiesEnsureACL(conn) < 0)
        return ret;

    cfg = libxlDriverConfigGet(driver);

    if (virttype_str &&
        (virttype = virDomainVirtTypeFromString(virttype_str)) < 0) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown virttype: %s"),
                       virttype_str);
        goto cleanup;
    }

    if (virttype != VIR_DOMAIN_VIRT_XEN) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown virttype: %s"),
                       virttype_str);
        goto cleanup;
    }

    if (arch_str && (arch = virArchFromString(arch_str)) == VIR_ARCH_NONE) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown architecture: %s"),
                       arch_str);
        goto cleanup;
    }

    if (emulatorbin == NULL)
        emulatorbin = "/usr/bin/qemu-system-x86_64";

    if (machine) {
        if (STRNEQ(machine, "xenpv") && STRNEQ(machine, "xenfv")) {
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("Xen only supports 'xenpv' and 'xenfv' machines"));
            goto cleanup;
        }
    } else {
        machine = "xenpv";
    }

    if (!(domCaps = virDomainCapsNew(emulatorbin, machine, arch, virttype)))
        goto cleanup;

    if (libxlMakeDomainCapabilities(domCaps, cfg->firmwares,
                                    cfg->nfirmwares) < 0)
        goto cleanup;

    ret = virDomainCapsFormat(domCaps);

 cleanup:
    virObjectUnref(domCaps);
    virObjectUnref(cfg);
    return ret;
}


6414 6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433
static int
libxlConnectCompareCPU(virConnectPtr conn,
                       const char *xmlDesc,
                       unsigned int flags)
{
    libxlDriverPrivatePtr driver = conn->privateData;
    libxlDriverConfigPtr cfg;
    int ret = VIR_CPU_COMPARE_ERROR;
    bool failIncompatible;

    virCheckFlags(VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE,
                  VIR_CPU_COMPARE_ERROR);

    if (virConnectCompareCPUEnsureACL(conn) < 0)
        return ret;

    failIncompatible = !!(flags & VIR_CONNECT_COMPARE_CPU_FAIL_INCOMPATIBLE);

    cfg = libxlDriverConfigGet(driver);

J
Jiri Denemark 已提交
6434 6435
    ret = virCPUCompareXML(cfg->caps->host.arch, cfg->caps->host.cpu,
                           xmlDesc, failIncompatible);
6436 6437 6438 6439 6440

    virObjectUnref(cfg);
    return ret;
}

6441 6442 6443 6444 6445 6446
static char *
libxlConnectBaselineCPU(virConnectPtr conn,
                        const char **xmlCPUs,
                        unsigned int ncpus,
                        unsigned int flags)
{
J
Jiri Denemark 已提交
6447 6448 6449
    virCPUDefPtr *cpus = NULL;
    virCPUDefPtr cpu = NULL;
    char *cpustr = NULL;
6450 6451 6452 6453 6454 6455 6456

    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
                  VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL);

    if (virConnectBaselineCPUEnsureACL(conn) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
6457 6458 6459
    if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST)))
        goto cleanup;

6460
    if (!(cpu = cpuBaseline(cpus, ncpus, NULL,
J
Jiri Denemark 已提交
6461 6462 6463 6464 6465 6466 6467
                            !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE))))
        goto cleanup;

    if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) &&
        virCPUExpandFeatures(cpus[0]->arch, cpu) < 0)
        goto cleanup;

6468
    cpustr = virCPUDefFormat(cpu, NULL);
6469 6470

 cleanup:
J
Jiri Denemark 已提交
6471 6472 6473 6474
    virCPUDefListFree(cpus);
    virCPUDefFree(cpu);

    return cpustr;
6475 6476
}

6477
static virHypervisorDriver libxlHypervisorDriver = {
6478
    .name = LIBXL_DRIVER_NAME,
6479 6480 6481 6482
    .connectOpen = libxlConnectOpen, /* 0.9.0 */
    .connectClose = libxlConnectClose, /* 0.9.0 */
    .connectGetType = libxlConnectGetType, /* 0.9.0 */
    .connectGetVersion = libxlConnectGetVersion, /* 0.9.0 */
6483
    .connectGetHostname = libxlConnectGetHostname, /* 0.9.0 */
6484
    .connectGetSysinfo = libxlConnectGetSysinfo, /* 1.1.0 */
6485
    .connectGetMaxVcpus = libxlConnectGetMaxVcpus, /* 0.9.0 */
6486
    .nodeGetInfo = libxlNodeGetInfo, /* 0.9.0 */
6487 6488 6489 6490
    .connectGetCapabilities = libxlConnectGetCapabilities, /* 0.9.0 */
    .connectListDomains = libxlConnectListDomains, /* 0.9.0 */
    .connectNumOfDomains = libxlConnectNumOfDomains, /* 0.9.0 */
    .connectListAllDomains = libxlConnectListAllDomains, /* 0.9.13 */
6491 6492 6493 6494 6495 6496 6497
    .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 */
6498
    .domainShutdownFlags = libxlDomainShutdownFlags, /* 0.9.10 */
6499 6500
    .domainReboot = libxlDomainReboot, /* 0.9.0 */
    .domainDestroy = libxlDomainDestroy, /* 0.9.0 */
6501
    .domainDestroyFlags = libxlDomainDestroyFlags, /* 0.9.4 */
6502 6503
    .domainGetOSType = libxlDomainGetOSType, /* 0.9.0 */
    .domainGetMaxMemory = libxlDomainGetMaxMemory, /* 0.9.0 */
6504
    .domainSetMaxMemory = libxlDomainSetMaxMemory, /* 0.9.2 */
6505 6506 6507 6508
    .domainSetMemory = libxlDomainSetMemory, /* 0.9.0 */
    .domainSetMemoryFlags = libxlDomainSetMemoryFlags, /* 0.9.0 */
    .domainGetInfo = libxlDomainGetInfo, /* 0.9.0 */
    .domainGetState = libxlDomainGetState, /* 0.9.2 */
6509
    .domainSave = libxlDomainSave, /* 0.9.2 */
6510
    .domainSaveFlags = libxlDomainSaveFlags, /* 0.9.4 */
6511
    .domainRestore = libxlDomainRestore, /* 0.9.2 */
6512
    .domainRestoreFlags = libxlDomainRestoreFlags, /* 0.9.4 */
6513
    .domainCoreDump = libxlDomainCoreDump, /* 0.9.2 */
6514 6515 6516
    .domainSetVcpus = libxlDomainSetVcpus, /* 0.9.0 */
    .domainSetVcpusFlags = libxlDomainSetVcpusFlags, /* 0.9.0 */
    .domainGetVcpusFlags = libxlDomainGetVcpusFlags, /* 0.9.0 */
6517
    .domainGetMaxVcpus = libxlDomainGetMaxVcpus, /* 3.0.0 */
6518
    .domainPinVcpu = libxlDomainPinVcpu, /* 0.9.0 */
6519
    .domainPinVcpuFlags = libxlDomainPinVcpuFlags, /* 1.2.1 */
6520
    .domainGetVcpus = libxlDomainGetVcpus, /* 0.9.0 */
6521
    .domainGetVcpuPinInfo = libxlDomainGetVcpuPinInfo, /* 1.2.1 */
6522
    .domainGetXMLDesc = libxlDomainGetXMLDesc, /* 0.9.0 */
6523 6524 6525 6526
    .connectDomainXMLFromNative = libxlConnectDomainXMLFromNative, /* 0.9.0 */
    .connectDomainXMLToNative = libxlConnectDomainXMLToNative, /* 0.9.0 */
    .connectListDefinedDomains = libxlConnectListDefinedDomains, /* 0.9.0 */
    .connectNumOfDefinedDomains = libxlConnectNumOfDefinedDomains, /* 0.9.0 */
6527 6528 6529
    .domainCreate = libxlDomainCreate, /* 0.9.0 */
    .domainCreateWithFlags = libxlDomainCreateWithFlags, /* 0.9.0 */
    .domainDefineXML = libxlDomainDefineXML, /* 0.9.0 */
6530
    .domainDefineXMLFlags = libxlDomainDefineXMLFlags, /* 1.2.12 */
6531
    .domainUndefine = libxlDomainUndefine, /* 0.9.0 */
6532
    .domainUndefineFlags = libxlDomainUndefineFlags, /* 0.9.4 */
6533 6534 6535 6536 6537
    .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 */
6538 6539 6540 6541
    .domainGetAutostart = libxlDomainGetAutostart, /* 0.9.0 */
    .domainSetAutostart = libxlDomainSetAutostart, /* 0.9.0 */
    .domainGetSchedulerType = libxlDomainGetSchedulerType, /* 0.9.0 */
    .domainGetSchedulerParameters = libxlDomainGetSchedulerParameters, /* 0.9.0 */
6542
    .domainGetSchedulerParametersFlags = libxlDomainGetSchedulerParametersFlags, /* 0.9.2 */
6543
    .domainSetSchedulerParameters = libxlDomainSetSchedulerParameters, /* 0.9.0 */
6544
    .domainSetSchedulerParametersFlags = libxlDomainSetSchedulerParametersFlags, /* 0.9.2 */
6545 6546 6547
#ifdef LIBXL_HAVE_DOMAIN_NODEAFFINITY
    .domainGetNumaParameters = libxlDomainGetNumaParameters, /* 1.1.1 */
#endif
6548
    .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
6549
    .nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
6550
    .domainGetJobInfo = libxlDomainGetJobInfo, /* 1.3.1 */
6551
    .domainGetJobStats = libxlDomainGetJobStats, /* 1.3.1 */
P
Pavel Hrdina 已提交
6552 6553
    .domainMemoryStats = libxlDomainMemoryStats, /* 1.3.0 */
    .domainGetCPUStats = libxlDomainGetCPUStats, /* 1.3.0 */
6554
    .domainInterfaceStats = libxlDomainInterfaceStats, /* 1.3.2 */
6555 6556
    .domainBlockStats = libxlDomainBlockStats, /* 2.1.0 */
    .domainBlockStatsFlags = libxlDomainBlockStatsFlags, /* 2.1.0 */
6557 6558
    .connectDomainEventRegister = libxlConnectDomainEventRegister, /* 0.9.0 */
    .connectDomainEventDeregister = libxlConnectDomainEventDeregister, /* 0.9.0 */
6559 6560 6561
    .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */
    .domainHasManagedSaveImage = libxlDomainHasManagedSaveImage, /* 0.9.2 */
    .domainManagedSaveRemove = libxlDomainManagedSaveRemove, /* 0.9.2 */
B
Bamvor Jian Zhang 已提交
6562
    .domainOpenConsole = libxlDomainOpenConsole, /* 1.1.2 */
6563 6564 6565
    .domainIsActive = libxlDomainIsActive, /* 0.9.0 */
    .domainIsPersistent = libxlDomainIsPersistent, /* 0.9.0 */
    .domainIsUpdated = libxlDomainIsUpdated, /* 0.9.0 */
6566 6567 6568
    .connectDomainEventRegisterAny = libxlConnectDomainEventRegisterAny, /* 0.9.0 */
    .connectDomainEventDeregisterAny = libxlConnectDomainEventDeregisterAny, /* 0.9.0 */
    .connectIsAlive = libxlConnectIsAlive, /* 0.9.8 */
6569
    .connectSupportsFeature = libxlConnectSupportsFeature, /* 1.1.1 */
6570 6571 6572 6573
    .nodeDeviceDettach = libxlNodeDeviceDettach, /* 1.2.3 */
    .nodeDeviceDetachFlags = libxlNodeDeviceDetachFlags, /* 1.2.3 */
    .nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.2.3 */
    .nodeDeviceReset = libxlNodeDeviceReset, /* 1.2.3 */
6574 6575
    .domainMigrateBegin3Params = libxlDomainMigrateBegin3Params, /* 1.2.6 */
    .domainMigratePrepare3Params = libxlDomainMigratePrepare3Params, /* 1.2.6 */
B
Bob Liu 已提交
6576
    .domainMigratePrepareTunnel3Params = libxlDomainMigratePrepareTunnel3Params, /* 3.1.0 */
6577 6578 6579
    .domainMigratePerform3Params = libxlDomainMigratePerform3Params, /* 1.2.6 */
    .domainMigrateFinish3Params = libxlDomainMigrateFinish3Params, /* 1.2.6 */
    .domainMigrateConfirm3Params = libxlDomainMigrateConfirm3Params, /* 1.2.6 */
6580
    .nodeGetSecurityModel = libxlNodeGetSecurityModel, /* 1.2.16 */
6581
    .domainInterfaceAddresses = libxlDomainInterfaceAddresses, /* 1.3.5 */
6582
    .connectGetDomainCapabilities = libxlConnectGetDomainCapabilities, /* 2.0.0 */
6583
    .connectCompareCPU = libxlConnectCompareCPU, /* 2.3.0 */
6584
    .connectBaselineCPU = libxlConnectBaselineCPU, /* 2.3.0 */
J
Jim Fehlig 已提交
6585 6586
};

6587 6588 6589 6590
static virConnectDriver libxlConnectDriver = {
    .hypervisorDriver = &libxlHypervisorDriver,
};

J
Jim Fehlig 已提交
6591 6592
static virStateDriver libxlStateDriver = {
    .name = "LIBXL",
6593
    .stateInitialize = libxlStateInitialize,
6594
    .stateAutoStart = libxlStateAutoStart,
6595 6596
    .stateCleanup = libxlStateCleanup,
    .stateReload = libxlStateReload,
J
Jim Fehlig 已提交
6597 6598 6599 6600 6601 6602
};


int
libxlRegister(void)
{
6603 6604
    if (virRegisterConnectDriver(&libxlConnectDriver,
                                 true) < 0)
J
Jim Fehlig 已提交
6605 6606 6607 6608 6609 6610
        return -1;
    if (virRegisterStateDriver(&libxlStateDriver) < 0)
        return -1;

    return 0;
}