libxl_driver.c 193.7 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

86 87 88 89
#define LIBXL_CHECK_DOM0_GOTO(name, label) \
    do { \
        if (STREQ_NULLABLE(name, "Domain-0")) { \
            virReportError(VIR_ERR_OPERATION_INVALID, "%s", \
J
Jim Fehlig 已提交
90
                           _("Domain-0 does not support requested operation")); \
91 92
            goto label; \
        } \
J
Jim Fehlig 已提交
93 94
    } 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
    vm->persistent = 1;
J
Jim Fehlig 已提交
613
    virDomainObjSetState(vm, VIR_DOMAIN_RUNNING, VIR_DOMAIN_RUNNING_BOOTED);
614
    if (virDomainDefSetVcpusMax(vm->def, d_info.vcpu_max_id + 1, driver->xmlopt))
615 616
        goto cleanup;

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

    ret = 0;

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

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

    if (!libxlDriverShouldLoad(privileged))
        return 0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    libxlReconnectDomains(libxl_driver);

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

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

J
Jim Fehlig 已提交
788 789
    return 0;

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

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

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

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

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

814 815
    cfg = libxlDriverConfigGet(libxl_driver);

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

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

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


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

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

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

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

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

    return VIR_DRV_OPEN_SUCCESS;
};

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

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

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

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

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

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

913

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

919 920 921
    return virGetHostname();
}

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

    virCheckFlags(0, NULL);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return n;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ret = 0;

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

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


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

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

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

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

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

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

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

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

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

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

    ret = 0;

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

1394 1395
    virCheckFlags(0, -1);

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

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

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

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

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

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

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

    event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);

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

    ret = 0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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 1518

/*
 * 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;
}


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

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

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

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

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

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

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

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

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

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

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

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

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

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

1601 1602
    ret = 0;

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

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

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

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

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

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

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

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

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

        libxl_dominfo_dispose(&d_info);
1656 1657
    }

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

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

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

    virCheckFlags(0, -1);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ret = 0;
1828

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH, -1);

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

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

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

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

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

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

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

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

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

    ret = 0;

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

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

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

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

    virCheckFlags(0, -1);

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

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

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

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

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

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

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

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

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

    ret = 0;
2062

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

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

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

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

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

    vm->hasManagedSave = virFileExists(name);

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

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

    virCheckFlags(0, -1);

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

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

2112
    ret = vm->hasManagedSave;
2113

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ret = 0;

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

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

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

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

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

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

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

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

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

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

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

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

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
2384

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

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

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

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

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

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

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

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

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

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

2429 2430
    ret = 0;

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

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

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

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

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

    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;

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

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

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

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

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

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

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

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

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

    ret = maxinfo;

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

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

2568 2569
    /* Flags checked by virDomainDefFormat */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    virCheckFlags(VIR_DOMAIN_START_PAUSED, -1);

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

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

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

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

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

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

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

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

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

2789 2790 2791
    virCheckFlags(VIR_DOMAIN_DEFINE_VALIDATE, NULL);

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

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

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

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

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

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

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

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

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

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

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

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

2856 2857
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE, -1);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    virDomainDiskDefFree(disk);

    ret = 0;

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

static int
J
Jim Fehlig 已提交
2975
libxlDomainAttachDeviceDiskLive(virDomainObjPtr vm, virDomainDeviceDefPtr dev)
2976
{
J
Jim Fehlig 已提交
2977
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(libxl_driver);
2978 2979 2980 2981 2982 2983
    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 已提交
2984
            ret = libxlDomainChangeEjectableMedia(vm, l_disk);
2985 2986 2987
            break;
        case VIR_DOMAIN_DISK_DEVICE_DISK:
            if (l_disk->bus == VIR_DOMAIN_DISK_BUS_XEN) {
2988
                if (virDomainDiskIndexByName(vm->def, l_disk->dst, true) >= 0) {
2989 2990
                    virReportError(VIR_ERR_OPERATION_FAILED,
                                   _("target %s already exists"), l_disk->dst);
2991 2992 2993
                    goto cleanup;
                }

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

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

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

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

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

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

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

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

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

3057 3058
    libxl_device_pci_init(&pcidev);

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

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

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

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

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

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

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

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

3100
#ifdef LIBXL_HAVE_PVUSB
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 3154
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;
}

3155 3156 3157 3158 3159 3160 3161 3162 3163
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;
3164 3165
    size_t i;
    int ports = 0, usbdevs = 0;
3166 3167 3168 3169 3170 3171 3172

    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;

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 3202
    /* 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;
        }
    }

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 3235
    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

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

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

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

    return 0;
}

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

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

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

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

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

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

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

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

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

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

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

3342 3343
    libxl_device_nic_init(&nic);

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

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

    actualType = virDomainNetGetActualType(net);

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

3364
    if (actualType == VIR_DOMAIN_NET_TYPE_HOSTDEV) {
3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375
        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;

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

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

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

    ret = 0;

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

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

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

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

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

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

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

    return ret;
}

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

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

3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492
        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;

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

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

3509 3510 3511 3512 3513 3514
            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:
3515
                return -1;
3516
            }
3517 3518

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

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

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

static int
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 3570
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 已提交
3571
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
3572
    virDomainHostdevSubsysPtr subsys = &hostdev->source.subsys;
3573
    virDomainHostdevSubsysPCIPtr pcisrc = &subsys->u.pci;
3574 3575 3576 3577
    libxl_device_pci pcidev;
    virDomainHostdevDefPtr detach;
    int idx;
    virHostdevManagerPtr hostdev_mgr = driver->hostdevMgr;
J
Jim Fehlig 已提交
3578
    int ret = -1;
3579

3580 3581
    libxl_device_pci_init(&pcidev);

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

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


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

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


    virDomainHostdevRemove(vm->def, idx);

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

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

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

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

3629
#ifdef LIBXL_HAVE_PVUSB
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 3680
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;
}

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 3749
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

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

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

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

    return -1;
}

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

3794 3795
    libxl_device_nic_init(&nic);

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

    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 已提交
3805
        ret = libxlDomainDetachHostDevice(driver, vm,
3806
                                          virDomainNetGetActualHostdev(detach));
3807
        goto cleanup;
3808 3809
    }

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

J
Jim Fehlig 已提交
3814
    if (libxl_device_nic_remove(cfg->ctx, vm->def->id, &nic, 0)) {
3815 3816 3817 3818 3819 3820 3821 3822 3823
        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 已提交
3824 3825 3826 3827
    if (!ret) {
        networkReleaseActualDevice(vm->def, detach);
        virDomainNetRemove(vm->def, detachidx);
    }
J
Jim Fehlig 已提交
3828
    virObjectUnref(cfg);
3829 3830 3831
    return ret;
}

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

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

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

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

3856
        case VIR_DOMAIN_DEVICE_HOSTDEV:
3857 3858 3859 3860 3861 3862 3863 3864 3865 3866
            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);
3867 3868
            break;

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

    return ret;
}

3879

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

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

3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911
        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;

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

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

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

3939
    return 0;
3940 3941 3942
}

static int
J
Jim Fehlig 已提交
3943
libxlDomainUpdateDeviceLive(virDomainObjPtr vm, virDomainDeviceDefPtr dev)
3944 3945 3946 3947 3948 3949 3950 3951 3952
{
    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 已提交
3953
                    ret = libxlDomainChangeEjectableMedia(vm, disk);
3954 3955 3956 3957
                    if (ret == 0)
                        dev->data.disk = NULL;
                    break;
                default:
3958 3959 3960
                    virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                                   _("disk bus '%s' cannot be updated."),
                                   virDomainDiskBusTypeToString(disk->bus));
3961 3962 3963 3964
                    break;
            }
            break;
        default:
3965 3966 3967
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("device type '%s' cannot be updated"),
                           virDomainDeviceTypeToString(dev->type));
3968 3969 3970 3971 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983
            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;
3984
            if (!(orig = virDomainDiskByName(vmdef, disk->dst, false))) {
3985 3986
                virReportError(VIR_ERR_INVALID_ARG,
                               _("target %s doesn't exist."), disk->dst);
3987 3988 3989
                goto cleanup;
            }
            if (!(orig->device == VIR_DOMAIN_DISK_DEVICE_CDROM)) {
3990 3991
                virReportError(VIR_ERR_INVALID_ARG, "%s",
                               _("this disk doesn't support update"));
3992 3993 3994
                goto cleanup;
            }

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

    ret = 0;

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


static int
4016 4017
libxlDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                             unsigned int flags)
4018 4019
{
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4020
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4021 4022 4023 4024 4025 4026 4027 4028
    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 已提交
4029
    if (!(vm = libxlDomObjFromDomain(dom)))
4030 4031
        goto cleanup;

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

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

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

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

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

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

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

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

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

4075 4076
    ret = 0;

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

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

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

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

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

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

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

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

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

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

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

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

4166 4167
    ret = 0;

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

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

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

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)
{
4199
    libxlDriverPrivatePtr driver = dom->conn->privateData;
4200
    libxlDriverConfigPtr cfg = libxlDriverConfigGet(driver);
4201 4202 4203 4204 4205 4206 4207 4208
    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 已提交
4209
    if (!(vm = libxlDomObjFromDomain(dom)))
4210 4211
        goto cleanup;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4338 4339
    ret = numCells;

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

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

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

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

4362
    return 0;
4363 4364 4365 4366
}


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

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

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

4380
    return 0;
4381 4382
}

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

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

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

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

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

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

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

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

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

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

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

    autostart = (autostart != 0);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    ret = 0;

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

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

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

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 已提交
4698
    if (!(vm = libxlDomObjFromDomain(dom)))
B
Bamvor Jian Zhang 已提交
4699 4700
        goto cleanup;

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

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

B
Bob Liu 已提交
4716 4717 4718 4719 4720 4721 4722
        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 已提交
4723
        chr = vm->def->consoles[0];
4724 4725 4726
        if (chr->targetType == VIR_DOMAIN_CHR_CONSOLE_TARGET_TYPE_SERIAL)
            chr = vm->def->serials[0];
    }
B
Bamvor Jian Zhang 已提交
4727 4728 4729 4730 4731 4732 4733 4734

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

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

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

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

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

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

4798 4799
    libxl_bitmap_init(&nodemap);

J
Jim Fehlig 已提交
4800
    if (!(vm = libxlDomObjFromDomain(dom)))
4801 4802 4803 4804 4805 4806 4807 4808 4809 4810 4811 4812 4813 4814 4815 4816 4817 4818 4819
        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];
4820
        int numnodes;
4821 4822 4823 4824 4825 4826 4827 4828 4829 4830 4831 4832 4833 4834 4835 4836 4837 4838

        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 已提交
4839
            numnodes = libxl_get_max_nodes(cfg->ctx);
4840 4841 4842
            if (numnodes <= 0)
                goto cleanup;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4950 4951
    ret = vm->updated;

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

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

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

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

    ret = 0;
4991 4992

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

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

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

    if (nparams == 0)
        return LIBXL_NB_TOTAL_CPU_STAT_PARAM;

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

5016 5017 5018 5019
    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 已提交
5020
        goto cleanup;
5021 5022 5023 5024 5025 5026 5027 5028 5029 5030
    }

    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 已提交
5031
    virObjectUnref(cfg);
5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045
    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 已提交
5046
    libxlDriverConfigPtr cfg;
5047 5048 5049 5050 5051
    int ret = -1;

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

J
Jim Fehlig 已提交
5054
    cfg = libxlDriverConfigGet(driver);
5055 5056 5057 5058 5059
    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 已提交
5060
        goto cleanup;
5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072
    }

    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 已提交
5073 5074 5075
    if (vcpuinfo)
        libxl_vcpuinfo_list_free(vcpuinfo, maxcpu);
    virObjectUnref(cfg);
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 5116
    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;
}

5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130
#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 已提交
5131
    libxlDriverConfigPtr cfg;
5132 5133 5134 5135 5136 5137 5138 5139
    virDomainObjPtr vm;
    libxl_dominfo d_info;
    unsigned mem, maxmem;
    size_t i = 0;
    int ret = -1;

    virCheckFlags(0, -1);

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

5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 5153 5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164
    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;
5165
    maxmem = virDomainDefGetMemoryTotal(vm->def);
5166 5167 5168 5169 5170 5171 5172

    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 已提交
5173
    libxlDomainObjEndJob(driver, vm);
5174 5175

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

#undef LIBXL_SET_MEMSTAT

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

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 5271
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;
}
5272

R
Roman Bogorodskiy 已提交
5273
#ifdef __linux__
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 5320
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;
}

5321
# define LIBXL_VBD_SECTOR_SIZE 512
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 5371

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;
5372
    unsigned long long status;
5373 5374 5375 5376 5377 5378 5379 5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391 5392 5393 5394 5395

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

5396
# define LIBXL_SET_VBDSTAT(FIELD, VAR, MUL) \
5397
    if ((virAsprintf(&name, "%s/"FIELD, path) < 0) || \
5398 5399 5400 5401 5402 5403 5404 5405
        (virFileReadAll(name, 256, &val) < 0) || \
        (sscanf(val, "%llu", &status) != 1)) { \
        virReportError(VIR_ERR_OPERATION_FAILED, \
                       _("cannot read %s"), name); \
        goto cleanup; \
    } \
    VAR += (status * MUL); \
    VIR_FREE(name); \
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 5458
    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")) {
5459
        if (disk_fmt != VIR_STORAGE_FILE_RAW) {
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
            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;

5588 5589 5590
#define LIBXL_BLKSTAT_ASSIGN_PARAM(VAR, NAME) \
    if (nstats < *nparams && (blkstats.VAR) != -1) { \
        if (virTypedParameterAssign(params + nstats, NAME, \
5591
                                    VIR_TYPED_PARAM_LLONG, (blkstats.VAR)) < 0) \
5592 5593
            goto endjob; \
        nstats++; \
5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618
    }

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

5619
static int
5620 5621 5622
libxlConnectDomainEventRegisterAny(virConnectPtr conn, virDomainPtr dom, int eventID,
                                   virConnectDomainEventGenericCallback callback,
                                   void *opaque, virFreeCallback freecb)
5623 5624 5625 5626
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int ret;

5627 5628 5629
    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        return -1;

5630 5631 5632 5633
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID, callback, opaque,
                                      freecb, &ret) < 0)
5634
        ret = -1;
5635 5636 5637 5638 5639 5640

    return ret;
}


static int
5641
libxlConnectDomainEventDeregisterAny(virConnectPtr conn, int callbackID)
5642 5643 5644
{
    libxlDriverPrivatePtr driver = conn->privateData;

5645 5646 5647
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        return -1;

5648 5649
    if (virObjectEventStateDeregisterID(conn,
                                        driver->domainEventState,
5650
                                        callbackID, true) < 0)
5651
        return -1;
5652

5653
    return 0;
5654 5655
}

J
Jim Fehlig 已提交
5656

5657
static int
5658
libxlConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
5659 5660 5661 5662
{
    return 1;
}

5663
static int
5664 5665 5666
libxlConnectListAllDomains(virConnectPtr conn,
                           virDomainPtr **domains,
                           unsigned int flags)
5667 5668 5669 5670
{
    libxlDriverPrivatePtr driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
5671
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
5672

5673 5674 5675
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        return -1;

5676 5677
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
5678 5679 5680 5681

    return ret;
}

5682 5683 5684 5685 5686 5687 5688 5689
/* Which features are supported by this driver? */
static int
libxlConnectSupportsFeature(virConnectPtr conn, int feature)
{
    if (virConnectSupportsFeatureEnsureACL(conn) < 0)
        return -1;

    switch (feature) {
5690
    case VIR_DRV_FEATURE_MIGRATION_V3:
5691
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
J
Jim Fehlig 已提交
5692
    case VIR_DRV_FEATURE_MIGRATION_PARAMS:
J
Joao Martins 已提交
5693
    case VIR_DRV_FEATURE_MIGRATION_P2P:
5694 5695 5696 5697 5698
        return 1;
    default:
        return 0;
    }
}
5699

5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710
static int
libxlNodeDeviceGetPCIInfo(virNodeDeviceDefPtr def,
                          unsigned *domain,
                          unsigned *bus,
                          unsigned *slot,
                          unsigned *function)
{
    virNodeDevCapsDefPtr cap;

    cap = def->caps;
    while (cap) {
5711
        if (cap->data.type == VIR_NODE_DEV_CAP_PCI_DEV) {
5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 5723 5724
            *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 已提交
5725
        return -1;
5726 5727
    }

C
Chunyan Liu 已提交
5728
    return 0;
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 5764
}

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")) {
5765
        virPCIDeviceSetStubDriver(pci, VIR_PCI_STUB_DRIVER_XEN);
5766 5767 5768 5769 5770 5771 5772 5773 5774 5775
    } else {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported driver name '%s'"), driverName);
        goto cleanup;
    }

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

    ret = 0;
5776
 cleanup:
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 5818
    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 已提交
5819
        goto cleanup;
5820 5821

    ret = 0;
C
Chunyan Liu 已提交
5822

5823
 cleanup:
C
Chunyan Liu 已提交
5824
    virPCIDeviceFree(pci);
5825 5826 5827 5828 5829 5830 5831 5832
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
libxlNodeDeviceReset(virNodeDevicePtr dev)
{
C
Chunyan Liu 已提交
5833
    virPCIDevicePtr pci = NULL;
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 5859
    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 已提交
5860
        goto cleanup;
5861 5862

    ret = 0;
C
Chunyan Liu 已提交
5863

5864
 cleanup:
C
Chunyan Liu 已提交
5865
    virPCIDeviceFree(pci);
5866 5867 5868 5869 5870
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

J
Jim Fehlig 已提交
5871 5872 5873 5874
static char *
libxlDomainMigrateBegin3Params(virDomainPtr domain,
                               virTypedParameterPtr params,
                               int nparams,
5875 5876
                               char **cookieout,
                               int *cookieoutlen,
J
Jim Fehlig 已提交
5877 5878 5879 5880 5881
                               unsigned int flags)
{
    const char *xmlin = NULL;
    virDomainObjPtr vm = NULL;

5882 5883 5884 5885 5886
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return NULL;
#endif

J
Jim Fehlig 已提交
5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898
    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 已提交
5899 5900 5901 5902 5903 5904
    if (STREQ_NULLABLE(vm->def->name, "Domain-0")) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Domain-0 cannot be migrated"));
            return NULL;
    }

J
Jim Fehlig 已提交
5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916
    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;
    }

5917 5918
    return libxlDomainMigrationBegin(domain->conn, vm, xmlin,
                                     cookieout, cookieoutlen);
J
Jim Fehlig 已提交
5919 5920
}

B
Bob Liu 已提交
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 5975
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 已提交
5976 5977 5978 5979
static int
libxlDomainMigratePrepare3Params(virConnectPtr dconn,
                                 virTypedParameterPtr params,
                                 int nparams,
5980 5981
                                 const char *cookiein,
                                 int cookieinlen,
J
Jim Fehlig 已提交
5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992
                                 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;

5993 5994 5995 5996 5997
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 6018 6019
    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;

6020 6021
    if (libxlDomainMigrationPrepare(dconn, &def, uri_in, uri_out,
                                    cookiein, cookieinlen, flags) < 0)
J
Jim Fehlig 已提交
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 6048
        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;

6049 6050 6051 6052 6053
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075
    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 已提交
6076
    if ((flags & (VIR_MIGRATE_TUNNELLED | VIR_MIGRATE_PEER2PEER))) {
J
Joao Martins 已提交
6077 6078 6079 6080 6081 6082 6083 6084
        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 已提交
6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107

    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;
6108
    virDomainPtr ret = NULL;
J
Jim Fehlig 已提交
6109

6110 6111 6112 6113 6114
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return NULL;
#endif

J
Jim Fehlig 已提交
6115 6116 6117 6118 6119 6120 6121 6122 6123 6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134
    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) {
6135
        virDomainObjEndAPI(&vm);
J
Jim Fehlig 已提交
6136 6137 6138
        return NULL;
    }

6139
    if (libxlDomainObjBeginJob(driver, vm, LIBXL_JOB_MODIFY) < 0) {
6140
        virDomainObjEndAPI(&vm);
6141 6142 6143 6144 6145
        return NULL;
    }

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

W
Wang Yufei 已提交
6146
    libxlDomainObjEndJob(driver, vm);
6147

6148
    virDomainObjEndAPI(&vm);
6149 6150

    return ret;
J
Jim Fehlig 已提交
6151 6152 6153 6154 6155 6156 6157 6158 6159 6160 6161 6162 6163 6164
}

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;

6165 6166 6167 6168 6169
#ifdef LIBXL_HAVE_NO_SUSPEND_RESUME
    virReportUnsupportedError();
    return -1;
#endif

J
Jim Fehlig 已提交
6170 6171 6172 6173 6174 6175 6176 6177 6178 6179 6180 6181 6182 6183 6184
    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);
}

6185 6186 6187 6188 6189 6190 6191 6192 6193 6194 6195 6196 6197 6198 6199 6200 6201
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;
}
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 6341
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;
}


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


6415 6416 6417 6418 6419 6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434
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 已提交
6435 6436
    ret = virCPUCompareXML(cfg->caps->host.arch, cfg->caps->host.cpu,
                           xmlDesc, failIncompatible);
6437 6438 6439 6440 6441

    virObjectUnref(cfg);
    return ret;
}

6442 6443 6444 6445 6446 6447
static char *
libxlConnectBaselineCPU(virConnectPtr conn,
                        const char **xmlCPUs,
                        unsigned int ncpus,
                        unsigned int flags)
{
J
Jiri Denemark 已提交
6448 6449 6450
    virCPUDefPtr *cpus = NULL;
    virCPUDefPtr cpu = NULL;
    char *cpustr = NULL;
6451 6452 6453 6454 6455 6456 6457

    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES |
                  VIR_CONNECT_BASELINE_CPU_MIGRATABLE, NULL);

    if (virConnectBaselineCPUEnsureACL(conn) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
6458 6459 6460
    if (!(cpus = virCPUDefListParse(xmlCPUs, ncpus, VIR_CPU_TYPE_HOST)))
        goto cleanup;

6461
    if (!(cpu = cpuBaseline(cpus, ncpus, NULL,
J
Jiri Denemark 已提交
6462 6463 6464 6465 6466 6467 6468
                            !!(flags & VIR_CONNECT_BASELINE_CPU_MIGRATABLE))))
        goto cleanup;

    if ((flags & VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) &&
        virCPUExpandFeatures(cpus[0]->arch, cpu) < 0)
        goto cleanup;

6469
    cpustr = virCPUDefFormat(cpu, NULL);
6470 6471

 cleanup:
J
Jiri Denemark 已提交
6472 6473 6474 6475
    virCPUDefListFree(cpus);
    virCPUDefFree(cpu);

    return cpustr;
6476 6477
}

6478
static virHypervisorDriver libxlHypervisorDriver = {
6479
    .name = LIBXL_DRIVER_NAME,
6480 6481 6482 6483
    .connectOpen = libxlConnectOpen, /* 0.9.0 */
    .connectClose = libxlConnectClose, /* 0.9.0 */
    .connectGetType = libxlConnectGetType, /* 0.9.0 */
    .connectGetVersion = libxlConnectGetVersion, /* 0.9.0 */
6484
    .connectGetHostname = libxlConnectGetHostname, /* 0.9.0 */
6485
    .connectGetSysinfo = libxlConnectGetSysinfo, /* 1.1.0 */
6486
    .connectGetMaxVcpus = libxlConnectGetMaxVcpus, /* 0.9.0 */
6487
    .nodeGetInfo = libxlNodeGetInfo, /* 0.9.0 */
6488 6489 6490 6491
    .connectGetCapabilities = libxlConnectGetCapabilities, /* 0.9.0 */
    .connectListDomains = libxlConnectListDomains, /* 0.9.0 */
    .connectNumOfDomains = libxlConnectNumOfDomains, /* 0.9.0 */
    .connectListAllDomains = libxlConnectListAllDomains, /* 0.9.13 */
6492 6493 6494 6495 6496 6497 6498
    .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 */
6499
    .domainShutdownFlags = libxlDomainShutdownFlags, /* 0.9.10 */
6500 6501
    .domainReboot = libxlDomainReboot, /* 0.9.0 */
    .domainDestroy = libxlDomainDestroy, /* 0.9.0 */
6502
    .domainDestroyFlags = libxlDomainDestroyFlags, /* 0.9.4 */
6503 6504
    .domainGetOSType = libxlDomainGetOSType, /* 0.9.0 */
    .domainGetMaxMemory = libxlDomainGetMaxMemory, /* 0.9.0 */
6505
    .domainSetMaxMemory = libxlDomainSetMaxMemory, /* 0.9.2 */
6506 6507 6508 6509
    .domainSetMemory = libxlDomainSetMemory, /* 0.9.0 */
    .domainSetMemoryFlags = libxlDomainSetMemoryFlags, /* 0.9.0 */
    .domainGetInfo = libxlDomainGetInfo, /* 0.9.0 */
    .domainGetState = libxlDomainGetState, /* 0.9.2 */
6510
    .domainSave = libxlDomainSave, /* 0.9.2 */
6511
    .domainSaveFlags = libxlDomainSaveFlags, /* 0.9.4 */
6512
    .domainRestore = libxlDomainRestore, /* 0.9.2 */
6513
    .domainRestoreFlags = libxlDomainRestoreFlags, /* 0.9.4 */
6514
    .domainCoreDump = libxlDomainCoreDump, /* 0.9.2 */
6515 6516 6517
    .domainSetVcpus = libxlDomainSetVcpus, /* 0.9.0 */
    .domainSetVcpusFlags = libxlDomainSetVcpusFlags, /* 0.9.0 */
    .domainGetVcpusFlags = libxlDomainGetVcpusFlags, /* 0.9.0 */
6518
    .domainGetMaxVcpus = libxlDomainGetMaxVcpus, /* 3.0.0 */
6519
    .domainPinVcpu = libxlDomainPinVcpu, /* 0.9.0 */
6520
    .domainPinVcpuFlags = libxlDomainPinVcpuFlags, /* 1.2.1 */
6521
    .domainGetVcpus = libxlDomainGetVcpus, /* 0.9.0 */
6522
    .domainGetVcpuPinInfo = libxlDomainGetVcpuPinInfo, /* 1.2.1 */
6523
    .domainGetXMLDesc = libxlDomainGetXMLDesc, /* 0.9.0 */
6524 6525 6526 6527
    .connectDomainXMLFromNative = libxlConnectDomainXMLFromNative, /* 0.9.0 */
    .connectDomainXMLToNative = libxlConnectDomainXMLToNative, /* 0.9.0 */
    .connectListDefinedDomains = libxlConnectListDefinedDomains, /* 0.9.0 */
    .connectNumOfDefinedDomains = libxlConnectNumOfDefinedDomains, /* 0.9.0 */
6528 6529 6530
    .domainCreate = libxlDomainCreate, /* 0.9.0 */
    .domainCreateWithFlags = libxlDomainCreateWithFlags, /* 0.9.0 */
    .domainDefineXML = libxlDomainDefineXML, /* 0.9.0 */
6531
    .domainDefineXMLFlags = libxlDomainDefineXMLFlags, /* 1.2.12 */
6532
    .domainUndefine = libxlDomainUndefine, /* 0.9.0 */
6533
    .domainUndefineFlags = libxlDomainUndefineFlags, /* 0.9.4 */
6534 6535 6536 6537 6538
    .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 */
6539 6540 6541 6542
    .domainGetAutostart = libxlDomainGetAutostart, /* 0.9.0 */
    .domainSetAutostart = libxlDomainSetAutostart, /* 0.9.0 */
    .domainGetSchedulerType = libxlDomainGetSchedulerType, /* 0.9.0 */
    .domainGetSchedulerParameters = libxlDomainGetSchedulerParameters, /* 0.9.0 */
6543
    .domainGetSchedulerParametersFlags = libxlDomainGetSchedulerParametersFlags, /* 0.9.2 */
6544
    .domainSetSchedulerParameters = libxlDomainSetSchedulerParameters, /* 0.9.0 */
6545
    .domainSetSchedulerParametersFlags = libxlDomainSetSchedulerParametersFlags, /* 0.9.2 */
6546 6547 6548
#ifdef LIBXL_HAVE_DOMAIN_NODEAFFINITY
    .domainGetNumaParameters = libxlDomainGetNumaParameters, /* 1.1.1 */
#endif
6549
    .nodeGetFreeMemory = libxlNodeGetFreeMemory, /* 0.9.0 */
6550
    .nodeGetCellsFreeMemory = libxlNodeGetCellsFreeMemory, /* 1.1.1 */
6551
    .domainGetJobInfo = libxlDomainGetJobInfo, /* 1.3.1 */
6552
    .domainGetJobStats = libxlDomainGetJobStats, /* 1.3.1 */
P
Pavel Hrdina 已提交
6553 6554
    .domainMemoryStats = libxlDomainMemoryStats, /* 1.3.0 */
    .domainGetCPUStats = libxlDomainGetCPUStats, /* 1.3.0 */
6555
    .domainInterfaceStats = libxlDomainInterfaceStats, /* 1.3.2 */
6556 6557
    .domainBlockStats = libxlDomainBlockStats, /* 2.1.0 */
    .domainBlockStatsFlags = libxlDomainBlockStatsFlags, /* 2.1.0 */
6558 6559
    .connectDomainEventRegister = libxlConnectDomainEventRegister, /* 0.9.0 */
    .connectDomainEventDeregister = libxlConnectDomainEventDeregister, /* 0.9.0 */
6560 6561 6562
    .domainManagedSave = libxlDomainManagedSave, /* 0.9.2 */
    .domainHasManagedSaveImage = libxlDomainHasManagedSaveImage, /* 0.9.2 */
    .domainManagedSaveRemove = libxlDomainManagedSaveRemove, /* 0.9.2 */
B
Bamvor Jian Zhang 已提交
6563
    .domainOpenConsole = libxlDomainOpenConsole, /* 1.1.2 */
6564 6565 6566
    .domainIsActive = libxlDomainIsActive, /* 0.9.0 */
    .domainIsPersistent = libxlDomainIsPersistent, /* 0.9.0 */
    .domainIsUpdated = libxlDomainIsUpdated, /* 0.9.0 */
6567 6568 6569
    .connectDomainEventRegisterAny = libxlConnectDomainEventRegisterAny, /* 0.9.0 */
    .connectDomainEventDeregisterAny = libxlConnectDomainEventDeregisterAny, /* 0.9.0 */
    .connectIsAlive = libxlConnectIsAlive, /* 0.9.8 */
6570
    .connectSupportsFeature = libxlConnectSupportsFeature, /* 1.1.1 */
6571 6572 6573 6574
    .nodeDeviceDettach = libxlNodeDeviceDettach, /* 1.2.3 */
    .nodeDeviceDetachFlags = libxlNodeDeviceDetachFlags, /* 1.2.3 */
    .nodeDeviceReAttach = libxlNodeDeviceReAttach, /* 1.2.3 */
    .nodeDeviceReset = libxlNodeDeviceReset, /* 1.2.3 */
6575 6576
    .domainMigrateBegin3Params = libxlDomainMigrateBegin3Params, /* 1.2.6 */
    .domainMigratePrepare3Params = libxlDomainMigratePrepare3Params, /* 1.2.6 */
B
Bob Liu 已提交
6577
    .domainMigratePrepareTunnel3Params = libxlDomainMigratePrepareTunnel3Params, /* 3.1.0 */
6578 6579 6580
    .domainMigratePerform3Params = libxlDomainMigratePerform3Params, /* 1.2.6 */
    .domainMigrateFinish3Params = libxlDomainMigrateFinish3Params, /* 1.2.6 */
    .domainMigrateConfirm3Params = libxlDomainMigrateConfirm3Params, /* 1.2.6 */
6581
    .nodeGetSecurityModel = libxlNodeGetSecurityModel, /* 1.2.16 */
6582
    .domainInterfaceAddresses = libxlDomainInterfaceAddresses, /* 1.3.5 */
6583
    .connectGetDomainCapabilities = libxlConnectGetDomainCapabilities, /* 2.0.0 */
6584
    .connectCompareCPU = libxlConnectCompareCPU, /* 2.3.0 */
6585
    .connectBaselineCPU = libxlConnectBaselineCPU, /* 2.3.0 */
J
Jim Fehlig 已提交
6586 6587
};

6588 6589 6590 6591
static virConnectDriver libxlConnectDriver = {
    .hypervisorDriver = &libxlHypervisorDriver,
};

J
Jim Fehlig 已提交
6592 6593
static virStateDriver libxlStateDriver = {
    .name = "LIBXL",
6594
    .stateInitialize = libxlStateInitialize,
6595
    .stateAutoStart = libxlStateAutoStart,
6596 6597
    .stateCleanup = libxlStateCleanup,
    .stateReload = libxlStateReload,
J
Jim Fehlig 已提交
6598 6599 6600 6601 6602 6603
};


int
libxlRegister(void)
{
6604 6605
    if (virRegisterConnectDriver(&libxlConnectDriver,
                                 true) < 0)
J
Jim Fehlig 已提交
6606 6607 6608 6609 6610 6611
        return -1;
    if (virRegisterStateDriver(&libxlStateDriver) < 0)
        return -1;

    return 0;
}