qemu_driver.c 441.8 KB
Newer Older
D
Daniel P. Berrange 已提交
1
/*
2
 * qemu_driver.c: core driver methods for managing qemu guests
D
Daniel P. Berrange 已提交
3
 *
4
 * Copyright (C) 2006-2012 Red Hat, Inc.
D
Daniel P. Berrange 已提交
5 6 7 8 9 10 11 12 13 14 15 16 17
 * Copyright (C) 2006 Daniel P. Berrange
 *
 * 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
18
 * License along with this library.  If not, see
O
Osier Yang 已提交
19
 * <http://www.gnu.org/licenses/>.
D
Daniel P. Berrange 已提交
20 21 22 23
 *
 * Author: Daniel P. Berrange <berrange@redhat.com>
 */

24
#include <config.h>
25

D
Daniel P. Berrange 已提交
26 27
#include <sys/types.h>
#include <sys/poll.h>
28
#include <sys/time.h>
D
Daniel P. Berrange 已提交
29 30 31 32 33 34 35 36
#include <dirent.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
37
#include <sys/utsname.h>
38 39 40 41
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <paths.h>
42
#include <stdio.h>
43
#include <sys/wait.h>
44
#include <sys/ioctl.h>
45
#include <sys/un.h>
46
#include <byteswap.h>
D
Daniel P. Berrange 已提交
47

48

49
#include "qemu_driver.h"
50
#include "qemu_agent.h"
51
#include "qemu_conf.h"
52
#include "qemu_capabilities.h"
53
#include "qemu_command.h"
54
#include "qemu_cgroup.h"
55
#include "qemu_hostdev.h"
56
#include "qemu_hotplug.h"
57
#include "qemu_monitor.h"
58
#include "qemu_bridge_filter.h"
59
#include "qemu_process.h"
60
#include "qemu_migration.h"
61 62 63 64

#include "virterror_internal.h"
#include "logging.h"
#include "datatypes.h"
65
#include "buf.h"
66
#include "util.h"
67
#include "nodeinfo.h"
68
#include "stats_linux.h"
69
#include "capabilities.h"
70
#include "memory.h"
71
#include "uuid.h"
72
#include "domain_conf.h"
73
#include "domain_audit.h"
74 75
#include "node_device_conf.h"
#include "pci.h"
76
#include "hostusb.h"
77
#include "processinfo.h"
C
Chris Lalancette 已提交
78
#include "libvirt_internal.h"
79
#include "xml.h"
80
#include "cpu/cpu.h"
81
#include "sysinfo.h"
82
#include "domain_nwfilter.h"
83
#include "hooks.h"
84
#include "storage_file.h"
E
Eric Blake 已提交
85
#include "virfile.h"
86
#include "fdstream.h"
87
#include "configmake.h"
H
Hu Tao 已提交
88
#include "threadpool.h"
89
#include "locking/lock_manager.h"
90
#include "locking/domain_lock.h"
91
#include "virkeycode.h"
92
#include "virnodesuspend.h"
93
#include "virtime.h"
94
#include "virtypedparam.h"
95
#include "bitmap.h"
96

97 98
#define VIR_FROM_THIS VIR_FROM_QEMU

99 100
#define QEMU_DRIVER_NAME "QEMU"

101 102
#define QEMU_NB_MEM_PARAM  3

103 104
#define QEMU_NB_BLOCK_IO_TUNE_PARAM  6

105 106
#define QEMU_NB_NUMA_PARAM 2

E
Eric Blake 已提交
107
#define QEMU_NB_TOTAL_CPU_STAT_PARAM 3
108
#define QEMU_NB_PER_CPU_STAT_PARAM 2
E
Eric Blake 已提交
109

110 111 112 113 114
#define QEMU_SCHED_MIN_PERIOD              1000LL
#define QEMU_SCHED_MAX_PERIOD           1000000LL
#define QEMU_SCHED_MIN_QUOTA               1000LL
#define QEMU_SCHED_MAX_QUOTA  18446744073709551LL

115 116 117
#if HAVE_LINUX_KVM_H
# include <linux/kvm.h>
#endif
118

119 120
/* device for kvm ioctls */
#define KVM_DEVICE "/dev/kvm"
121

122 123 124 125 126 127 128 129 130 131 132
/* add definitions missing in older linux/kvm.h */
#ifndef KVMIO
# define KVMIO 0xAE
#endif
#ifndef KVM_CHECK_EXTENSION
# define KVM_CHECK_EXTENSION       _IO(KVMIO,   0x03)
#endif
#ifndef KVM_CAP_NR_VCPUS
# define KVM_CAP_NR_VCPUS 9       /* returns max vcpus per vm */
#endif

133
#define QEMU_NB_BLKIO_PARAM  2
134

135 136
#define QEMU_NB_BANDWIDTH_PARAM 6

H
Hu Tao 已提交
137 138
static void processWatchdogEvent(void *data, void *opaque);

139 140
static int qemudShutdown(void);

141 142 143
static int qemuDomainObjStart(virConnectPtr conn,
                              struct qemud_driver *driver,
                              virDomainObjPtr vm,
144
                              unsigned int flags);
J
Jiri Denemark 已提交
145

146
static int qemudDomainGetMaxVcpus(virDomainPtr dom);
147

148 149 150 151 152
static void qemuDomainManagedSaveLoad(void *payload,
                                      const void *n ATTRIBUTE_UNUSED,
                                      void *opaque);


153
struct qemud_driver *qemu_driver = NULL;
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
static void
qemuVMDriverLock(void) {
    qemuDriverLock(qemu_driver);
};


static void
qemuVMDriverUnlock(void) {
    qemuDriverUnlock(qemu_driver);
};


static int
qemuVMFilterRebuild(virConnectPtr conn ATTRIBUTE_UNUSED,
                    virHashIterator iter, void *data)
{
    virHashForEach(qemu_driver->domains.objs, iter, data);

    return 0;
}

static virNWFilterCallbackDriver qemuCallbackDriver = {
    .name = QEMU_DRIVER_NAME,
    .vmFilterRebuild = qemuVMFilterRebuild,
    .vmDriverLock = qemuVMDriverLock,
    .vmDriverUnlock = qemuVMDriverUnlock,
};


185 186 187 188
struct qemuAutostartData {
    struct qemud_driver *driver;
    virConnectPtr conn;
};
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

/* Looks up the domain object and unlocks the driver. The returned domain
 * object is locked and the caller is responsible for unlocking it. */
static virDomainObjPtr
qemuDomObjFromDomain(virDomainPtr domain)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    qemuDriverUnlock(driver);
    if (!vm) {
        virUUIDFormat(domain->uuid, uuidstr);
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
    }

    return vm;
}


/* Looks up the domain object from snapshot and unlocks the driver. The
 * returned domain object is locked and the caller is responsible for
 * unlocking it */
static virDomainObjPtr
qemuDomObjFromSnapshot(virDomainSnapshotPtr snapshot)
{
    return qemuDomObjFromDomain(snapshot->domain);
}


/* Looks up snapshot object from VM and name */
static virDomainSnapshotObjPtr
qemuSnapObjFromName(virDomainObjPtr vm,
                    const char *name)
{
    virDomainSnapshotObjPtr snap = NULL;
    snap = virDomainSnapshotFindByName(vm->snapshots, name);
    if (!snap)
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("no domain snapshot with matching name '%s'"),
                       name);

    return snap;
}


/* Looks up snapshot object from VM and snapshotPtr */
static virDomainSnapshotObjPtr
qemuSnapObjFromSnapshot(virDomainObjPtr vm,
                        virDomainSnapshotPtr snapshot)
{
    return qemuSnapObjFromName(vm, snapshot->name);
}

247
static void
248 249
qemuAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED,
                    void *opaque)
250 251 252
{
    virDomainObjPtr vm = payload;
    struct qemuAutostartData *data = opaque;
253
    virErrorPtr err;
254 255 256 257
    int flags = 0;

    if (data->driver->autoStartBypassCache)
        flags |= VIR_DOMAIN_START_BYPASS_CACHE;
258 259

    virDomainObjLock(vm);
260
    virResetLastError();
261 262 263 264 265 266 267 268 269 270 271 272
    if (vm->autostart &&
        !virDomainObjIsActive(vm)) {
        if (qemuDomainObjBeginJobWithDriver(data->driver, vm,
                                            QEMU_JOB_MODIFY) < 0) {
            err = virGetLastError();
            VIR_ERROR(_("Failed to start job on VM '%s': %s"),
                      vm->def->name,
                      err ? err->message : _("unknown error"));
            goto cleanup;
        }

        if (qemuDomainObjStart(data->conn, data->driver, vm, flags) < 0) {
273
            err = virGetLastError();
274
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
275
                      vm->def->name,
276
                      err ? err->message : _("unknown error"));
277
        }
278

279
        if (qemuDomainObjEndJob(data->driver, vm) == 0)
280
            vm = NULL;
281
    }
282

283
cleanup:
284 285
    if (vm)
        virDomainObjUnlock(vm);
286 287
}

288

289
static void
290 291
qemuAutostartDomains(struct qemud_driver *driver)
{
292 293 294 295 296
    /* XXX: Figure out a better way todo this. The domain
     * startup code needs a connection handle in order
     * to lookup the bridge associated with a virtual
     * network
     */
297 298 299
    virConnectPtr conn = virConnectOpen(driver->privileged ?
                                        "qemu:///system" :
                                        "qemu:///session");
300
    /* Ignoring NULL conn which is mostly harmless here */
301
    struct qemuAutostartData data = { driver, conn };
302

303
    qemuDriverLock(driver);
304
    virHashForEach(driver->domains.objs, qemuAutostartDomain, &data);
305
    qemuDriverUnlock(driver);
306

307 308
    if (conn)
        virConnectClose(conn);
309 310
}

311
static int
312
qemuSecurityInit(struct qemud_driver *driver)
313
{
314
    char **names;
315 316 317
    virSecurityManagerPtr mgr = NULL;
    virSecurityManagerPtr stack = NULL;

318 319
    if (driver->securityDriverNames &&
        driver->securityDriverNames[0]) {
320
        names = driver->securityDriverNames;
321
        while (names && *names) {
322 323 324 325 326
            if (!(mgr = virSecurityManagerNew(*names,
                                              QEMU_DRIVER_NAME,
                                              driver->allowDiskFormatProbing,
                                              driver->securityDefaultConfined,
                                              driver->securityRequireConfined)))
327
                goto error;
328 329 330 331 332 333 334 335
            if (!stack) {
                if (!(stack = virSecurityManagerNewStack(mgr)))
                    goto error;
            } else {
                if (virSecurityManagerStackAddNested(stack, mgr) < 0)
                    goto error;
            }
            mgr = NULL;
336 337
            names++;
        }
338 339 340 341 342 343
    } else {
        if (!(mgr = virSecurityManagerNew(NULL,
                                          QEMU_DRIVER_NAME,
                                          driver->allowDiskFormatProbing,
                                          driver->securityDefaultConfined,
                                          driver->securityRequireConfined)))
344
            goto error;
345
        if (!(stack = virSecurityManagerNewStack(mgr)))
346
            goto error;
347 348
        mgr = NULL;
    }
349

350
    if (driver->privileged) {
351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
        if (!(mgr = virSecurityManagerNewDAC(QEMU_DRIVER_NAME,
                                             driver->user,
                                             driver->group,
                                             driver->allowDiskFormatProbing,
                                             driver->securityDefaultConfined,
                                             driver->securityRequireConfined,
                                             driver->dynamicOwnership)))
            goto error;
        if (!stack) {
            if (!(stack = virSecurityManagerNewStack(mgr)))
                goto error;
        } else {
            if (virSecurityManagerStackAddNested(stack, mgr) < 0)
                goto error;
        }
        mgr = NULL;
367
    }
D
Daniel Veillard 已提交
368

369
    driver->securityManager = stack;
370
    return 0;
371

372
error:
373
    VIR_ERROR(_("Failed to initialize security drivers"));
374
    virSecurityManagerFree(stack);
375 376 377
    virSecurityManagerFree(mgr);
    return -1;
}
378

379

380 381 382 383
static virCapsPtr
qemuCreateCapabilities(virCapsPtr oldcaps,
                       struct qemud_driver *driver)
{
384
    size_t i;
385
    virCapsPtr caps;
386 387 388
    virSecurityManagerPtr *sec_managers = NULL;
    /* Security driver data */
    const char *doi, *model;
389

390 391 392 393
    /* Basic host arch / guest machine capabilities */
    if (!(caps = qemuCapsInit(oldcaps))) {
        virReportOOMError();
        return NULL;
394 395
    }

396 397 398 399 400 401
    if (driver->allowDiskFormatProbing) {
        caps->defaultDiskDriverName = NULL;
        caps->defaultDiskDriverType = NULL;
    } else {
        caps->defaultDiskDriverName = "qemu";
        caps->defaultDiskDriverType = "raw";
402 403
    }

404 405
    qemuDomainSetPrivateDataHooks(caps);
    qemuDomainSetNamespaceHooks(caps);
406

407
    if (virGetHostUUID(caps->host.host_uuid)) {
408 409
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot get the host uuid"));
410
        goto err_exit;
411
    }
412

413 414 415 416 417
    /* access sec drivers and create a sec model for each one */
    sec_managers = virSecurityManagerGetNested(driver->securityManager);
    if (sec_managers == NULL) {
        goto err_exit;
    }
418

419 420 421 422
    /* calculate length */
    for (i = 0; sec_managers[i]; i++)
        ;
    caps->host.nsecModels = i;
423

424
    if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0)
425 426
        goto no_memory;

427 428 429 430
    for (i = 0; sec_managers[i]; i++) {
        doi = virSecurityManagerGetDOI(sec_managers[i]);
        model = virSecurityManagerGetModel(sec_managers[i]);
        if (!(caps->host.secModels[i].model = strdup(model)))
431
            goto no_memory;
432
        if (!(caps->host.secModels[i].doi = strdup(doi)))
433
            goto no_memory;
434 435
        VIR_DEBUG("Initialized caps for security driver \"%s\" with "
                  "DOI \"%s\"", model, doi);
436
    }
437
    VIR_FREE(sec_managers);
438

439
    return caps;
440

441 442 443
no_memory:
    virReportOOMError();
err_exit:
444
    VIR_FREE(sec_managers);
445
    virCapabilitiesFree(caps);
446 447 448
    return NULL;
}

449
static void qemuDomainSnapshotLoad(void *payload,
450
                                   const void *name ATTRIBUTE_UNUSED,
451
                                   void *data)
452
{
453 454 455 456 457 458 459 460 461
    virDomainObjPtr vm = (virDomainObjPtr)payload;
    char *baseDir = (char *)data;
    char *snapDir = NULL;
    DIR *dir = NULL;
    struct dirent *entry;
    char *xmlStr;
    int ret;
    char *fullpath;
    virDomainSnapshotDefPtr def = NULL;
462
    virDomainSnapshotObjPtr snap = NULL;
463
    virDomainSnapshotObjPtr current = NULL;
464
    char ebuf[1024];
465
    unsigned int flags = (VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE |
466
                          VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
467
                          VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL);
468

469 470 471 472
    virDomainObjLock(vm);
    if (virAsprintf(&snapDir, "%s/%s", baseDir, vm->def->name) < 0) {
        VIR_ERROR(_("Failed to allocate memory for snapshot directory for domain %s"),
                   vm->def->name);
473
        goto cleanup;
474 475
    }

476 477
    VIR_INFO("Scanning for snapshots for domain %s in %s", vm->def->name,
             snapDir);
478

479 480 481 482 483
    if (!(dir = opendir(snapDir))) {
        if (errno != ENOENT)
            VIR_ERROR(_("Failed to open snapshot directory %s for domain %s: %s"),
                      snapDir, vm->def->name,
                      virStrerror(errno, ebuf, sizeof(ebuf)));
484
        goto cleanup;
485 486
    }

487 488 489
    while ((entry = readdir(dir))) {
        if (entry->d_name[0] == '.')
            continue;
490

491 492 493
        /* NB: ignoring errors, so one malformed config doesn't
           kill the whole process */
        VIR_INFO("Loading snapshot file '%s'", entry->d_name);
494

495
        if (virAsprintf(&fullpath, "%s/%s", snapDir, entry->d_name) < 0) {
496
            VIR_ERROR(_("Failed to allocate memory for path"));
497 498
            continue;
        }
499

500 501 502 503 504 505 506 507
        ret = virFileReadAll(fullpath, 1024*1024*1, &xmlStr);
        if (ret < 0) {
            /* Nothing we can do here, skip this one */
            VIR_ERROR(_("Failed to read snapshot file %s: %s"), fullpath,
                      virStrerror(errno, ebuf, sizeof(ebuf)));
            VIR_FREE(fullpath);
            continue;
        }
508

509 510 511
        def = virDomainSnapshotDefParseString(xmlStr, qemu_driver->caps,
                                              QEMU_EXPECTED_VIRT_TYPES,
                                              flags);
512 513
        if (def == NULL) {
            /* Nothing we can do here, skip this one */
514 515
            VIR_ERROR(_("Failed to parse snapshot XML from file '%s'"),
                      fullpath);
516 517 518 519
            VIR_FREE(fullpath);
            VIR_FREE(xmlStr);
            continue;
        }
520

521
        snap = virDomainSnapshotAssignDef(vm->snapshots, def);
522 523
        if (snap == NULL) {
            virDomainSnapshotDefFree(def);
524 525 526 527
        } else if (snap->def->current) {
            current = snap;
            if (!vm->current_snapshot)
                vm->current_snapshot = snap;
528
        }
529

530 531
        VIR_FREE(fullpath);
        VIR_FREE(xmlStr);
532 533
    }

534 535 536 537 538 539
    if (vm->current_snapshot != current) {
        VIR_ERROR(_("Too many snapshots claiming to be current for domain %s"),
                  vm->def->name);
        vm->current_snapshot = NULL;
    }

540
    if (virDomainSnapshotUpdateRelations(vm->snapshots) < 0)
541 542 543
        VIR_ERROR(_("Snapshots have inconsistent relations for domain %s"),
                  vm->def->name);

544 545 546 547 548 549 550 551
    /* FIXME: qemu keeps internal track of snapshots.  We can get access
     * to this info via the "info snapshots" monitor command for running
     * domains, or via "qemu-img snapshot -l" for shutoff domains.  It would
     * be nice to update our internal state based on that, but there is a
     * a problem.  qemu doesn't track all of the same metadata that we do.
     * In particular we wouldn't be able to fill in the <parent>, which is
     * pretty important in our metadata.
     */
552

553
    virResetLastError();
554

555 556 557 558
cleanup:
    if (dir)
        closedir(dir);
    VIR_FREE(snapDir);
559 560 561
    virDomainObjUnlock(vm);
}

562 563 564 565 566

static void qemuDomainNetsRestart(void *payload,
                                const void *name ATTRIBUTE_UNUSED,
                                void *data ATTRIBUTE_UNUSED)
{
567 568 569 570 571 572 573 574 575 576 577 578 579
    int i;
    virDomainObjPtr vm = (virDomainObjPtr)payload;
    virDomainDefPtr def = vm->def;

    virDomainObjLock(vm);

    for (i = 0; i < def->nnets; i++) {
        virDomainNetDefPtr net = def->nets[i];
        if (virDomainNetGetActualType(net) == VIR_DOMAIN_NET_TYPE_DIRECT &&
            virDomainNetGetActualDirectMode(net) == VIR_NETDEV_MACVLAN_MODE_VEPA) {
            VIR_DEBUG("VEPA mode device %s active in domain %s. Reassociating.",
                      net->ifname, def->name);
            ignore_value(virNetDevMacVLanRestartWithVPortProfile(net->ifname,
580
                                                                 &net->mac,
581 582 583 584 585 586 587 588
                                                                 virDomainNetGetActualDirectDev(net),
                                                                 def->uuid,
                                                                 virDomainNetGetActualVirtPortProfile(net),
                                                                 VIR_NETDEV_VPORT_PROFILE_OP_CREATE));
        }
    }

    virDomainObjUnlock(vm);
589 590
}

591 592 593 594 595
/**
 * qemudStartup:
 *
 * Initialization function for the QEmu daemon
 */
596
static int
597 598 599 600 601
qemudStartup(int privileged) {
    char *base = NULL;
    char *driverConf = NULL;
    int rc;
    virConnectPtr conn = NULL;
602
    char ebuf[1024];
603 604
    char *membase = NULL;
    char *mempath = NULL;
605

606 607
    if (VIR_ALLOC(qemu_driver) < 0)
        return -1;
608

609
    if (virMutexInit(&qemu_driver->lock) < 0) {
610
        VIR_ERROR(_("cannot initialize mutex"));
611 612
        VIR_FREE(qemu_driver);
        return -1;
613
    }
614 615
    qemuDriverLock(qemu_driver);
    qemu_driver->privileged = privileged;
616

617 618
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;
619

620 621
    if (virDomainObjListInit(&qemu_driver->domains) < 0)
        goto out_of_memory;
622

623
    /* Init domain events */
624
    qemu_driver->domainEventState = virDomainEventStateNew();
625
    if (!qemu_driver->domainEventState)
626
        goto error;
627

628 629 630
    /* read the host sysinfo */
    if (privileged)
        qemu_driver->hostsysinfo = virSysinfoRead();
631

632 633 634 635
    if (privileged) {
        if (virAsprintf(&qemu_driver->logDir,
                        "%s/log/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
636

637 638
        if ((base = strdup (SYSCONFDIR "/libvirt")) == NULL)
            goto out_of_memory;
639

640 641 642
        if (virAsprintf(&qemu_driver->stateDir,
                      "%s/run/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
643

644 645 646
        if (virAsprintf(&qemu_driver->libDir,
                      "%s/lib/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
647

648 649 650 651 652 653 654 655 656 657 658 659 660
        if (virAsprintf(&qemu_driver->cacheDir,
                      "%s/cache/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->saveDir,
                      "%s/lib/libvirt/qemu/save", LOCALSTATEDIR) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->snapshotDir,
                        "%s/lib/libvirt/qemu/snapshot", LOCALSTATEDIR) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->autoDumpPath,
                        "%s/lib/libvirt/qemu/dump", LOCALSTATEDIR) == -1)
            goto out_of_memory;
    } else {
661 662 663
        char *rundir;
        char *cachedir;

664
        cachedir = virGetUserCacheDirectory();
665
        if (!cachedir)
666
            goto error;
667

668
        if (virAsprintf(&qemu_driver->logDir,
669 670
                        "%s/qemu/log", cachedir) == -1) {
            VIR_FREE(cachedir);
671 672
            goto out_of_memory;
        }
673 674
        if (virAsprintf(&qemu_driver->cacheDir, "%s/qemu/cache", cachedir) == -1) {
            VIR_FREE(cachedir);
675 676
            goto out_of_memory;
        }
677
        VIR_FREE(cachedir);
678

679
        rundir = virGetUserRuntimeDirectory();
680 681 682 683
        if (!rundir)
            goto error;
        if (virAsprintf(&qemu_driver->stateDir, "%s/qemu/run", rundir) == -1) {
            VIR_FREE(rundir);
684
            goto out_of_memory;
685 686 687
        }
        VIR_FREE(rundir);

688
        base = virGetUserConfigDirectory();
689 690
        if (!base)
            goto error;
691 692 693 694 695 696 697 698
        if (virAsprintf(&qemu_driver->libDir, "%s/qemu/lib", base) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->saveDir, "%s/qemu/save", base) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->snapshotDir, "%s/qemu/snapshot", base) == -1)
            goto out_of_memory;
        if (virAsprintf(&qemu_driver->autoDumpPath, "%s/qemu/dump", base) == -1)
            goto out_of_memory;
699
    }
H
Hu Tao 已提交
700

701
    if (virFileMakePath(qemu_driver->stateDir) < 0) {
702
        VIR_ERROR(_("Failed to create state dir '%s': %s"),
703
                  qemu_driver->stateDir, virStrerror(errno, ebuf, sizeof(ebuf)));
704
        goto error;
H
Hu Tao 已提交
705
    }
706
    if (virFileMakePath(qemu_driver->libDir) < 0) {
707
        VIR_ERROR(_("Failed to create lib dir '%s': %s"),
708
                  qemu_driver->libDir, virStrerror(errno, ebuf, sizeof(ebuf)));
709 710
        goto error;
    }
711
    if (virFileMakePath(qemu_driver->cacheDir) < 0) {
712
        VIR_ERROR(_("Failed to create cache dir '%s': %s"),
713
                  qemu_driver->cacheDir, virStrerror(errno, ebuf, sizeof(ebuf)));
714 715
        goto error;
    }
716
    if (virFileMakePath(qemu_driver->saveDir) < 0) {
717
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
718
                  qemu_driver->saveDir, virStrerror(errno, ebuf, sizeof(ebuf)));
719 720
        goto error;
    }
721
    if (virFileMakePath(qemu_driver->snapshotDir) < 0) {
722
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
723
                  qemu_driver->snapshotDir, virStrerror(errno, ebuf, sizeof(ebuf)));
724 725
        goto error;
    }
726
    if (virFileMakePath(qemu_driver->autoDumpPath) < 0) {
727
        VIR_ERROR(_("Failed to create dump dir '%s': %s"),
728
                  qemu_driver->autoDumpPath, virStrerror(errno, ebuf, sizeof(ebuf)));
729
        goto error;
730 731
    }

732 733 734 735 736 737 738
    /* Configuration paths are either ~/.libvirt/qemu/... (session) or
     * /etc/libvirt/qemu/... (system).
     */
    if (virAsprintf(&driverConf, "%s/qemu.conf", base) < 0 ||
        virAsprintf(&qemu_driver->configDir, "%s/qemu", base) < 0 ||
        virAsprintf(&qemu_driver->autostartDir, "%s/qemu/autostart", base) < 0)
        goto out_of_memory;
739

740
    VIR_FREE(base);
741

742 743 744
    rc = virCgroupForDriver("qemu", &qemu_driver->cgroup, privileged, 1);
    if (rc < 0) {
        VIR_INFO("Unable to create cgroup for driver: %s",
745
                 virStrerror(-rc, ebuf, sizeof(ebuf)));
746 747
    }

748 749 750 751
    if (qemudLoadDriverConfig(qemu_driver, driverConf) < 0) {
        goto error;
    }
    VIR_FREE(driverConf);
752

753 754 755 756
    /* Allocate bitmap for remote display port reservations. We cannot
     * do this before the config is loaded properly, since the port
     * numbers are configurable now */
    if ((qemu_driver->reservedRemotePorts =
757
         virBitmapNew(qemu_driver->remotePortMax - qemu_driver->remotePortMin)) == NULL)
758 759
        goto out_of_memory;

760 761 762 763 764 765 766 767
    /* We should always at least have the 'nop' manager, so
     * NULLs here are a fatal error
     */
    if (!qemu_driver->lockManager) {
        VIR_ERROR(_("Missing lock manager implementation"));
        goto error;
    }

768 769
    if (qemuSecurityInit(qemu_driver) < 0)
        goto error;
770

771 772 773
    if ((qemu_driver->caps = qemuCreateCapabilities(NULL,
                                                    qemu_driver)) == NULL)
        goto error;
774

775
    if ((qemu_driver->activePciHostdevs = pciDeviceListNew()) == NULL)
776
        goto error;
777

778 779 780
    if ((qemu_driver->activeUsbHostdevs = usbDeviceListNew()) == NULL)
        goto error;

781 782 783
    if ((qemu_driver->inactivePciHostdevs = pciDeviceListNew()) == NULL)
        goto error;

784 785 786 787 788 789
    if (privileged) {
        if (chown(qemu_driver->libDir, qemu_driver->user, qemu_driver->group) < 0) {
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to user %d:%d"),
                                 qemu_driver->libDir, qemu_driver->user, qemu_driver->group);
            goto error;
790
        }
791
        if (chown(qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group) < 0) {
792
            virReportSystemError(errno,
793 794 795
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group);
            goto error;
796
        }
797 798 799 800 801 802 803 804 805 806 807
        if (chown(qemu_driver->saveDir, qemu_driver->user, qemu_driver->group) < 0) {
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->saveDir, qemu_driver->user, qemu_driver->group);
            goto error;
        }
        if (chown(qemu_driver->snapshotDir, qemu_driver->user, qemu_driver->group) < 0) {
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->snapshotDir, qemu_driver->user, qemu_driver->group);
            goto error;
808
        }
809
    }
810

811 812 813 814 815 816
    /* If hugetlbfs is present, then we need to create a sub-directory within
     * it, since we can't assume the root mount point has permissions that
     * will let our spawned QEMU instances use it.
     *
     * NB the check for '/', since user may config "" to disable hugepages
     * even when mounted
817
     */
818 819
    if (qemu_driver->hugetlbfs_mount &&
        qemu_driver->hugetlbfs_mount[0] == '/') {
820 821 822
        if (virAsprintf(&membase, "%s/libvirt",
                        qemu_driver->hugetlbfs_mount) < 0 ||
            virAsprintf(&mempath, "%s/qemu", membase) < 0)
823
            goto out_of_memory;
824

825 826
        if (virFileMakePath(mempath) < 0) {
            virReportSystemError(errno,
827 828
                                 _("unable to create hugepage path %s"), mempath);
            goto error;
829
        }
830 831 832 833 834 835 836 837 838 839
        if (qemu_driver->privileged) {
            if (virFileUpdatePerm(membase, 0, S_IXGRP | S_IXOTH) < 0)
                goto error;
            if (chown(mempath, qemu_driver->user, qemu_driver->group) < 0) {
                virReportSystemError(errno,
                                     _("unable to set ownership on %s to %d:%d"),
                                     mempath, qemu_driver->user,
                                     qemu_driver->group);
                goto error;
            }
G
Guido Günther 已提交
840
        }
S
Stefan Berger 已提交
841
        VIR_FREE(membase);
E
Eric Blake 已提交
842

843
        qemu_driver->hugepage_path = mempath;
844
    }
845

846 847 848
    if (qemuDriverCloseCallbackInit(qemu_driver) < 0)
        goto error;

849 850 851 852 853
    /* Get all the running persistent or transient configs first */
    if (virDomainLoadAllConfigs(qemu_driver->caps,
                                &qemu_driver->domains,
                                qemu_driver->stateDir,
                                NULL,
M
Matthias Bolte 已提交
854 855
                                1, QEMU_EXPECTED_VIRT_TYPES,
                                NULL, NULL) < 0)
856
        goto error;
857

858 859
    virHashForEach(qemu_driver->domains.objs, qemuDomainNetsRestart, NULL);

860 861 862
    conn = virConnectOpen(qemu_driver->privileged ?
                          "qemu:///system" :
                          "qemu:///session");
863

864
    qemuProcessReconnectAll(conn, qemu_driver);
865

866 867 868 869 870
    /* Then inactive persistent configs */
    if (virDomainLoadAllConfigs(qemu_driver->caps,
                                &qemu_driver->domains,
                                qemu_driver->configDir,
                                qemu_driver->autostartDir,
M
Matthias Bolte 已提交
871 872
                                0, QEMU_EXPECTED_VIRT_TYPES,
                                NULL, NULL) < 0)
873
        goto error;
874

875

876 877
    virHashForEach(qemu_driver->domains.objs, qemuDomainSnapshotLoad,
                   qemu_driver->snapshotDir);
878

879 880 881
    virHashForEach(qemu_driver->domains.objs, qemuDomainManagedSaveLoad,
                   qemu_driver);

882
    qemu_driver->workerPool = virThreadPoolNew(0, 1, 0, processWatchdogEvent, qemu_driver);
883 884
    if (!qemu_driver->workerPool)
        goto error;
885

886 887 888 889
    qemuDriverUnlock(qemu_driver);

    qemuAutostartDomains(qemu_driver);

890 891
    if (conn)
        virConnectClose(conn);
892

893
    virNWFilterRegisterCallbackDriver(&qemuCallbackDriver);
894
    return 0;
895

896 897 898 899 900 901 902 903 904
out_of_memory:
    virReportOOMError();
error:
    if (qemu_driver)
        qemuDriverUnlock(qemu_driver);
    if (conn)
        virConnectClose(conn);
    VIR_FREE(base);
    VIR_FREE(driverConf);
905 906
    VIR_FREE(membase);
    VIR_FREE(mempath);
907
    qemudShutdown();
908
    return -1;
909 910
}

911 912 913
static void qemudNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
{
    struct qemud_driver *driver = opaque;
914

915 916 917 918 919 920 921
    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
E
Eric Blake 已提交
922
    }
923
}
E
Eric Blake 已提交
924

925 926 927 928 929 930 931 932 933 934
/**
 * qemudReload:
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
qemudReload(void) {
    if (!qemu_driver)
        return 0;
935

936 937 938 939 940
    qemuDriverLock(qemu_driver);
    virDomainLoadAllConfigs(qemu_driver->caps,
                            &qemu_driver->domains,
                            qemu_driver->configDir,
                            qemu_driver->autostartDir,
M
Matthias Bolte 已提交
941 942
                            0, QEMU_EXPECTED_VIRT_TYPES,
                            qemudNotifyLoadDomain, qemu_driver);
943
    qemuDriverUnlock(qemu_driver);
944

945 946
    return 0;
}
S
Stefan Berger 已提交
947

948 949 950 951 952 953 954 955 956 957 958
/**
 * qemudActive:
 *
 * Checks if the QEmu daemon is active, i.e. has an active domain or
 * an active network
 *
 * Returns 1 if active, 0 otherwise
 */
static int
qemudActive(void) {
    int active = 0;
959

960 961
    if (!qemu_driver)
        return 0;
962

963 964 965 966 967 968
    /* XXX having to iterate here is not great because it requires many locks */
    qemuDriverLock(qemu_driver);
    active = virDomainObjListNumOfDomains(&qemu_driver->domains, 1);
    qemuDriverUnlock(qemu_driver);
    return active;
}
969

970 971 972 973 974 975 976 977
/**
 * qemudShutdown:
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
qemudShutdown(void) {
    int i;
978

979 980
    if (!qemu_driver)
        return -1;
981

982
    qemuDriverLock(qemu_driver);
983
    virNWFilterUnRegisterCallbackDriver(&qemuCallbackDriver);
984
    pciDeviceListFree(qemu_driver->activePciHostdevs);
985
    pciDeviceListFree(qemu_driver->inactivePciHostdevs);
986
    usbDeviceListFree(qemu_driver->activeUsbHostdevs);
987
    virCapabilitiesFree(qemu_driver->caps);
988

989
    virDomainObjListDeinit(&qemu_driver->domains);
990
    virBitmapFree(qemu_driver->reservedRemotePorts);
991

992
    virSysinfoDefFree(qemu_driver->hostsysinfo);
993

994
    qemuDriverCloseCallbackShutdown(qemu_driver);
995

996 997 998 999 1000 1001 1002 1003
    VIR_FREE(qemu_driver->configDir);
    VIR_FREE(qemu_driver->autostartDir);
    VIR_FREE(qemu_driver->logDir);
    VIR_FREE(qemu_driver->stateDir);
    VIR_FREE(qemu_driver->libDir);
    VIR_FREE(qemu_driver->cacheDir);
    VIR_FREE(qemu_driver->saveDir);
    VIR_FREE(qemu_driver->snapshotDir);
E
Eric Blake 已提交
1004
    VIR_FREE(qemu_driver->qemuImgBinary);
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
    VIR_FREE(qemu_driver->autoDumpPath);
    VIR_FREE(qemu_driver->vncTLSx509certdir);
    VIR_FREE(qemu_driver->vncListen);
    VIR_FREE(qemu_driver->vncPassword);
    VIR_FREE(qemu_driver->vncSASLdir);
    VIR_FREE(qemu_driver->spiceTLSx509certdir);
    VIR_FREE(qemu_driver->spiceListen);
    VIR_FREE(qemu_driver->spicePassword);
    VIR_FREE(qemu_driver->hugetlbfs_mount);
    VIR_FREE(qemu_driver->hugepage_path);
    VIR_FREE(qemu_driver->saveImageFormat);
    VIR_FREE(qemu_driver->dumpImageFormat);
1017

1018
    virSecurityManagerFree(qemu_driver->securityManager);
1019

1020
    ebtablesContextFree(qemu_driver->ebtables);
1021

1022 1023 1024 1025
    if (qemu_driver->cgroupDeviceACL) {
        for (i = 0 ; qemu_driver->cgroupDeviceACL[i] != NULL ; i++)
            VIR_FREE(qemu_driver->cgroupDeviceACL[i]);
        VIR_FREE(qemu_driver->cgroupDeviceACL);
S
Stefan Berger 已提交
1026 1027
    }

1028
    /* Free domain callback list */
1029
    virDomainEventStateFree(qemu_driver->domainEventState);
D
Daniel P. Berrange 已提交
1030

1031
    virCgroupFree(&qemu_driver->cgroup);
1032

1033 1034
    virLockManagerPluginUnref(qemu_driver->lockManager);

1035 1036 1037 1038
    qemuDriverUnlock(qemu_driver);
    virMutexDestroy(&qemu_driver->lock);
    virThreadPoolFree(qemu_driver->workerPool);
    VIR_FREE(qemu_driver);
1039

1040
    return 0;
1041 1042
}

1043

1044
static virDrvOpenStatus qemudOpen(virConnectPtr conn,
1045
                                  virConnectAuthPtr auth ATTRIBUTE_UNUSED,
E
Eric Blake 已提交
1046
                                  unsigned int flags)
1047
{
E
Eric Blake 已提交
1048 1049
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1050
    if (conn->uri == NULL) {
1051 1052 1053
        if (qemu_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;

1054 1055 1056
        if (!(conn->uri = virURIParse(qemu_driver->privileged ?
                                      "qemu:///system" :
                                      "qemu:///session")))
1057
            return VIR_DRV_OPEN_ERROR;
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
    } else {
        /* If URI isn't 'qemu' its definitely not for us */
        if (conn->uri->scheme == NULL ||
            STRNEQ(conn->uri->scheme, "qemu"))
            return VIR_DRV_OPEN_DECLINED;

        /* Allow remote driver to deal with URIs with hostname server */
        if (conn->uri->server != NULL)
            return VIR_DRV_OPEN_DECLINED;

1068
        if (qemu_driver == NULL) {
1069 1070
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("qemu state driver is not active"));
1071 1072 1073
            return VIR_DRV_OPEN_ERROR;
        }

1074
        if (conn->uri->path == NULL) {
1075 1076 1077 1078 1079
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no QEMU URI path given, try %s"),
                           qemu_driver->privileged
                           ? "qemu:///system"
                           : "qemu:///session");
1080 1081 1082
                return VIR_DRV_OPEN_ERROR;
        }

1083
        if (qemu_driver->privileged) {
1084 1085
            if (STRNEQ (conn->uri->path, "/system") &&
                STRNEQ (conn->uri->path, "/session")) {
1086 1087 1088
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected QEMU URI path '%s', try qemu:///system"),
                               conn->uri->path);
1089 1090 1091 1092
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
            if (STRNEQ (conn->uri->path, "/session")) {
1093 1094 1095
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected QEMU URI path '%s', try qemu:///session"),
                               conn->uri->path);
1096 1097 1098
                return VIR_DRV_OPEN_ERROR;
            }
        }
1099 1100 1101 1102 1103 1104 1105
    }
    conn->privateData = qemu_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

static int qemudClose(virConnectPtr conn) {
1106
    struct qemud_driver *driver = conn->privateData;
1107 1108

    /* Get rid of callbacks registered for this conn */
1109
    qemuDriverLock(driver);
1110
    qemuDriverCloseCallbackRunAll(driver, conn);
1111
    qemuDriverUnlock(driver);
1112 1113 1114 1115 1116 1117

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
1118 1119 1120 1121 1122
/* Which features are supported by this driver? */
static int
qemudSupportsFeature (virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
{
    switch (feature) {
1123
    case VIR_DRV_FEATURE_MIGRATION_V2:
1124
    case VIR_DRV_FEATURE_MIGRATION_V3:
1125
    case VIR_DRV_FEATURE_MIGRATION_P2P:
1126
    case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
1127
    case VIR_DRV_FEATURE_FD_PASSING:
1128
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
1129 1130 1131
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
1132 1133 1134
    }
}

1135
static const char *qemudGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
1136
    return "QEMU";
1137 1138
}

1139

1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151
static int qemuIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}

static int qemuIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}

1152 1153 1154 1155 1156
static int qemuIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return 1;
}

1157

1158 1159 1160 1161
static int kvmGetMaxVCPUs(void) {
    int maxvcpus = 1;

    int r, fd;
1162

1163 1164
    fd = open(KVM_DEVICE, O_RDONLY);
    if (fd < 0) {
1165
        virReportSystemError(errno, _("Unable to open %s"), KVM_DEVICE);
1166
        return -1;
1167 1168 1169 1170 1171 1172
    }

    r = ioctl(fd, KVM_CHECK_EXTENSION, KVM_CAP_NR_VCPUS);
    if (r > 0)
        maxvcpus = r;

1173
    VIR_FORCE_CLOSE(fd);
1174 1175 1176 1177
    return maxvcpus;
}


E
Eric Blake 已提交
1178 1179 1180 1181
static char *
qemuGetSysinfo(virConnectPtr conn, unsigned int flags)
{
    struct qemud_driver *driver = conn->privateData;
1182
    virBuffer buf = VIR_BUFFER_INITIALIZER;
E
Eric Blake 已提交
1183 1184 1185 1186

    virCheckFlags(0, NULL);

    if (!driver->hostsysinfo) {
1187 1188
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Host SMBIOS information is not available"));
E
Eric Blake 已提交
1189 1190 1191
        return NULL;
    }

1192 1193 1194 1195 1196 1197 1198
    if (virSysinfoFormat(&buf, driver->hostsysinfo) < 0)
        return NULL;
    if (virBufferError(&buf)) {
        virReportOOMError();
        return NULL;
    }
    return virBufferContentAndReset(&buf);
E
Eric Blake 已提交
1199 1200
}

1201
static int qemudGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED, const char *type) {
1202 1203 1204
    if (!type)
        return 16;

1205
    if (STRCASEEQ(type, "qemu"))
1206 1207
        return 16;

1208
    if (STRCASEEQ(type, "kvm"))
1209
        return kvmGetMaxVCPUs();
1210

1211
    if (STRCASEEQ(type, "kqemu"))
1212
        return 1;
1213

1214 1215
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unknown type '%s'"), type);
1216 1217 1218
    return -1;
}

1219

1220
static char *qemudGetCapabilities(virConnectPtr conn) {
1221
    struct qemud_driver *driver = conn->privateData;
1222
    virCapsPtr caps = NULL;
1223
    char *xml = NULL;
1224

1225
    qemuDriverLock(driver);
1226

1227
    if ((caps = qemuCreateCapabilities(qemu_driver->caps,
1228
                                       qemu_driver)) == NULL) {
1229 1230 1231
        virCapabilitiesFree(caps);
        goto cleanup;
    }
1232

1233
    virCapabilitiesFree(qemu_driver->caps);
1234 1235 1236
    qemu_driver->caps = caps;

    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
1237
        virReportOOMError();
1238 1239

cleanup:
1240
    qemuDriverUnlock(driver);
1241

1242
    return xml;
1243 1244 1245
}


1246
static int
1247
qemudGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss,
1248
                    pid_t pid, int tid)
1249 1250
{
    char *proc;
D
Daniel P. Berrange 已提交
1251
    FILE *pidinfo;
1252
    unsigned long long usertime, systime;
1253
    long rss;
1254 1255
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
1256

1257 1258
    /* In general, we cannot assume pid_t fits in int; but /proc parsing
     * is specific to Linux where int works fine.  */
1259
    if (tid)
1260
        ret = virAsprintf(&proc, "/proc/%d/task/%d/stat", (int) pid, tid);
1261
    else
1262
        ret = virAsprintf(&proc, "/proc/%d/stat", (int) pid);
1263
    if (ret < 0)
D
Daniel P. Berrange 已提交
1264 1265 1266 1267
        return -1;

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
1268 1269 1270 1271
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
1272 1273
        if (vm_rss)
            *vm_rss = 0;
1274
        VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1275 1276
        return 0;
    }
1277
    VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1278

1279 1280 1281 1282 1283 1284
    /* See 'man proc' for information about what all these fields are. We're
     * only interested in a very few of them */
    if (fscanf(pidinfo,
               /* pid -> stime */
               "%*d %*s %*c %*d %*d %*d %*d %*d %*u %*u %*u %*u %*u %llu %llu"
               /* cutime -> endcode */
1285
               "%*d %*d %*d %*d %*d %*d %*u %*u %ld %*u %*u %*u"
1286 1287
               /* startstack -> processor */
               "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
1288
               &usertime, &systime, &rss, &cpu) != 4) {
1289
        VIR_FORCE_FCLOSE(pidinfo);
1290
        VIR_WARN("cannot parse process status data");
1291
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
1292 1293 1294 1295 1296 1297 1298 1299
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
1300 1301 1302 1303 1304
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

1305 1306 1307 1308 1309 1310
    /* We got pages
     * We want kiloBytes
     * _SC_PAGESIZE is page size in Bytes
     * So calculate, but first lower the pagesize so we don't get overflow */
    if (vm_rss)
        *vm_rss = rss * (sysconf(_SC_PAGESIZE) >> 10);
D
Daniel P. Berrange 已提交
1311

1312 1313

    VIR_DEBUG("Got status for %d/%d user=%llu sys=%llu cpu=%d rss=%ld",
1314
              (int) pid, tid, usertime, systime, cpu, rss);
D
Daniel P. Berrange 已提交
1315

1316
    VIR_FORCE_FCLOSE(pidinfo);
D
Daniel P. Berrange 已提交
1317 1318 1319 1320 1321

    return 0;
}


1322
static virDomainPtr qemudDomainLookupByID(virConnectPtr conn,
1323
                                          int id) {
1324 1325 1326 1327
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

1328
    qemuDriverLock(driver);
1329
    vm  = virDomainFindByID(&driver->domains, id);
1330
    qemuDriverUnlock(driver);
1331 1332

    if (!vm) {
1333 1334
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), id);
1335
        goto cleanup;
1336 1337
    }

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

cleanup:
1342 1343
    if (vm)
        virDomainObjUnlock(vm);
1344 1345
    return dom;
}
1346

1347
static virDomainPtr qemudDomainLookupByUUID(virConnectPtr conn,
1348
                                            const unsigned char *uuid) {
1349 1350 1351
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1352

1353
    qemuDriverLock(driver);
1354
    vm = virDomainFindByUUID(&driver->domains, uuid);
1355 1356
    qemuDriverUnlock(driver);

1357
    if (!vm) {
1358 1359
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
1360 1361
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1362
        goto cleanup;
1363 1364
    }

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

cleanup:
1369 1370
    if (vm)
        virDomainObjUnlock(vm);
1371 1372
    return dom;
}
1373

1374
static virDomainPtr qemudDomainLookupByName(virConnectPtr conn,
1375
                                            const char *name) {
1376 1377 1378
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1379

1380
    qemuDriverLock(driver);
1381
    vm = virDomainFindByName(&driver->domains, name);
1382 1383
    qemuDriverUnlock(driver);

1384
    if (!vm) {
1385 1386
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), name);
1387
        goto cleanup;
1388 1389
    }

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

cleanup:
1394 1395
    if (vm)
        virDomainObjUnlock(vm);
1396 1397 1398
    return dom;
}

1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409

static int qemuDomainIsActive(virDomainPtr dom)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    qemuDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!obj) {
E
Eric Blake 已提交
1410 1411
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1412 1413
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433
        goto cleanup;
    }
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}

static int qemuDomainIsPersistent(virDomainPtr dom)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    qemuDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!obj) {
E
Eric Blake 已提交
1434 1435
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1436 1437
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1438 1439 1440 1441 1442 1443 1444 1445 1446 1447
        goto cleanup;
    }
    ret = obj->persistent;

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}

1448 1449 1450 1451 1452 1453 1454 1455 1456 1457
static int qemuDomainIsUpdated(virDomainPtr dom)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr obj;
    int ret = -1;

    qemuDriverLock(driver);
    obj = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!obj) {
E
Eric Blake 已提交
1458 1459
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1460 1461
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1462 1463 1464 1465 1466 1467 1468 1469 1470
        goto cleanup;
    }
    ret = obj->updated;

cleanup:
    if (obj)
        virDomainObjUnlock(obj);
    return ret;
}
1471

1472
static int qemudGetVersion(virConnectPtr conn, unsigned long *version) {
1473 1474 1475
    struct qemud_driver *driver = conn->privateData;
    int ret = -1;

1476
    qemuDriverLock(driver);
1477
    if (qemuCapsExtractVersion(driver->caps, &driver->qemuVersion) < 0)
1478
        goto cleanup;
1479

1480
    *version = driver->qemuVersion;
1481 1482 1483
    ret = 0;

cleanup:
1484
    qemuDriverUnlock(driver);
1485
    return ret;
D
Daniel P. Berrange 已提交
1486 1487
}

1488
static int qemudListDomains(virConnectPtr conn, int *ids, int nids) {
1489
    struct qemud_driver *driver = conn->privateData;
1490
    int n;
1491

1492
    qemuDriverLock(driver);
1493
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
1494
    qemuDriverUnlock(driver);
1495

1496
    return n;
D
Daniel P. Berrange 已提交
1497
}
1498

1499
static int qemudNumDomains(virConnectPtr conn) {
1500
    struct qemud_driver *driver = conn->privateData;
1501
    int n;
1502

1503
    qemuDriverLock(driver);
1504
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
1505
    qemuDriverUnlock(driver);
1506

1507
    return n;
D
Daniel P. Berrange 已提交
1508
}
1509

1510
static virDomainPtr qemudDomainCreate(virConnectPtr conn, const char *xml,
1511
                                      unsigned int flags) {
1512
    struct qemud_driver *driver = conn->privateData;
1513
    virDomainDefPtr def;
1514
    virDomainObjPtr vm = NULL;
1515
    virDomainPtr dom = NULL;
1516
    virDomainEventPtr event = NULL;
1517
    virDomainEventPtr event2 = NULL;
1518
    unsigned int start_flags = VIR_QEMU_PROCESS_START_COLD;
D
Daniel P. Berrange 已提交
1519

1520 1521
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
                  VIR_DOMAIN_START_AUTODESTROY, NULL);
1522

1523 1524 1525 1526 1527
    if (flags & VIR_DOMAIN_START_PAUSED)
        start_flags |= VIR_QEMU_PROCESS_START_PAUSED;
    if (flags & VIR_DOMAIN_START_AUTODESTROY)
        start_flags |= VIR_QEMU_PROCESS_START_AUTODESROY;

1528
    qemuDriverLock(driver);
1529
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
1530
                                        QEMU_EXPECTED_VIRT_TYPES,
1531
                                        VIR_DOMAIN_XML_INACTIVE)))
1532
        goto cleanup;
1533

1534
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
1535 1536
        goto cleanup;

1537 1538
    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;
1539

1540 1541 1542
    if (qemudCanonicalizeMachine(driver, def) < 0)
        goto cleanup;

1543
    if (qemuDomainAssignAddresses(def, NULL, NULL) < 0)
1544 1545
        goto cleanup;

1546
    if (!(vm = virDomainAssignDef(driver->caps,
1547
                                  &driver->domains,
1548
                                  def, false)))
1549 1550 1551
        goto cleanup;

    def = NULL;
D
Daniel P. Berrange 已提交
1552

1553
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
1554 1555
        goto cleanup; /* XXXX free the 'vm' we created ? */

1556 1557 1558
    if (qemuProcessStart(conn, driver, vm, NULL, -1, NULL, NULL,
                         VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                         start_flags) < 0) {
1559
        virDomainAuditStart(vm, "booted", false);
1560
        if (qemuDomainObjEndJob(driver, vm) > 0)
1561
            qemuDomainRemoveInactive(driver, vm);
1562
        vm = NULL;
1563
        goto cleanup;
D
Daniel P. Berrange 已提交
1564
    }
1565 1566 1567 1568

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1569 1570 1571 1572 1573 1574 1575 1576 1577 1578
    if (event && (flags & VIR_DOMAIN_START_PAUSED)) {
        /* There are two classes of event-watching clients - those
         * that only care about on/off (and must see a started event
         * no matter what, but don't care about suspend events), and
         * those that also care about running/paused.  To satisfy both
         * client types, we have to send two events.  */
        event2 = virDomainEventNewFromObj(vm,
                                          VIR_DOMAIN_EVENT_SUSPENDED,
                                          VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }
1579
    virDomainAuditStart(vm, "booted", true);
D
Daniel P. Berrange 已提交
1580

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

1584
    if (vm &&
1585
        qemuDomainObjEndJob(driver, vm) == 0)
1586
        vm = NULL;
1587

1588 1589
cleanup:
    virDomainDefFree(def);
1590 1591
    if (vm)
        virDomainObjUnlock(vm);
1592
    if (event) {
1593
        qemuDomainEventQueue(driver, event);
1594 1595 1596
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
1597
    qemuDriverUnlock(driver);
1598
    return dom;
D
Daniel P. Berrange 已提交
1599 1600 1601
}


1602
static int qemudDomainSuspend(virDomainPtr dom) {
1603 1604 1605
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1606
    virDomainEventPtr event = NULL;
1607
    qemuDomainObjPrivatePtr priv;
1608 1609
    virDomainPausedReason reason;
    int eventDetail;
1610
    int state;
1611

1612
    qemuDriverLock(driver);
1613
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1614

D
Daniel P. Berrange 已提交
1615
    if (!vm) {
1616 1617
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1618 1619
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1620
        goto cleanup;
D
Daniel P. Berrange 已提交
1621
    }
D
Daniel P. Berrange 已提交
1622
    if (!virDomainObjIsActive(vm)) {
1623 1624
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1625
        goto cleanup;
D
Daniel P. Berrange 已提交
1626
    }
1627 1628 1629

    priv = vm->privateData;

1630
    if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) {
1631 1632
        reason = VIR_DOMAIN_PAUSED_MIGRATION;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED;
1633
    } else {
1634 1635 1636
        reason = VIR_DOMAIN_PAUSED_USER;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED;
    }
1637

1638 1639 1640 1641
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_SUSPEND) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
1642 1643
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1644 1645
        goto endjob;
    }
1646 1647 1648 1649 1650 1651 1652

    state = virDomainObjGetState(vm, NULL);
    if (state == VIR_DOMAIN_PMSUSPENDED) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is pmsuspended"));
        goto endjob;
    } else if (state != VIR_DOMAIN_PAUSED) {
1653
        if (qemuProcessStopCPUs(driver, vm, reason, QEMU_ASYNC_JOB_NONE) < 0) {
1654
            goto endjob;
1655
        }
1656 1657 1658
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         eventDetail);
D
Daniel P. Berrange 已提交
1659
    }
1660 1661 1662
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
        goto endjob;
    ret = 0;
1663

1664
endjob:
1665
    if (qemuDomainObjEndJob(driver, vm) == 0)
1666
        vm = NULL;
1667

1668
cleanup:
1669 1670
    if (vm)
        virDomainObjUnlock(vm);
1671

1672
    if (event)
1673
        qemuDomainEventQueue(driver, event);
1674
    qemuDriverUnlock(driver);
1675
    return ret;
D
Daniel P. Berrange 已提交
1676 1677 1678
}


1679
static int qemudDomainResume(virDomainPtr dom) {
1680 1681 1682
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1683
    virDomainEventPtr event = NULL;
1684
    int state;
1685

1686
    qemuDriverLock(driver);
1687
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1688

D
Daniel P. Berrange 已提交
1689
    if (!vm) {
1690 1691
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1692 1693
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1694
        goto cleanup;
D
Daniel P. Berrange 已提交
1695
    }
1696

1697
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
1698 1699
        goto cleanup;

D
Daniel P. Berrange 已提交
1700
    if (!virDomainObjIsActive(vm)) {
1701 1702
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1703
        goto endjob;
D
Daniel P. Berrange 已提交
1704
    }
1705 1706 1707 1708 1709 1710 1711

    state = virDomainObjGetState(vm, NULL);
    if (state == VIR_DOMAIN_PMSUSPENDED) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is pmsuspended"));
        goto endjob;
    } else if (state == VIR_DOMAIN_PAUSED) {
J
Jiri Denemark 已提交
1712
        if (qemuProcessStartCPUs(driver, vm, dom->conn,
1713 1714
                                 VIR_DOMAIN_RUNNING_UNPAUSED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
1715
            if (virGetLastError() == NULL)
1716 1717
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("resume operation failed"));
1718
            goto endjob;
1719
        }
1720 1721 1722
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
1723
    }
1724
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
1725
        goto endjob;
1726 1727
    ret = 0;

1728
endjob:
1729
    if (qemuDomainObjEndJob(driver, vm) == 0)
1730
        vm = NULL;
1731

1732
cleanup:
1733 1734
    if (vm)
        virDomainObjUnlock(vm);
1735
    if (event)
1736
        qemuDomainEventQueue(driver, event);
1737
    qemuDriverUnlock(driver);
1738
    return ret;
D
Daniel P. Berrange 已提交
1739 1740
}

1741
static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags) {
1742 1743 1744
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1745
    qemuDomainObjPrivatePtr priv;
1746 1747 1748 1749
    bool useAgent = false;

    virCheckFlags(VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN |
                  VIR_DOMAIN_SHUTDOWN_GUEST_AGENT, -1);
1750

1751
    qemuDriverLock(driver);
1752
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
1753 1754
    qemuDriverUnlock(driver);

1755
    if (!vm) {
1756 1757
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1758 1759
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1760
        goto cleanup;
1761 1762
    }

1763 1764 1765 1766 1767 1768 1769 1770 1771
    priv = vm->privateData;

    if ((flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT) ||
        (!(flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN) &&
         priv->agent))
        useAgent = true;

    if (useAgent) {
        if (priv->agentError) {
1772 1773 1774
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                           _("QEMU guest agent is not "
                             "available due to an error"));
1775
            goto cleanup;
1776 1777
        }
        if (!priv->agent) {
1778 1779
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
1780
            goto cleanup;
1781 1782 1783
        }
    }

1784
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
1785 1786
        goto cleanup;

D
Daniel P. Berrange 已提交
1787
    if (!virDomainObjIsActive(vm)) {
1788 1789
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1790
        goto endjob;
1791 1792
    }

1793 1794 1795 1796 1797 1798
    if (useAgent) {
        qemuDomainObjEnterAgent(driver, vm);
        ret = qemuAgentShutdown(priv->agent, QEMU_AGENT_SHUTDOWN_POWERDOWN);
        qemuDomainObjExitAgent(driver, vm);
    } else {
        qemuDomainSetFakeReboot(driver, vm, false);
1799

1800 1801 1802 1803
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSystemPowerdown(priv->mon);
        qemuDomainObjExitMonitor(driver, vm);
    }
1804

1805
endjob:
1806
    if (qemuDomainObjEndJob(driver, vm) == 0)
1807
        vm = NULL;
1808

1809
cleanup:
1810 1811
    if (vm)
        virDomainObjUnlock(vm);
1812
    return ret;
1813 1814
}

1815 1816
static int qemuDomainShutdown(virDomainPtr dom)
{
1817 1818 1819
    return qemuDomainShutdownFlags(dom, 0);
}

1820

1821 1822 1823
static int
qemuDomainReboot(virDomainPtr dom, unsigned int flags)
{
1824 1825 1826 1827
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
1828
    bool useAgent = false;
1829

1830 1831
    virCheckFlags(VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN |
                  VIR_DOMAIN_SHUTDOWN_GUEST_AGENT , -1);
1832 1833 1834 1835 1836 1837 1838 1839

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1840 1841
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1842 1843 1844
        goto cleanup;
    }

1845 1846
    priv = vm->privateData;

1847 1848 1849 1850 1851 1852 1853
    if ((flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT) ||
        (!(flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN) &&
         priv->agent))
        useAgent = true;

    if (useAgent) {
        if (priv->agentError) {
1854 1855 1856
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                           _("QEMU guest agent is not "
                             "available due to an error"));
1857 1858 1859
            goto cleanup;
        }
        if (!priv->agent) {
1860 1861
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
1862 1863 1864 1865
            goto cleanup;
        }
    } else {
#if HAVE_YAJL
1866 1867
        if (qemuCapsGet(priv->caps, QEMU_CAPS_MONITOR_JSON)) {
            if (!qemuCapsGet(priv->caps, QEMU_CAPS_NO_SHUTDOWN)) {
1868 1869
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Reboot is not supported with this QEMU binary"));
1870 1871 1872 1873
                goto cleanup;
            }
        } else {
#endif
1874 1875
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Reboot is not supported without the JSON monitor"));
1876
            goto cleanup;
1877
#if HAVE_YAJL
1878
        }
1879 1880
#endif
    }
1881

1882 1883
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;
1884

1885
    if (!virDomainObjIsActive(vm)) {
1886 1887
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1888 1889
        goto endjob;
    }
1890

1891 1892 1893 1894 1895
    if (useAgent) {
        qemuDomainObjEnterAgent(driver, vm);
        ret = qemuAgentShutdown(priv->agent, QEMU_AGENT_SHUTDOWN_REBOOT);
        qemuDomainObjExitAgent(driver, vm);
    } else {
1896
        qemuDomainObjEnterMonitor(driver, vm);
1897
        ret = qemuMonitorSystemPowerdown(priv->mon);
1898
        qemuDomainObjExitMonitor(driver, vm);
1899

1900 1901
        if (ret == 0)
            qemuDomainSetFakeReboot(driver, vm, true);
1902 1903
    }

1904 1905 1906 1907
endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

1908 1909 1910 1911 1912 1913 1914
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931
static int
qemuDomainReset(virDomainPtr dom, unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1932 1933
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1934 1935 1936 1937 1938 1939 1940
        goto cleanup;
    }

    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
1941 1942
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963
        goto endjob;
    }

    priv = vm->privateData;
    qemuDomainObjEnterMonitor(driver, vm);
    ret = qemuMonitorSystemReset(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);

    priv->fakeReboot = false;

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

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


1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976
/* Count how many snapshots in a set have external disk snapshots.  */
static void
qemuDomainSnapshotCountExternal(void *payload,
                                const void *name ATTRIBUTE_UNUSED,
                                void *data)
{
    virDomainSnapshotObjPtr snap = payload;
    int *count = data;

    if (snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT)
        (*count)++;
}

1977 1978 1979 1980
static int
qemuDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
{
1981 1982 1983
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
1984
    virDomainEventPtr event = NULL;
1985
    qemuDomainObjPrivatePtr priv;
1986

1987
    virCheckFlags(VIR_DOMAIN_DESTROY_GRACEFUL, -1);
1988

1989
    qemuDriverLock(driver);
1990
    vm  = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel P. Berrange 已提交
1991
    if (!vm) {
1992 1993
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1994 1995
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1996
        goto cleanup;
D
Daniel P. Berrange 已提交
1997
    }
1998

1999 2000
    priv = vm->privateData;

2001
    qemuDomainSetFakeReboot(driver, vm, false);
2002

2003 2004 2005 2006 2007
    /* Although qemuProcessStop does this already, there may
     * be an outstanding job active. We want to make sure we
     * can kill the process even if a job is active. Killing
     * it now means the job will be released
     */
2008
    if (flags & VIR_DOMAIN_DESTROY_GRACEFUL) {
2009
        if (qemuProcessKill(driver, vm, 0) < 0) {
2010 2011
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("failed to kill qemu process with SIGTERM"));
2012 2013 2014
            goto cleanup;
        }
    } else {
2015 2016 2017 2018 2019
        if (qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_FORCE) < 0) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("failed to kill qemu process with SIGTERM"));
            goto cleanup;
        }
2020
    }
2021

2022 2023 2024 2025 2026
    /* We need to prevent monitor EOF callback from doing our work (and sending
     * misleading events) while the vm is unlocked inside BeginJob API
     */
    priv->beingDestroyed = true;

2027
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_DESTROY) < 0)
2028 2029
        goto cleanup;

2030 2031
    priv->beingDestroyed = false;

D
Daniel P. Berrange 已提交
2032
    if (!virDomainObjIsActive(vm)) {
2033 2034
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2035
        goto endjob;
2036
    }
2037

2038
    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED, 0);
2039 2040 2041
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
2042
    virDomainAuditStop(vm, "destroyed");
2043

2044
    if (!vm->persistent) {
2045
        if (qemuDomainObjEndJob(driver, vm) > 0)
2046
            qemuDomainRemoveInactive(driver, vm);
2047 2048
        vm = NULL;
    }
2049 2050
    ret = 0;

2051
endjob:
2052
    if (vm &&
2053
        qemuDomainObjEndJob(driver, vm) == 0)
2054
        vm = NULL;
2055

2056
cleanup:
2057 2058
    if (vm)
        virDomainObjUnlock(vm);
2059 2060
    if (event)
        qemuDomainEventQueue(driver, event);
2061
    qemuDriverUnlock(driver);
2062
    return ret;
D
Daniel P. Berrange 已提交
2063 2064
}

2065 2066 2067 2068 2069
static int
qemuDomainDestroy(virDomainPtr dom)
{
    return qemuDomainDestroyFlags(dom, 0);
}
D
Daniel P. Berrange 已提交
2070

2071
static char *qemudDomainGetOSType(virDomainPtr dom) {
2072 2073 2074
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *type = NULL;
2075

2076
    qemuDriverLock(driver);
2077
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2078
    qemuDriverUnlock(driver);
2079
    if (!vm) {
2080 2081
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2082 2083
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2084
        goto cleanup;
2085 2086
    }

2087
    if (!(type = strdup(vm->def->os.type)))
2088
        virReportOOMError();
2089 2090

cleanup:
2091 2092
    if (vm)
        virDomainObjUnlock(vm);
2093 2094 2095
    return type;
}

2096
/* Returns max memory in kb, 0 if error */
2097 2098 2099
static unsigned long long
qemuDomainGetMaxMemory(virDomainPtr dom)
{
2100 2101
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
2102
    unsigned long long ret = 0;
2103

2104
    qemuDriverLock(driver);
2105
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2106 2107
    qemuDriverUnlock(driver);

2108
    if (!vm) {
2109 2110
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2111 2112
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2113
        goto cleanup;
2114 2115
    }

2116
    ret = vm->def->mem.max_balloon;
2117 2118

cleanup:
2119 2120
    if (vm)
        virDomainObjUnlock(vm);
2121
    return ret;
2122 2123
}

2124 2125
static int qemudDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
                                     unsigned int flags) {
2126
    struct qemud_driver *driver = dom->conn->privateData;
2127
    qemuDomainObjPrivatePtr priv;
2128
    virDomainObjPtr vm;
2129
    virDomainDefPtr persistentDef = NULL;
2130
    int ret = -1, r;
2131

2132 2133
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
2134
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
2135

2136
    qemuDriverLock(driver);
2137
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2138
    qemuDriverUnlock(driver);
2139
    if (!vm) {
2140 2141
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2142 2143
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2144
        goto cleanup;
2145 2146
    }

2147
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
2148 2149
        goto cleanup;

2150 2151
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
2152
        goto endjob;
2153

2154 2155 2156
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
        /* resize the maximum memory */

2157
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2158 2159 2160
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot resize the maximum memory on an "
                             "active domain"));
2161
            goto endjob;
2162
        }
2163

2164
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
2165 2166
            /* Help clang 2.8 decipher the logic flow.  */
            sa_assert(persistentDef);
2167 2168 2169 2170
            persistentDef->mem.max_balloon = newmem;
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
            ret = virDomainSaveConfig(driver->configDir, persistentDef);
2171 2172 2173
            goto endjob;
        }

2174 2175 2176 2177
    } else {
        /* resize the current memory */

        if (newmem > vm->def->mem.max_balloon) {
2178 2179
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("cannot set memory higher than max memory"));
2180 2181 2182
            goto endjob;
        }

2183
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2184
            priv = vm->privateData;
2185
            qemuDomainObjEnterMonitor(driver, vm);
2186
            r = qemuMonitorSetBalloon(priv->mon, newmem);
2187
            qemuDomainObjExitMonitor(driver, vm);
2188 2189
            virDomainAuditMemory(vm, vm->def->mem.cur_balloon, newmem, "update",
                                 r == 1);
2190 2191 2192 2193 2194
            if (r < 0)
                goto endjob;

            /* Lack of balloon support is a fatal error */
            if (r == 0) {
2195 2196 2197
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("Unable to change memory of active domain without "
                                 "the balloon device and guest OS balloon driver"));
2198 2199 2200 2201
                goto endjob;
            }
        }

2202
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
2203
            sa_assert(persistentDef);
2204 2205 2206 2207
            persistentDef->mem.cur_balloon = newmem;
            ret = virDomainSaveConfig(driver->configDir, persistentDef);
            goto endjob;
        }
2208
    }
2209

2210
    ret = 0;
2211
endjob:
2212
    if (qemuDomainObjEndJob(driver, vm) == 0)
2213
        vm = NULL;
2214

2215
cleanup:
2216 2217
    if (vm)
        virDomainObjUnlock(vm);
2218
    return ret;
2219 2220
}

2221 2222
static int qemudDomainSetMemory(virDomainPtr dom, unsigned long newmem)
{
2223
    return qemudDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
2224 2225
}

2226 2227 2228 2229 2230
static int qemudDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
{
    return qemudDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
}

2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244
static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
2245 2246
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2247 2248 2249 2250
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2251 2252
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2253 2254 2255 2256 2257
        goto cleanup;
    }

    priv = vm->privateData;

2258
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
2259
        goto cleanup;
2260 2261

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

2267
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2268 2269
    ret = qemuMonitorInjectNMI(priv->mon);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2270 2271

endjob:
2272
    if (qemuDomainObjEndJob(driver, vm) == 0) {
2273 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283
        vm = NULL;
        goto cleanup;
    }

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297
static int qemuDomainSendKey(virDomainPtr domain,
                             unsigned int codeset,
                             unsigned int holdtime,
                             unsigned int *keycodes,
                             int nkeycodes,
                             unsigned int flags)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2298 2299
    /* translate the keycode to RFB for qemu driver */
    if (codeset != VIR_KEYCODE_SET_RFB) {
2300 2301 2302 2303
        int i;
        int keycode;

        for (i = 0; i < nkeycodes; i++) {
2304
            keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_RFB,
2305 2306
                                               keycodes[i]);
            if (keycode < 0) {
2307 2308 2309 2310
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot translate keycode %u of %s codeset to rfb keycode"),
                               keycodes[i],
                               virKeycodeSetTypeToString(codeset));
2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321
                return -1;
            }
            keycodes[i] = keycode;
        }
    }

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
2322 2323
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2324 2325 2326 2327 2328 2329 2330 2331 2332
        goto cleanup;
    }

    priv = vm->privateData;

    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

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

2338
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2339 2340
    ret = qemuMonitorSendKey(priv->mon, holdtime, keycodes, nkeycodes);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2341 2342 2343

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
2344 2345 2346 2347 2348 2349 2350 2351 2352
        vm = NULL;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

2353
static int qemudDomainGetInfo(virDomainPtr dom,
2354 2355
                              virDomainInfoPtr info)
{
2356 2357 2358
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
2359
    int err;
2360
    unsigned long long balloon;
2361

2362
    qemuDriverLock(driver);
2363
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
2364
    qemuDriverUnlock(driver);
D
Daniel P. Berrange 已提交
2365
    if (!vm) {
2366 2367
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2368 2369
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2370
        goto cleanup;
D
Daniel P. Berrange 已提交
2371 2372
    }

J
Jiri Denemark 已提交
2373
    info->state = virDomainObjGetState(vm, NULL);
D
Daniel P. Berrange 已提交
2374

D
Daniel P. Berrange 已提交
2375
    if (!virDomainObjIsActive(vm)) {
2376
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
2377
    } else {
2378
        if (qemudGetProcessInfo(&(info->cpuTime), NULL, NULL, vm->pid, 0) < 0) {
2379 2380
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("cannot read cputime for domain"));
2381
            goto cleanup;
D
Daniel P. Berrange 已提交
2382 2383 2384
        }
    }

2385
    info->maxMem = vm->def->mem.max_balloon;
2386

D
Daniel P. Berrange 已提交
2387
    if (virDomainObjIsActive(vm)) {
2388
        qemuDomainObjPrivatePtr priv = vm->privateData;
2389 2390 2391

        if ((vm->def->memballoon != NULL) &&
            (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
2392
            info->memory = vm->def->mem.max_balloon;
2393
        } else if (qemuCapsGet(priv->caps, QEMU_CAPS_BALLOON_EVENT)) {
2394
            info->memory = vm->def->mem.cur_balloon;
2395
        } else if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
2396
            if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
2397
                goto cleanup;
2398 2399 2400
            if (!virDomainObjIsActive(vm))
                err = 0;
            else {
2401
                qemuDomainObjEnterMonitor(driver, vm);
2402
                err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
2403
                qemuDomainObjExitMonitor(driver, vm);
2404
            }
2405
            if (qemuDomainObjEndJob(driver, vm) == 0) {
2406
                vm = NULL;
2407 2408 2409
                goto cleanup;
            }

2410 2411 2412 2413 2414 2415 2416
            if (err < 0) {
                /* We couldn't get current memory allocation but that's not
                 * a show stopper; we wouldn't get it if there was a job
                 * active either
                 */
                info->memory = vm->def->mem.cur_balloon;
            } else if (err == 0) {
2417
                /* Balloon not supported, so maxmem is always the allocation */
2418
                info->memory = vm->def->mem.max_balloon;
2419
            } else {
2420
                info->memory = balloon;
2421
            }
2422
        } else {
2423
            info->memory = vm->def->mem.cur_balloon;
2424
        }
2425
    } else {
2426
        info->memory = vm->def->mem.cur_balloon;
2427 2428
    }

2429
    info->nrVirtCpu = vm->def->vcpus;
2430 2431 2432
    ret = 0;

cleanup:
2433 2434
    if (vm)
        virDomainObjUnlock(vm);
2435
    return ret;
D
Daniel P. Berrange 已提交
2436 2437
}

2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456
static int
qemuDomainGetState(virDomainPtr dom,
                   int *state,
                   int *reason,
                   unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2457 2458
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2459 2460 2461
        goto cleanup;
    }

J
Jiri Denemark 已提交
2462
    *state = virDomainObjGetState(vm, reason);
2463 2464 2465 2466 2467 2468 2469 2470
    ret = 0;

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

2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489
static int
qemuDomainGetControlInfo(virDomainPtr dom,
                          virDomainControlInfoPtr info,
                          unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2490 2491
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2492 2493 2494 2495
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2496 2497
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2498 2499 2500 2501 2502 2503 2504 2505 2506
        goto cleanup;
    }

    priv = vm->privateData;

    memset(info, 0, sizeof(*info));

    if (priv->monError) {
        info->state = VIR_DOMAIN_CONTROL_ERROR;
2507
    } else if (priv->job.active) {
2508 2509
        if (!priv->monStart) {
            info->state = VIR_DOMAIN_CONTROL_JOB;
2510
            if (virTimeMillisNow(&info->stateTime) < 0)
2511
                goto cleanup;
2512
            info->stateTime -= priv->job.start;
2513 2514
        } else {
            info->state = VIR_DOMAIN_CONTROL_OCCUPIED;
2515
            if (virTimeMillisNow(&info->stateTime) < 0)
2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530
                goto cleanup;
            info->stateTime -= priv->monStart;
        }
    } else {
        info->state = VIR_DOMAIN_CONTROL_OK;
    }

    ret = 0;

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

D
Daniel P. Berrange 已提交
2531

E
Eric Blake 已提交
2532 2533
#define QEMUD_SAVE_MAGIC   "LibvirtQemudSave"
#define QEMUD_SAVE_PARTIAL "LibvirtQemudPart"
2534 2535
#define QEMUD_SAVE_VERSION 2

E
Eric Blake 已提交
2536 2537
verify(sizeof(QEMUD_SAVE_MAGIC) == sizeof(QEMUD_SAVE_PARTIAL));

2538
enum qemud_save_formats {
2539 2540 2541
    QEMUD_SAVE_FORMAT_RAW = 0,
    QEMUD_SAVE_FORMAT_GZIP = 1,
    QEMUD_SAVE_FORMAT_BZIP2 = 2,
2542 2543
    /*
     * Deprecated by xz and never used as part of a release
2544
     * QEMUD_SAVE_FORMAT_LZMA
2545 2546
     */
    QEMUD_SAVE_FORMAT_XZ = 3,
2547
    QEMUD_SAVE_FORMAT_LZOP = 4,
2548 2549 2550
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
2551 2552

    QEMUD_SAVE_FORMAT_LAST
2553
};
2554

2555 2556 2557 2558 2559
VIR_ENUM_DECL(qemudSaveCompression)
VIR_ENUM_IMPL(qemudSaveCompression, QEMUD_SAVE_FORMAT_LAST,
              "raw",
              "gzip",
              "bzip2",
2560 2561
              "xz",
              "lzop")
2562

2563 2564
struct qemud_save_header {
    char magic[sizeof(QEMUD_SAVE_MAGIC)-1];
2565 2566 2567 2568 2569
    uint32_t version;
    uint32_t xml_len;
    uint32_t was_running;
    uint32_t compressed;
    uint32_t unused[15];
2570 2571
};

2572 2573 2574 2575 2576 2577 2578 2579 2580
static inline void
bswap_header(struct qemud_save_header *hdr) {
    hdr->version = bswap_32(hdr->version);
    hdr->xml_len = bswap_32(hdr->xml_len);
    hdr->was_running = bswap_32(hdr->was_running);
    hdr->compressed = bswap_32(hdr->compressed);
}


2581
/* return -errno on failure, or 0 on success */
E
Eric Blake 已提交
2582 2583 2584 2585
static int
qemuDomainSaveHeader(int fd, const char *path, char *xml,
                     struct qemud_save_header *header)
{
2586 2587
    int ret = 0;

E
Eric Blake 已提交
2588
    if (safewrite(fd, header, sizeof(*header)) != sizeof(*header)) {
2589
        ret = -errno;
2590 2591 2592
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to write header to domain save file '%s'"),
                       path);
2593 2594 2595
        goto endjob;
    }

E
Eric Blake 已提交
2596
    if (safewrite(fd, xml, header->xml_len) != header->xml_len) {
2597
        ret = -errno;
2598 2599
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to write xml to '%s'"), path);
2600 2601 2602 2603 2604 2605
        goto endjob;
    }
endjob:
    return ret;
}

2606 2607 2608 2609 2610 2611 2612 2613 2614
/* Given a enum qemud_save_formats compression level, return the name
 * of the program to run, or NULL if no program is needed.  */
static const char *
qemuCompressProgramName(int compress)
{
    return (compress == QEMUD_SAVE_FORMAT_RAW ? NULL :
            qemudSaveCompressionTypeToString(compress));
}

E
Eric Blake 已提交
2615 2616 2617 2618 2619 2620 2621 2622 2623 2624
/* Internal function to properly create or open existing files, with
 * ownership affected by qemu driver setup.  */
static int
qemuOpenFile(struct qemud_driver *driver, const char *path, int oflags,
             bool *needUnlink, bool *bypassSecurityDriver)
{
    struct stat sb;
    bool is_reg = true;
    bool need_unlink = false;
    bool bypass_security = false;
L
Laine Stump 已提交
2625
    unsigned int vfoflags = 0;
E
Eric Blake 已提交
2626
    int fd = -1;
2627
    int path_shared = virStorageFileIsSharedFS(path);
E
Eric Blake 已提交
2628 2629 2630 2631 2632 2633 2634 2635
    uid_t uid = getuid();
    gid_t gid = getgid();

    /* path might be a pre-existing block dev, in which case
     * we need to skip the create step, and also avoid unlink
     * in the failure case */
    if (oflags & O_CREAT) {
        need_unlink = true;
2636 2637 2638 2639 2640 2641

        /* Don't force chown on network-shared FS
         * as it is likely to fail. */
        if (path_shared <= 0 || driver->dynamicOwnership)
            vfoflags |= VIR_FILE_OPEN_FORCE_OWNER;

E
Eric Blake 已提交
2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661
        if (stat(path, &sb) == 0) {
            is_reg = !!S_ISREG(sb.st_mode);
            /* If the path is regular file which exists
             * already and dynamic_ownership is off, we don't
             * want to change it's ownership, just open it as-is */
            if (is_reg && !driver->dynamicOwnership) {
                uid = sb.st_uid;
                gid = sb.st_gid;
            }
        }
    }

    /* First try creating the file as root */
    if (!is_reg) {
        fd = open(path, oflags & ~O_CREAT);
        if (fd < 0) {
            virReportSystemError(errno, _("unable to open %s"), path);
            goto cleanup;
        }
    } else {
L
Laine Stump 已提交
2662 2663
        if ((fd = virFileOpenAs(path, oflags, S_IRUSR | S_IWUSR, uid, gid,
                                vfoflags | VIR_FILE_OPEN_NOFORK)) < 0) {
E
Eric Blake 已提交
2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678
            /* If we failed as root, and the error was permission-denied
               (EACCES or EPERM), assume it's on a network-connected share
               where root access is restricted (eg, root-squashed NFS). If the
               qemu user (driver->user) is non-root, just set a flag to
               bypass security driver shenanigans, and retry the operation
               after doing setuid to qemu user */
            if ((fd != -EACCES && fd != -EPERM) ||
                driver->user == getuid()) {
                virReportSystemError(-fd,
                                     _("Failed to create file '%s'"),
                                     path);
                goto cleanup;
            }

            /* On Linux we can also verify the FS-type of the directory. */
2679
            switch (path_shared) {
E
Eric Blake 已提交
2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706
                case 1:
                   /* it was on a network share, so we'll continue
                    * as outlined above
                    */
                   break;

                case -1:
                   virReportSystemError(errno,
                                        _("Failed to create file "
                                          "'%s': couldn't determine fs type"),
                                        path);
                   goto cleanup;

                case 0:
                default:
                   /* local file - log the error returned by virFileOpenAs */
                   virReportSystemError(-fd,
                                        _("Failed to create file '%s'"),
                                        path);
                   goto cleanup;
            }

            /* Retry creating the file as driver->user */

            if ((fd = virFileOpenAs(path, oflags,
                                    S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
                                    driver->user, driver->group,
L
Laine Stump 已提交
2707
                                    vfoflags | VIR_FILE_OPEN_FORK)) < 0) {
E
Eric Blake 已提交
2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729
                virReportSystemError(-fd,
                                   _("Error from child process creating '%s'"),
                                     path);
                goto cleanup;
            }

            /* Since we had to setuid to create the file, and the fstype
               is NFS, we assume it's a root-squashing NFS share, and that
               the security driver stuff would have failed anyway */

            bypass_security = true;
        }
    }
cleanup:
    if (needUnlink)
        *needUnlink = need_unlink;
    if (bypassSecurityDriver)
        *bypassSecurityDriver = bypass_security;

    return fd;
}

2730
/* This internal function expects the driver lock to already be held on
2731 2732 2733 2734
 * entry and the vm must be active + locked. Vm will be unlocked and
 * potentially free'd after this returns (eg transient VMs are freed
 * shutdown). So 'vm' must not be referenced by the caller after
 * this returns (whether returning success or failure).
2735
 */
2736 2737 2738
static int
qemuDomainSaveInternal(struct qemud_driver *driver, virDomainPtr dom,
                       virDomainObjPtr vm, const char *path,
2739
                       int compressed, const char *xmlin, unsigned int flags)
2740
{
2741
    char *xml = NULL;
2742
    struct qemud_save_header header;
2743
    bool bypassSecurityDriver = false;
2744
    int ret = -1;
2745
    int rc;
2746
    virDomainEventPtr event = NULL;
2747
    qemuDomainObjPrivatePtr priv;
E
Eric Blake 已提交
2748
    bool needUnlink = false;
2749
    size_t len;
2750
    unsigned long long offset;
2751
    unsigned long long pad;
2752
    int fd = -1;
2753
    int directFlag = 0;
J
Jiri Denemark 已提交
2754
    virFileWrapperFdPtr wrapperFd = NULL;
2755
    unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
2756

2757
    if (qemuProcessAutoDestroyActive(driver, vm)) {
2758 2759
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is marked for auto destroy"));
2760
        goto cleanup;
2761 2762
    }

2763
    memset(&header, 0, sizeof(header));
E
Eric Blake 已提交
2764
    memcpy(header.magic, QEMUD_SAVE_PARTIAL, sizeof(header.magic));
2765 2766
    header.version = QEMUD_SAVE_VERSION;

2767
    header.compressed = compressed;
2768

2769
    priv = vm->privateData;
2770

2771 2772
    if (qemuDomainObjBeginAsyncJobWithDriver(driver, vm,
                                             QEMU_ASYNC_JOB_SAVE) < 0)
2773 2774
        goto cleanup;

2775 2776
    memset(&priv->job.info, 0, sizeof(priv->job.info));
    priv->job.info.type = VIR_DOMAIN_JOB_UNBOUNDED;
2777

2778
    /* Pause */
J
Jiri Denemark 已提交
2779
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
2780
        header.was_running = 1;
2781 2782
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_SAVE) < 0)
2783
            goto endjob;
2784 2785

        if (!virDomainObjIsActive(vm)) {
2786 2787
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
2788 2789
            goto endjob;
        }
2790
    }
2791 2792 2793 2794 2795
    /* libvirt.c already guaranteed these two flags are exclusive.  */
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        header.was_running = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        header.was_running = 0;
2796

2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812
    /* Get XML for the domain.  Restore needs only the inactive xml,
     * including secure.  We should get the same result whether xmlin
     * is NULL or whether it was the live xml of the domain moments
     * before.  */
    if (xmlin) {
        virDomainDefPtr def = NULL;

        if (!(def = virDomainDefParseString(driver->caps, xmlin,
                                            QEMU_EXPECTED_VIRT_TYPES,
                                            VIR_DOMAIN_XML_INACTIVE))) {
            goto endjob;
        }
        if (!virDomainDefCheckABIStability(vm->def, def)) {
            virDomainDefFree(def);
            goto endjob;
        }
2813
        xml = qemuDomainDefFormatLive(driver, def, true, true);
2814
    } else {
2815
        xml = qemuDomainDefFormatLive(driver, vm->def, true, true);
2816
    }
2817
    if (!xml) {
2818 2819
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to get domain xml"));
2820
        goto endjob;
2821
    }
2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841
    len = strlen(xml) + 1;
    offset = sizeof(header) + len;

    /* Due to way we append QEMU state on our header with dd,
     * we need to ensure there's a 512 byte boundary. Unfortunately
     * we don't have an explicit offset in the header, so we fake
     * it by padding the XML string with NUL bytes.  Additionally,
     * we want to ensure that virDomainSaveImageDefineXML can supply
     * slightly larger XML, so we add a miminum padding prior to
     * rounding out to page boundaries.
     */
    pad = 1024;
    pad += (QEMU_MONITOR_MIGRATE_TO_FILE_BS -
            ((offset + pad) % QEMU_MONITOR_MIGRATE_TO_FILE_BS));
    if (VIR_EXPAND_N(xml, len, pad) < 0) {
        virReportOOMError();
        goto endjob;
    }
    offset += pad;
    header.xml_len = len;
2842

2843
    /* Obtain the file handle.  */
2844 2845
    if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE)) {
        wrapperFlags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
2846 2847
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
2848 2849
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
E
Eric Blake 已提交
2850
            goto cleanup;
2851
        }
2852
    }
E
Eric Blake 已提交
2853 2854 2855 2856
    fd = qemuOpenFile(driver, path, O_WRONLY | O_TRUNC | O_CREAT | directFlag,
                      &needUnlink, &bypassSecurityDriver);
    if (fd < 0)
        goto endjob;
2857
    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, wrapperFlags)))
2858 2859
        goto endjob;

2860
    /* Write header to file, followed by XML */
E
Eric Blake 已提交
2861
    if (qemuDomainSaveHeader(fd, path, xml, &header) < 0) {
2862 2863 2864 2865
        VIR_FORCE_CLOSE(fd);
        goto endjob;
    }

2866
    /* Perform the migration */
2867
    if (qemuMigrationToFile(driver, vm, fd, offset, path,
2868
                            qemuCompressProgramName(compressed),
E
Eric Blake 已提交
2869
                            bypassSecurityDriver,
2870
                            QEMU_ASYNC_JOB_SAVE) < 0)
2871
        goto endjob;
E
Eric Blake 已提交
2872

2873 2874 2875 2876 2877 2878 2879 2880 2881
    /* Touch up file header to mark image complete. */

    /* Reopen the file to touch up the header, since we aren't set
     * up to seek backwards on wrapperFd.  The reopened fd will
     * trigger a single page of file system cache pollution, but
     * that's acceptable.  */
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("unable to close %s"), path);
        goto endjob;
E
Eric Blake 已提交
2882
    }
2883 2884 2885 2886 2887 2888
    if (virFileWrapperFdClose(wrapperFd) < 0)
        goto endjob;
    fd = qemuOpenFile(driver, path, O_WRONLY, NULL, NULL);
    if (fd < 0)
        goto endjob;

E
Eric Blake 已提交
2889 2890 2891 2892 2893
    memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic));
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
        virReportSystemError(errno, _("unable to write %s"), path);
        goto endjob;
    }
2894 2895
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("unable to close %s"), path);
2896
        goto endjob;
2897 2898
    }

2899 2900
    ret = 0;

2901
    /* Shut it down */
2902
    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SAVED, 0);
2903
    virDomainAuditStop(vm, "saved");
2904 2905 2906
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
2907
    if (!vm->persistent) {
2908
        if (qemuDomainObjEndAsyncJob(driver, vm) > 0)
2909
            qemuDomainRemoveInactive(driver, vm);
2910 2911
        vm = NULL;
    }
2912

2913
endjob:
2914
    if (vm) {
2915
        if (ret != 0) {
2916
            if (header.was_running && virDomainObjIsActive(vm)) {
J
Jiri Denemark 已提交
2917
                rc = qemuProcessStartCPUs(driver, vm, dom->conn,
2918 2919
                                          VIR_DOMAIN_RUNNING_SAVE_CANCELED,
                                          QEMU_ASYNC_JOB_SAVE);
2920
                if (rc < 0)
2921
                    VIR_WARN("Unable to resume guest CPUs after save failure");
2922
            }
2923
        }
2924
        if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
2925
            vm = NULL;
2926
    }
2927

2928
cleanup:
2929
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
2930
    virFileWrapperFdFree(wrapperFd);
2931
    VIR_FREE(xml);
E
Eric Blake 已提交
2932
    if (ret != 0 && needUnlink)
2933
        unlink(path);
2934 2935
    if (event)
        qemuDomainEventQueue(driver, event);
2936 2937
    if (vm)
        virDomainObjUnlock(vm);
2938
    return ret;
D
Daniel P. Berrange 已提交
2939 2940
}

2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956
/* Returns true if a compression program is available in PATH */
static bool qemudCompressProgramAvailable(enum qemud_save_formats compress)
{
    const char *prog;
    char *c;

    if (compress == QEMUD_SAVE_FORMAT_RAW)
        return true;
    prog = qemudSaveCompressionTypeToString(compress);
    c = virFindFileInPath(prog);
    if (!c)
        return false;
    VIR_FREE(c);
    return true;
}

2957 2958 2959
static int
qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
                    unsigned int flags)
2960 2961 2962
{
    struct qemud_driver *driver = dom->conn->privateData;
    int compressed;
2963 2964 2965
    int ret = -1;
    virDomainObjPtr vm = NULL;

2966 2967 2968
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
2969

2970
    qemuDriverLock(driver);
2971 2972 2973 2974 2975 2976

    if (driver->saveImageFormat == NULL)
        compressed = QEMUD_SAVE_FORMAT_RAW;
    else {
        compressed = qemudSaveCompressionTypeFromString(driver->saveImageFormat);
        if (compressed < 0) {
2977 2978 2979
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Invalid save image format specified "
                                   "in configuration file"));
2980
            goto cleanup;
2981
        }
2982
        if (!qemudCompressProgramAvailable(compressed)) {
2983 2984 2985
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Compression program for image format "
                                   "in configuration file isn't available"));
2986
            goto cleanup;
2987
        }
2988 2989
    }

2990 2991 2992 2993
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2994 2995
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2996 2997 2998
        goto cleanup;
    }

2999
    if (!virDomainObjIsActive(vm)) {
3000 3001
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3002 3003 3004
        goto cleanup;
    }

3005
    ret = qemuDomainSaveInternal(driver, dom, vm, path, compressed,
3006
                                 dxml, flags);
3007
    vm = NULL;
3008 3009 3010 3011 3012 3013 3014

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);

    return ret;
3015 3016
}

3017 3018 3019 3020 3021 3022
static int
qemuDomainSave(virDomainPtr dom, const char *path)
{
    return qemuDomainSaveFlags(dom, path, NULL, 0);
}

3023 3024 3025 3026 3027 3028
static char *
qemuDomainManagedSavePath(struct qemud_driver *driver, virDomainObjPtr vm) {
    char *ret;

    if (virAsprintf(&ret, "%s/%s.save", driver->saveDir, vm->def->name) < 0) {
        virReportOOMError();
3029
        return NULL;
3030 3031
    }

3032
    return ret;
3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043
}

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

3044 3045 3046
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
3047 3048 3049 3050 3051 3052

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3053 3054
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
3055
        goto cleanup;
3056 3057
    }

3058
    if (!virDomainObjIsActive(vm)) {
3059 3060
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3061 3062
        goto cleanup;
    }
3063
    if (!vm->persistent) {
3064 3065
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot do managed save for transient domain"));
3066 3067
        goto cleanup;
    }
3068

3069 3070
    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
3071
        goto cleanup;
3072

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

    compressed = QEMUD_SAVE_FORMAT_RAW;
3076 3077 3078 3079
    if ((ret = qemuDomainSaveInternal(driver, dom, vm, name, compressed,
                                      NULL, flags)) == 0)
        vm->hasManagedSave = true;

3080
    vm = NULL;
3081 3082 3083 3084 3085

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
3086 3087 3088
    VIR_FREE(name);

    return ret;
3089 3090
}

3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111
static void
qemuDomainManagedSaveLoad(void *payload,
                          const void *n ATTRIBUTE_UNUSED,
                          void *opaque)
{
    virDomainObjPtr vm = payload;
    struct qemud_driver *driver = opaque;
    char *name;

    virDomainObjLock(vm);

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

    vm->hasManagedSave = virFileExists(name);

cleanup:
    virDomainObjUnlock(vm);
    VIR_FREE(name);
}

3112 3113 3114 3115 3116 3117 3118
static int
qemuDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;

3119
    virCheckFlags(0, -1);
3120 3121 3122 3123 3124 3125

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3126 3127
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
3128 3129 3130
        goto cleanup;
    }

3131
    ret = vm->hasManagedSave;
3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

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

3148
    virCheckFlags(0, -1);
3149 3150 3151 3152 3153 3154

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3155 3156
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
3157 3158 3159 3160 3161 3162 3163 3164
        goto cleanup;
    }

    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    ret = unlink(name);
3165
    vm->hasManagedSave = false;
3166 3167 3168 3169 3170 3171 3172 3173

cleanup:
    VIR_FREE(name);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
D
Daniel P. Berrange 已提交
3174

3175 3176 3177 3178 3179 3180
static int qemuDumpToFd(struct qemud_driver *driver, virDomainObjPtr vm,
                        int fd, enum qemuDomainAsyncJob asyncJob)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;

3181
    if (!qemuCapsGet(priv->caps, QEMU_CAPS_DUMP_GUEST_MEMORY)) {
3182 3183
        virReportError(VIR_ERR_NO_SUPPORT, "%s",
                       _("dump-guest-memory is not supported"));
3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195
        return -1;
    }

    if (virSecurityManagerSetImageFDLabel(driver->securityManager, vm->def,
                                          fd) < 0)
        return -1;

    priv->job.dump_memory_only = true;

    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        return -1;

3196
    ret = qemuMonitorDumpToFd(priv->mon, fd);
3197 3198 3199 3200 3201
    qemuDomainObjExitMonitorWithDriver(driver, vm);

    return ret;
}

3202 3203 3204 3205
static int
doCoreDump(struct qemud_driver *driver,
           virDomainObjPtr vm,
           const char *path,
3206
           enum qemud_save_formats compress,
3207
           unsigned int dump_flags)
H
Hu Tao 已提交
3208 3209 3210
{
    int fd = -1;
    int ret = -1;
J
Jiri Denemark 已提交
3211
    virFileWrapperFdPtr wrapperFd = NULL;
3212
    int directFlag = 0;
3213
    unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
H
Hu Tao 已提交
3214 3215

    /* Create an empty file with appropriate ownership.  */
3216
    if (dump_flags & VIR_DUMP_BYPASS_CACHE) {
3217
        flags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
3218 3219
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
3220 3221
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
3222 3223 3224
            goto cleanup;
        }
    }
E
Eric Blake 已提交
3225 3226 3227 3228 3229 3230
    /* Core dumps usually imply last-ditch analysis efforts are
     * desired, so we intentionally do not unlink even if a file was
     * created.  */
    if ((fd = qemuOpenFile(driver, path,
                           O_CREAT | O_TRUNC | O_WRONLY | directFlag,
                           NULL, NULL)) < 0)
H
Hu Tao 已提交
3231 3232
        goto cleanup;

3233
    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, flags)))
3234 3235
        goto cleanup;

3236 3237 3238 3239 3240 3241 3242 3243 3244
    if (dump_flags & VIR_DUMP_MEMORY_ONLY) {
        ret = qemuDumpToFd(driver, vm, fd, QEMU_ASYNC_JOB_DUMP);
    } else {
        ret = qemuMigrationToFile(driver, vm, fd, 0, path,
                                  qemuCompressProgramName(compress), false,
                                  QEMU_ASYNC_JOB_DUMP);
    }

    if (ret < 0)
3245 3246
        goto cleanup;

H
Hu Tao 已提交
3247 3248
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno,
3249
                             _("unable to close file %s"),
H
Hu Tao 已提交
3250 3251 3252
                             path);
        goto cleanup;
    }
J
Jiri Denemark 已提交
3253
    if (virFileWrapperFdClose(wrapperFd) < 0)
3254
        goto cleanup;
H
Hu Tao 已提交
3255

3256
    ret = 0;
H
Hu Tao 已提交
3257 3258

cleanup:
3259
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
3260
    virFileWrapperFdFree(wrapperFd);
H
Hu Tao 已提交
3261 3262 3263 3264 3265
    if (ret != 0)
        unlink(path);
    return ret;
}

3266 3267 3268 3269 3270
static enum qemud_save_formats
getCompressionType(struct qemud_driver *driver)
{
    int compress = QEMUD_SAVE_FORMAT_RAW;

3271 3272 3273 3274 3275 3276
    /*
     * We reuse "save" flag for "dump" here. Then, we can support the same
     * format in "save" and "dump".
     */
    if (driver->dumpImageFormat) {
        compress = qemudSaveCompressionTypeFromString(driver->dumpImageFormat);
3277 3278 3279
        /* Use "raw" as the format if the specified format is not valid,
         * or the compress program is not available.
         */
3280
        if (compress < 0) {
3281 3282
            VIR_WARN("%s", _("Invalid dump image format specified in "
                             "configuration file, using raw"));
3283
            return QEMUD_SAVE_FORMAT_RAW;
3284
        }
3285
        if (!qemudCompressProgramAvailable(compress)) {
3286 3287 3288
            VIR_WARN("%s", _("Compression program for dump image format "
                             "in configuration file isn't available, "
                             "using raw"));
3289
            return QEMUD_SAVE_FORMAT_RAW;
3290
        }
3291
    }
3292 3293 3294 3295 3296
    return compress;
}

static int qemudDomainCoreDump(virDomainPtr dom,
                               const char *path,
3297
                               unsigned int flags)
3298
{
3299 3300
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
M
Michal Privoznik 已提交
3301
    qemuDomainObjPrivatePtr priv;
3302
    int resume = 0, paused = 0;
H
Hu Tao 已提交
3303
    int ret = -1;
3304 3305
    virDomainEventPtr event = NULL;

M
Michal Privoznik 已提交
3306
    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH |
3307 3308
                  VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET |
                  VIR_DUMP_MEMORY_ONLY, -1);
3309

P
Paolo Bonzini 已提交
3310 3311 3312 3313 3314 3315
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3316 3317
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
P
Paolo Bonzini 已提交
3318 3319 3320
        goto cleanup;
    }

3321 3322
    if (qemuDomainObjBeginAsyncJobWithDriver(driver, vm,
                                             QEMU_ASYNC_JOB_DUMP) < 0)
3323 3324
        goto cleanup;

D
Daniel P. Berrange 已提交
3325
    if (!virDomainObjIsActive(vm)) {
3326 3327
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3328
        goto endjob;
P
Paolo Bonzini 已提交
3329 3330
    }

P
Paolo Bonzini 已提交
3331 3332
    /* Migrate will always stop the VM, so the resume condition is
       independent of whether the stop command is issued.  */
J
Jiri Denemark 已提交
3333
    resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
P
Paolo Bonzini 已提交
3334 3335

    /* Pause domain for non-live dump */
J
Jiri Denemark 已提交
3336 3337
    if (!(flags & VIR_DUMP_LIVE) &&
        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
3338 3339
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_DUMP,
                                QEMU_ASYNC_JOB_DUMP) < 0)
3340
            goto endjob;
P
Paolo Bonzini 已提交
3341
        paused = 1;
3342 3343

        if (!virDomainObjIsActive(vm)) {
3344 3345
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
3346 3347
            goto endjob;
        }
P
Paolo Bonzini 已提交
3348 3349
    }

3350
    ret = doCoreDump(driver, vm, path, getCompressionType(driver), flags);
3351 3352 3353 3354
    if (ret < 0)
        goto endjob;

    paused = 1;
3355 3356

endjob:
3357
    if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
3358
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED, 0);
3359
        virDomainAuditStop(vm, "crashed");
3360 3361 3362 3363 3364
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
    }

P
Paolo Bonzini 已提交
3365 3366 3367
    /* Since the monitor is always attached to a pty for libvirt, it
       will support synchronous operations so we always get here after
       the migration is complete.  */
M
Michal Privoznik 已提交
3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379
    else if (((resume && paused) || (flags & VIR_DUMP_RESET)) &&
             virDomainObjIsActive(vm)) {
        if ((ret == 0) && (flags & VIR_DUMP_RESET)) {
            priv =  vm->privateData;
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
            ret = qemuMonitorSystemReset(priv->mon);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
        }

        if (resume && qemuProcessStartCPUs(driver, vm, dom->conn,
                                           VIR_DOMAIN_RUNNING_UNPAUSED,
                                           QEMU_ASYNC_JOB_DUMP) < 0) {
3380
            if (virGetLastError() == NULL)
3381 3382
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
3383 3384
        }
    }
3385

3386
    if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
3387
        vm = NULL;
3388
    else if ((ret == 0) && (flags & VIR_DUMP_CRASH) && !vm->persistent) {
3389
        qemuDomainRemoveInactive(driver, vm);
3390 3391
        vm = NULL;
    }
3392 3393

cleanup:
P
Paolo Bonzini 已提交
3394 3395
    if (vm)
        virDomainObjUnlock(vm);
3396 3397
    if (event)
        qemuDomainEventQueue(driver, event);
3398
    qemuDriverUnlock(driver);
P
Paolo Bonzini 已提交
3399 3400 3401
    return ret;
}

3402 3403 3404 3405
static char *
qemuDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
3406
                     unsigned int flags)
3407 3408 3409 3410 3411 3412 3413
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    char *tmp = NULL;
    int tmp_fd = -1;
    char *ret = NULL;
E
Eric Blake 已提交
3414
    bool unlink_tmp = false;
3415

E
Eric Blake 已提交
3416 3417
    virCheckFlags(0, NULL);

3418 3419 3420 3421 3422 3423 3424
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3425 3426
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain matching uuid '%s'"), uuidstr);
3427 3428 3429 3430 3431
        goto cleanup;
    }

    priv = vm->privateData;

3432
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
3433 3434 3435
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
3436 3437
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3438 3439 3440 3441 3442 3443
        goto endjob;
    }

    /* Well, even if qemu allows multiple graphic cards, heads, whatever,
     * screenshot command does not */
    if (screen) {
3444 3445 3446
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("currently is supported only taking "
                               "screenshots of screen ID 0"));
3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458
        goto endjob;
    }

    if (virAsprintf(&tmp, "%s/qemu.screendump.XXXXXX", driver->cacheDir) < 0) {
        virReportOOMError();
        goto endjob;
    }

    if ((tmp_fd = mkstemp(tmp)) == -1) {
        virReportSystemError(errno, _("mkstemp(\"%s\") failed"), tmp);
        goto endjob;
    }
E
Eric Blake 已提交
3459
    unlink_tmp = true;
3460

3461
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
3462

3463
    qemuDomainObjEnterMonitor(driver, vm);
3464
    if (qemuMonitorScreendump(priv->mon, tmp) < 0) {
3465
        qemuDomainObjExitMonitor(driver, vm);
3466 3467
        goto endjob;
    }
3468
    qemuDomainObjExitMonitor(driver, vm);
3469 3470 3471 3472 3473 3474

    if (VIR_CLOSE(tmp_fd) < 0) {
        virReportSystemError(errno, _("unable to close %s"), tmp);
        goto endjob;
    }

E
Eric Blake 已提交
3475
    if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
3476 3477
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to open stream"));
3478 3479 3480 3481 3482 3483 3484
        goto endjob;
    }

    ret = strdup("image/x-portable-pixmap");

endjob:
    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
3485 3486
    if (unlink_tmp)
        unlink(tmp);
E
Eric Blake 已提交
3487
    VIR_FREE(tmp);
3488

3489
    if (qemuDomainObjEndJob(driver, vm) == 0)
3490 3491 3492 3493 3494 3495 3496 3497
        vm = NULL;

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

H
Hu Tao 已提交
3498 3499 3500
static void processWatchdogEvent(void *data, void *opaque)
{
    int ret;
3501
    struct qemuDomainWatchdogEvent *wdEvent = data;
H
Hu Tao 已提交
3502 3503
    struct qemud_driver *driver = opaque;

W
Wen Congyang 已提交
3504 3505 3506
    qemuDriverLock(driver);
    virDomainObjLock(wdEvent->vm);

H
Hu Tao 已提交
3507 3508 3509 3510
    switch (wdEvent->action) {
    case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
        {
            char *dumpfile;
3511
            unsigned int flags = 0;
H
Hu Tao 已提交
3512

E
Eric Blake 已提交
3513
            if (virAsprintf(&dumpfile, "%s/%s-%u",
H
Hu Tao 已提交
3514 3515
                            driver->autoDumpPath,
                            wdEvent->vm->def->name,
E
Eric Blake 已提交
3516 3517
                            (unsigned int)time(NULL)) < 0) {
                virReportOOMError();
W
Wen Congyang 已提交
3518
                goto unlock;
E
Eric Blake 已提交
3519
            }
H
Hu Tao 已提交
3520

3521 3522
            if (qemuDomainObjBeginAsyncJobWithDriver(driver, wdEvent->vm,
                                                     QEMU_ASYNC_JOB_DUMP) < 0) {
W
Wen Congyang 已提交
3523 3524 3525
                VIR_FREE(dumpfile);
                goto unlock;
            }
H
Hu Tao 已提交
3526 3527

            if (!virDomainObjIsActive(wdEvent->vm)) {
3528 3529
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("domain is not running"));
W
Wen Congyang 已提交
3530 3531
                VIR_FREE(dumpfile);
                goto endjob;
H
Hu Tao 已提交
3532 3533
            }

3534
            flags |= driver->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0;
3535
            ret = doCoreDump(driver, wdEvent->vm, dumpfile,
3536
                             getCompressionType(driver), flags);
H
Hu Tao 已提交
3537
            if (ret < 0)
3538 3539
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Dump failed"));
H
Hu Tao 已提交
3540

J
Jiri Denemark 已提交
3541
            ret = qemuProcessStartCPUs(driver, wdEvent->vm, NULL,
3542 3543
                                       VIR_DOMAIN_RUNNING_UNPAUSED,
                                       QEMU_ASYNC_JOB_DUMP);
H
Hu Tao 已提交
3544 3545

            if (ret < 0)
3546 3547
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Resuming after dump failed"));
H
Hu Tao 已提交
3548 3549 3550 3551

            VIR_FREE(dumpfile);
        }
        break;
W
Wen Congyang 已提交
3552 3553
    default:
        goto unlock;
H
Hu Tao 已提交
3554 3555
    }

W
Wen Congyang 已提交
3556 3557 3558 3559
endjob:
    /* Safe to ignore value since ref count was incremented in
     * qemuProcessHandleWatchdog().
     */
3560
    ignore_value(qemuDomainObjEndAsyncJob(driver, wdEvent->vm));
W
Wen Congyang 已提交
3561 3562

unlock:
3563 3564
    virDomainObjUnlock(wdEvent->vm);
    virObjectUnref(wdEvent->vm);
W
Wen Congyang 已提交
3565
    qemuDriverUnlock(driver);
H
Hu Tao 已提交
3566 3567
    VIR_FREE(wdEvent);
}
P
Paolo Bonzini 已提交
3568

3569 3570 3571
static int qemudDomainHotplugVcpus(struct qemud_driver *driver,
                                   virDomainObjPtr vm,
                                   unsigned int nvcpus)
3572 3573
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
3574
    int i, rc = 1;
3575
    int ret = -1;
3576
    int oldvcpus = vm->def->vcpus;
E
Eric Blake 已提交
3577
    int vcpus = oldvcpus;
3578 3579
    pid_t *cpupids = NULL;
    int ncpupids;
3580

3581
    qemuDomainObjEnterMonitor(driver, vm);
3582

3583 3584 3585
    /* We need different branches here, because we want to offline
     * in reverse order to onlining, so any partial fail leaves us in a
     * reasonably sensible state */
E
Eric Blake 已提交
3586 3587
    if (nvcpus > vcpus) {
        for (i = vcpus ; i < nvcpus ; i++) {
3588 3589 3590 3591 3592 3593 3594
            /* Online new CPU */
            rc = qemuMonitorSetCPU(priv->mon, i, 1);
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3595
            vcpus++;
3596 3597
        }
    } else {
E
Eric Blake 已提交
3598
        for (i = vcpus - 1 ; i >= nvcpus ; i--) {
3599 3600 3601 3602 3603 3604 3605
            /* Offline old CPU */
            rc = qemuMonitorSetCPU(priv->mon, i, 0);
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3606
            vcpus--;
3607 3608 3609
        }
    }

3610 3611
    /* hotplug succeeded */

3612 3613
    ret = 0;

3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624
    /* After hotplugging the CPUs we need to re-detect threads corresponding
     * to the virtual CPUs. Some older versions don't provide the thread ID
     * or don't have the "info cpus" command (and they don't support multiple
     * CPUs anyways), so errors in the re-detection will not be treated
     * fatal */
    if ((ncpupids = qemuMonitorGetCPUInfo(priv->mon, &cpupids)) <= 0) {
        virResetLastError();
        goto cleanup;
    }

    if (ncpupids != vcpus) {
3625 3626 3627 3628
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("got wrong number of vCPU pids from QEMU monitor. "
                         "got %d, wanted %d"),
                       ncpupids, vcpus);
3629 3630 3631 3632 3633 3634 3635 3636 3637
        ret = -1;
        goto cleanup;
    }

    priv->nvcpupids = ncpupids;
    VIR_FREE(priv->vcpupids);
    priv->vcpupids = cpupids;
    cpupids = NULL;

3638
cleanup:
3639
    qemuDomainObjExitMonitor(driver, vm);
E
Eric Blake 已提交
3640
    vm->def->vcpus = vcpus;
3641
    VIR_FREE(cpupids);
3642
    virDomainAuditVcpu(vm, oldvcpus, nvcpus, "update", rc == 1);
3643 3644 3645
    return ret;

unsupported:
3646 3647
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("cannot change vcpu count of this domain"));
3648 3649 3650 3651
    goto cleanup;
}


3652
static int
3653 3654
qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
3655
{
3656 3657
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3658
    virDomainDefPtr persistentDef;
3659 3660
    const char * type;
    int max;
3661
    int ret = -1;
3662
    bool maximum;
3663

3664 3665
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
3666 3667 3668
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

    if (!nvcpus || (unsigned short) nvcpus != nvcpus) {
3669 3670
        virReportError(VIR_ERR_INVALID_ARG,
                       _("argument out of range: %d"), nvcpus);
3671 3672 3673
        return -1;
    }

3674
    qemuDriverLock(driver);
3675
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
3676 3677
    qemuDriverUnlock(driver);

3678
    if (!vm) {
3679 3680
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3681 3682
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
3683
        goto cleanup;
3684 3685
    }

3686
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
3687 3688
        goto cleanup;

3689 3690 3691
    maximum = (flags & VIR_DOMAIN_VCPU_MAXIMUM) != 0;
    flags &= ~VIR_DOMAIN_VCPU_MAXIMUM;

3692 3693 3694
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto endjob;
3695 3696 3697

    /* MAXIMUM cannot be mixed with LIVE.  */
    if (maximum && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
3698 3699
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("cannot adjust maximum on running domain"));
3700 3701 3702
        goto endjob;
    }

3703
    if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
3704 3705 3706
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
3707 3708 3709 3710
        goto endjob;
    }

    if ((max = qemudGetMaxVCPUs(NULL, type)) < 0) {
3711 3712
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not determine max vcpus for the domain"));
3713 3714 3715
        goto endjob;
    }

3716
    if (!maximum && vm->def->maxvcpus < max) {
3717 3718 3719
        max = vm->def->maxvcpus;
    }

3720
    if (nvcpus > max) {
3721 3722 3723
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the domain: %d > %d"), nvcpus, max);
3724 3725 3726
        goto endjob;
    }

3727 3728 3729 3730 3731 3732
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (qemudDomainHotplugVcpus(driver, vm, nvcpus) < 0)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
3733 3734 3735 3736 3737 3738 3739
        if (maximum) {
            persistentDef->maxvcpus = nvcpus;
            if (nvcpus < persistentDef->vcpus)
                persistentDef->vcpus = nvcpus;
        } else {
            persistentDef->vcpus = nvcpus;
        }
3740

3741 3742
        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            goto endjob;
3743
    }
3744

3745
    ret = 0;
3746

3747
endjob:
3748
    if (qemuDomainObjEndJob(driver, vm) == 0)
3749
        vm = NULL;
3750

3751
cleanup:
3752 3753
    if (vm)
        virDomainObjUnlock(vm);
3754
    return ret;
3755 3756
}

3757
static int
3758
qemuDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
3759
{
3760
    return qemuDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
3761 3762
}

3763 3764

static int
3765 3766 3767 3768 3769 3770
qemudDomainPinVcpuFlags(virDomainPtr dom,
                        unsigned int vcpu,
                        unsigned char *cpumap,
                        int maplen,
                        unsigned int flags) {

3771 3772
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
3773
    virDomainDefPtr persistentDef = NULL;
3774 3775
    virCgroupPtr cgroup_dom = NULL;
    virCgroupPtr cgroup_vcpu = NULL;
3776
    int ret = -1;
3777
    qemuDomainObjPrivatePtr priv;
3778
    bool doReset = false;
3779 3780
    int newVcpuPinNum = 0;
    virDomainVcpuPinDefPtr *newVcpuPin = NULL;
3781
    virBitmapPtr pcpumap = NULL;
3782

3783 3784 3785
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

3786
    qemuDriverLock(driver);
3787
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
3788 3789
    qemuDriverUnlock(driver);

3790 3791 3792
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3793 3794
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
3795 3796 3797
        goto cleanup;
    }

3798 3799
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
3800
        goto cleanup;
3801

3802 3803 3804
    priv = vm->privateData;

    if (vcpu > (priv->nvcpupids-1)) {
3805 3806 3807
        virReportError(VIR_ERR_INVALID_ARG,
                       _("vcpu number out of range %d > %d"),
                       vcpu, priv->nvcpupids);
3808
        goto cleanup;
3809 3810
    }

3811 3812 3813 3814
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

3815 3816 3817
    /* pinning to all physical cpus means resetting,
     * so check if we can reset setting.
     */
3818 3819
    if (virBitmapIsAllSet(pcpumap))
        doReset = true;
3820

3821
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
3822

3823
        if (priv->vcpupids == NULL) {
3824 3825
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cpu affinity is not supported"));
3826 3827 3828
            goto cleanup;
        }

3829 3830 3831 3832 3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843
        if (vm->def->cputune.vcpupin) {
            newVcpuPin = virDomainVcpuPinDefCopy(vm->def->cputune.vcpupin,
                                                 vm->def->cputune.nvcpupin);
            if (!newVcpuPin)
                goto cleanup;

            newVcpuPinNum = vm->def->cputune.nvcpupin;
        } else {
            if (VIR_ALLOC(newVcpuPin) < 0) {
                virReportOOMError();
                goto cleanup;
            }
            newVcpuPinNum = 0;
        }

3844
        if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, vcpu) < 0) {
3845 3846
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("failed to update vcpupin"));
H
Hu Tao 已提交
3847
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858
            goto cleanup;
        }

        /* Configure the corresponding cpuset cgroup before set affinity. */
        if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUSET)) {
            if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup_dom, 0) == 0 &&
                virCgroupForVcpu(cgroup_dom, vcpu, &cgroup_vcpu, 0) == 0 &&
                qemuSetupCgroupVcpuPin(cgroup_vcpu, newVcpuPin, newVcpuPinNum, vcpu) < 0) {
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("failed to set cpuset.cpus in cgroup"
                                 " for vcpu %d"), vcpu);
3859 3860 3861
                goto cleanup;
            }
        } else {
3862
            if (virProcessInfoSetAffinity(priv->vcpupids[vcpu], pcpumap) < 0) {
3863 3864 3865 3866
                virReportError(VIR_ERR_SYSTEM_ERROR,
                               _("failed to set cpu affinity for vcpu %d"),
                               vcpu);
                goto cleanup;
H
Hu Tao 已提交
3867
            }
3868 3869
        }

3870
        if (doReset) {
3871
            if (virDomainVcpuPinDel(vm->def, vcpu) < 0) {
3872
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3873
                               _("failed to delete vcpupin xml of "
3874
                                 "a running domain"));
3875 3876
                goto cleanup;
            }
3877 3878
        } else {
            if (vm->def->cputune.vcpupin)
H
Hu Tao 已提交
3879
                virDomainVcpuPinDefArrayFree(vm->def->cputune.vcpupin, vm->def->cputune.nvcpupin);
3880 3881 3882 3883

            vm->def->cputune.vcpupin = newVcpuPin;
            vm->def->cputune.nvcpupin = newVcpuPinNum;
            newVcpuPin = NULL;
3884 3885
        }

3886
        if (newVcpuPin)
H
Hu Tao 已提交
3887
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
3888

3889 3890
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
            goto cleanup;
3891
    }
3892

3893 3894
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

3895
        if (doReset) {
E
Eric Blake 已提交
3896
            if (virDomainVcpuPinDel(persistentDef, vcpu) < 0) {
3897 3898 3899
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to delete vcpupin xml of "
                                 "a persistent domain"));
3900 3901 3902
                goto cleanup;
            }
        } else {
H
Hu Tao 已提交
3903 3904 3905 3906 3907 3908 3909
            if (!persistentDef->cputune.vcpupin) {
                if (VIR_ALLOC(persistentDef->cputune.vcpupin) < 0) {
                    virReportOOMError();
                    goto cleanup;
                }
                persistentDef->cputune.nvcpupin = 0;
            }
3910
            if (virDomainVcpuPinAdd(&persistentDef->cputune.vcpupin,
H
Hu Tao 已提交
3911 3912 3913 3914
                                    &persistentDef->cputune.nvcpupin,
                                    cpumap,
                                    maplen,
                                    vcpu) < 0) {
3915 3916 3917
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update or add vcpupin xml of "
                                 "a persistent domain"));
3918 3919
                goto cleanup;
            }
3920
        }
3921

3922
        ret = virDomainSaveConfig(driver->configDir, persistentDef);
3923 3924 3925
        goto cleanup;
    }

3926
    ret = 0;
3927

3928
cleanup:
3929 3930 3931 3932
    if (cgroup_vcpu)
        virCgroupFree(&cgroup_vcpu);
    if (cgroup_dom)
        virCgroupFree(&cgroup_dom);
3933 3934
    if (vm)
        virDomainObjUnlock(vm);
3935
    virBitmapFree(pcpumap);
3936
    return ret;
3937 3938
}

3939 3940 3941 3942 3943 3944 3945 3946 3947
static int
qemudDomainPinVcpu(virDomainPtr dom,
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
    return qemudDomainPinVcpuFlags(dom, vcpu, cpumap, maplen,
                                   VIR_DOMAIN_AFFECT_LIVE);
}

3948
static int
E
Eric Blake 已提交
3949
qemudDomainGetVcpuPinInfo(virDomainPtr dom,
3950 3951 3952 3953 3954 3955
                          int ncpumaps,
                          unsigned char *cpumaps,
                          int maplen,
                          unsigned int flags) {

    struct qemud_driver *driver = dom->conn->privateData;
E
Eric Blake 已提交
3956
    virDomainObjPtr vm = NULL;
3957 3958 3959 3960 3961
    virNodeInfo nodeinfo;
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    int maxcpu, hostcpus, vcpu, pcpu;
    int n;
E
Eric Blake 已提交
3962
    virDomainVcpuPinDefPtr *vcpupin_list;
H
Hu Tao 已提交
3963
    virBitmapPtr cpumask = NULL;
3964
    unsigned char *cpumap;
H
Hu Tao 已提交
3965
    bool pinned;
3966 3967 3968 3969 3970 3971 3972 3973 3974 3975 3976

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3977 3978
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
3979 3980 3981
        goto cleanup;
    }

3982 3983 3984
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &targetDef) < 0)
        goto cleanup;
3985 3986 3987 3988 3989

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        targetDef = vm->def;
    }

3990 3991 3992
    /* Coverity didn't realize that targetDef must be set if we got here.  */
    sa_assert(targetDef);

3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008 4009 4010 4011 4012 4013 4014 4015 4016 4017 4018 4019 4020 4021 4022 4023
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
        goto cleanup;
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
    maxcpu = maplen * 8;
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;

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

    if (ncpumaps < 1) {
        goto cleanup;
    }

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

    /* if vcpupin setting exists, there are unused physical cpus */
    for (n = 0; n < targetDef->cputune.nvcpupin; n++) {
        vcpupin_list = targetDef->cputune.vcpupin;
        vcpu = vcpupin_list[n]->vcpuid;
        cpumask = vcpupin_list[n]->cpumask;
        cpumap = VIR_GET_CPUMAP(cpumaps, maplen, vcpu);
        for (pcpu = 0; pcpu < maxcpu; pcpu++) {
H
Hu Tao 已提交
4024 4025 4026
            if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0)
                goto cleanup;
            if (!pinned)
4027 4028 4029 4030 4031 4032 4033 4034 4035 4036 4037
                VIR_UNUSE_CPU(cpumap, pcpu);
        }
    }
    ret = ncpumaps;

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

H
Hu Tao 已提交
4038 4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051
static int
qemudDomainPinEmulator(virDomainPtr dom,
                       unsigned char *cpumap,
                       int maplen,
                       unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virCgroupPtr cgroup_dom = NULL;
    virCgroupPtr cgroup_emulator = NULL;
    pid_t pid;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
4052
    bool doReset = false;
H
Hu Tao 已提交
4053 4054
    int newVcpuPinNum = 0;
    virDomainVcpuPinDefPtr *newVcpuPin = NULL;
4055
    virBitmapPtr pcpumap = NULL;
H
Hu Tao 已提交
4056 4057 4058 4059 4060 4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

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

    priv = vm->privateData;

4078 4079 4080 4081
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

H
Hu Tao 已提交
4082 4083 4084
    /* pinning to all physical cpus means resetting,
     * so check if we can reset setting.
     */
4085 4086
    if (virBitmapIsAllSet(pcpumap))
        doReset = true;
H
Hu Tao 已提交
4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097

    pid = vm->pid;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {

        if (priv->vcpupids != NULL) {
            if (VIR_ALLOC(newVcpuPin) < 0) {
                virReportOOMError();
                goto cleanup;
            }

4098
            if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, -1) < 0) {
H
Hu Tao 已提交
4099 4100
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update vcpupin"));
H
Hu Tao 已提交
4101
                virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
H
Hu Tao 已提交
4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122
                goto cleanup;
            }

            if (qemuCgroupControllerActive(driver,
                                           VIR_CGROUP_CONTROLLER_CPUSET)) {
                /*
                 * Configure the corresponding cpuset cgroup.
                 * If no cgroup for domain or hypervisor exists, do nothing.
                 */
                if (virCgroupForDomain(driver->cgroup, vm->def->name,
                                       &cgroup_dom, 0) == 0) {
                    if (virCgroupForEmulator(cgroup_dom, &cgroup_emulator, 0) == 0) {
                        if (qemuSetupCgroupEmulatorPin(cgroup_emulator, newVcpuPin[0]) < 0) {
                            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                           _("failed to set cpuset.cpus in cgroup"
                                             " for emulator threads"));
                            goto cleanup;
                        }
                    }
                }
            } else {
4123
                if (virProcessInfoSetAffinity(pid, pcpumap) < 0) {
H
Hu Tao 已提交
4124 4125 4126 4127 4128 4129 4130
                    virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
                                   _("failed to set cpu affinity for "
                                     "emulator threads"));
                    goto cleanup;
                }
            }

4131
            if (doReset) {
H
Hu Tao 已提交
4132 4133 4134 4135 4136 4137 4138
                if (virDomainEmulatorPinDel(vm->def) < 0) {
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("failed to delete emulatorpin xml of "
                                     "a running domain"));
                    goto cleanup;
                }
            } else {
H
Hu Tao 已提交
4139
                virDomainVcpuPinDefFree(vm->def->cputune.emulatorpin);
H
Hu Tao 已提交
4140 4141 4142 4143 4144
                vm->def->cputune.emulatorpin = newVcpuPin[0];
                VIR_FREE(newVcpuPin);
            }

            if (newVcpuPin)
H
Hu Tao 已提交
4145
                virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
H
Hu Tao 已提交
4146 4147 4148 4149 4150 4151 4152 4153 4154 4155 4156 4157
        } else {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cpu affinity is not supported"));
            goto cleanup;
        }

        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

4158
        if (doReset) {
H
Hu Tao 已提交
4159 4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170 4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184
            if (virDomainEmulatorPinDel(persistentDef) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to delete emulatorpin xml of "
                                 "a persistent domain"));
                goto cleanup;
            }
        } else {
            if (virDomainEmulatorPinAdd(persistentDef, cpumap, maplen) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update or add emulatorpin xml "
                                 "of a persistent domain"));
                goto cleanup;
            }
        }

        ret = virDomainSaveConfig(driver->configDir, persistentDef);
        goto cleanup;
    }

    ret = 0;

cleanup:
    if (cgroup_emulator)
        virCgroupFree(&cgroup_emulator);
    if (cgroup_dom)
        virCgroupFree(&cgroup_dom);
4185
    virBitmapFree(pcpumap);
H
Hu Tao 已提交
4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202 4203 4204

    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

static int
qemudDomainGetEmulatorPinInfo(virDomainPtr dom,
                              unsigned char *cpumaps,
                              int maplen,
                              unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    virNodeInfo nodeinfo;
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    int maxcpu, hostcpus, pcpu;
    virDomainVcpuPinDefPtr emulatorpin = NULL;
H
Hu Tao 已提交
4205 4206
    virBitmapPtr cpumask = NULL;
    bool pinned;
H
Hu Tao 已提交
4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4222 4223 4224 4225 4226 4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

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

    if (flags & VIR_DOMAIN_AFFECT_LIVE)
        targetDef = vm->def;

    /* Coverity didn't realize that targetDef must be set if we got here. */
    sa_assert(targetDef);

    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
        goto cleanup;
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
    maxcpu = maplen * 8;
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;

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

    /* If no emulatorpin, all cpus should be used */
    emulatorpin = targetDef->cputune.emulatorpin;
    if (!emulatorpin) {
        ret = 0;
        goto cleanup;
    }

    cpumask = emulatorpin->cpumask;
    for (pcpu = 0; pcpu < maxcpu; pcpu++) {
H
Hu Tao 已提交
4255 4256 4257
        if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0)
            goto cleanup;
        if (!pinned)
H
Hu Tao 已提交
4258 4259 4260 4261 4262 4263 4264 4265 4266 4267 4268
            VIR_UNUSE_CPU(cpumaps, pcpu);
    }

    ret = 1;

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

4269 4270 4271 4272 4273 4274
static int
qemudDomainGetVcpus(virDomainPtr dom,
                    virVcpuInfoPtr info,
                    int maxinfo,
                    unsigned char *cpumaps,
                    int maplen) {
4275 4276
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
4277
    virNodeInfo nodeinfo;
4278
    int i, v, maxcpu, hostcpus;
4279
    int ret = -1;
4280
    qemuDomainObjPrivatePtr priv;
4281

4282
    qemuDriverLock(driver);
4283
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4284 4285
    qemuDriverUnlock(driver);

4286 4287 4288
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4289 4290
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
4291 4292 4293
        goto cleanup;
    }

D
Daniel P. Berrange 已提交
4294
    if (!virDomainObjIsActive(vm)) {
4295 4296 4297
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s",
                       _("cannot list vcpu pinning for an inactive domain"));
4298
        goto cleanup;
4299 4300
    }

4301 4302
    priv = vm->privateData;

4303
    if (nodeGetInfo(dom->conn, &nodeinfo) < 0)
4304
        goto cleanup;
4305

4306
    hostcpus = VIR_NODEINFO_MAXCPUS(nodeinfo);
4307
    maxcpu = maplen * 8;
4308 4309
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
4310 4311

    /* Clamp to actual number of vcpus */
4312 4313
    if (maxinfo > priv->nvcpupids)
        maxinfo = priv->nvcpupids;
4314

4315 4316 4317 4318 4319 4320
    if (maxinfo >= 1) {
        if (info != NULL) {
            memset(info, 0, sizeof(*info) * maxinfo);
            for (i = 0 ; i < maxinfo ; i++) {
                info[i].number = i;
                info[i].state = VIR_VCPU_RUNNING;
4321

4322
                if (priv->vcpupids != NULL &&
4323 4324
                    qemudGetProcessInfo(&(info[i].cpuTime),
                                        &(info[i].cpu),
4325
                                        NULL,
4326
                                        vm->pid,
4327
                                        priv->vcpupids[i]) < 0) {
4328
                    virReportSystemError(errno, "%s",
4329 4330 4331
                                         _("cannot get vCPU placement & pCPU time"));
                    goto cleanup;
                }
4332
            }
4333 4334
        }

4335 4336
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
4337
            if (priv->vcpupids != NULL) {
4338 4339
                for (v = 0 ; v < maxinfo ; v++) {
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);
4340 4341 4342
                    virBitmapPtr map = NULL;
                    unsigned char *tmpmap = NULL;
                    int tmpmapLen = 0;
4343

4344
                    if (virProcessInfoGetAffinity(priv->vcpupids[v],
4345
                                                  &map, maxcpu) < 0)
4346
                        goto cleanup;
4347 4348 4349 4350 4351 4352 4353
                    virBitmapToData(map, &tmpmap, &tmpmapLen);
                    if (tmpmapLen > maplen)
                        tmpmapLen = maplen;
                    memcpy(cpumap, tmpmap, tmpmapLen);

                    VIR_FREE(tmpmap);
                    virBitmapFree(map);
4354
                }
4355
            } else {
4356 4357
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("cpu affinity is not available"));
4358
                goto cleanup;
4359 4360 4361
            }
        }
    }
4362
    ret = maxinfo;
4363

4364
cleanup:
4365 4366
    if (vm)
        virDomainObjUnlock(vm);
4367
    return ret;
4368 4369 4370
}


4371 4372 4373
static int
qemudDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
{
4374 4375
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
4376
    virDomainDefPtr def;
4377
    int ret = -1;
4378

4379 4380
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
4381 4382
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

4383
    qemuDriverLock(driver);
4384
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
4385 4386
    qemuDriverUnlock(driver);

4387
    if (!vm) {
4388 4389
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4390 4391
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
4392
        goto cleanup;
4393 4394
    }

4395 4396
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &def) < 0)
        goto cleanup;
4397

4398
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4399
        def = vm->def;
4400 4401
    }

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

4404
cleanup:
4405 4406
    if (vm)
        virDomainObjUnlock(vm);
4407 4408 4409
    return ret;
}

4410 4411 4412
static int
qemudDomainGetMaxVcpus(virDomainPtr dom)
{
4413
    return qemudDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
4414 4415 4416
                                          VIR_DOMAIN_VCPU_MAXIMUM));
}

4417 4418 4419 4420 4421 4422 4423 4424 4425
static int qemudDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
{
    struct qemud_driver *driver = (struct qemud_driver *)dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

4426 4427
    memset(seclabel, 0, sizeof(*seclabel));

4428 4429 4430
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
4431 4432
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
4433 4434 4435
        goto cleanup;
    }

4436
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
4437 4438 4439
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 4452 4453 4454 4455 4456
        goto cleanup;
    }

    /*
     * Theoretically, the pid can be replaced during this operation and
     * return the label of a different process.  If atomicity is needed,
     * further validation will be required.
     *
     * Comment from Dan Berrange:
     *
     *   Well the PID as stored in the virDomainObjPtr can't be changed
     *   because you've got a locked object.  The OS level PID could have
     *   exited, though and in extreme circumstances have cycled through all
     *   PIDs back to ours. We could sanity check that our PID still exists
     *   after reading the label, by checking that our FD connecting to the
     *   QEMU monitor hasn't seen SIGHUP/ERR on poll().
     */
D
Daniel P. Berrange 已提交
4457
    if (virDomainObjIsActive(vm)) {
4458
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
4459
                                              vm->def, vm->pid, seclabel) < 0) {
4460 4461
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to get security label"));
4462
            goto cleanup;
4463 4464 4465 4466 4467 4468 4469 4470
        }
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
4471
    qemuDriverUnlock(driver);
4472 4473 4474
    return ret;
}

M
Marcelo Cerri 已提交
4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546
static int qemuDomainGetSecurityLabelList(virDomainPtr dom,
                                          virSecurityLabelPtr* seclabels)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int i, ret = -1;

    /* Protect domain data with qemu lock */
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    if (!virDomainVirtTypeToString(vm->def->virtType)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
        goto cleanup;
    }

    /*
     * Check the comment in qemudDomainGetSecurityLabel function.
     */
    if (!virDomainObjIsActive(vm)) {
        /* No seclabels */
        *seclabels = NULL;
        ret = 0;
    } else {
        int len = 0;
        virSecurityManagerPtr* mgrs = virSecurityManagerGetNested(
                                            driver->securityManager);
        if (!mgrs)
            goto cleanup;

        /* Allocate seclabels array */
        for (i = 0; mgrs[i]; i++)
            len++;

        if (VIR_ALLOC_N((*seclabels), len) < 0) {
            virReportOOMError();
            VIR_FREE(mgrs);
            goto cleanup;
        }
        memset(*seclabels, 0, sizeof(**seclabels) * len);

        /* Fill the array */
        for (i = 0; i < len; i++) {
            if (virSecurityManagerGetProcessLabel(mgrs[i], vm->def, vm->pid,
                                                  &(*seclabels)[i]) < 0) {
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               "%s", _("Failed to get security label"));
                VIR_FREE(mgrs);
                VIR_FREE(*seclabels);
                goto cleanup;
            }
        }
        ret = len;
        VIR_FREE(mgrs);
    }

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
4547 4548
static int qemudNodeGetSecurityModel(virConnectPtr conn,
                                     virSecurityModelPtr secmodel)
4549 4550 4551
{
    struct qemud_driver *driver = (struct qemud_driver *)conn->privateData;
    char *p;
4552
    int ret = 0;
4553

4554
    qemuDriverLock(driver);
4555 4556
    memset(secmodel, 0, sizeof(*secmodel));

4557 4558 4559
    /* We treat no driver as success, but simply return no data in *secmodel */
    if (driver->caps->host.nsecModels == 0 ||
        driver->caps->host.secModels[0].model == NULL)
4560
        goto cleanup;
4561

4562
    p = driver->caps->host.secModels[0].model;
4563
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
4564 4565 4566
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security model string exceeds max %d bytes"),
                       VIR_SECURITY_MODEL_BUFLEN-1);
4567 4568
        ret = -1;
        goto cleanup;
4569 4570 4571
    }
    strcpy(secmodel->model, p);

4572
    p = driver->caps->host.secModels[0].doi;
4573
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
4574 4575 4576
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security DOI string exceeds max %d bytes"),
                       VIR_SECURITY_DOI_BUFLEN-1);
4577 4578
        ret = -1;
        goto cleanup;
4579 4580
    }
    strcpy(secmodel->doi, p);
4581 4582 4583 4584

cleanup:
    qemuDriverUnlock(driver);
    return ret;
4585 4586
}

E
Eric Blake 已提交
4587
/* Return -1 on most failures after raising error, -2 if edit was specified
4588 4589 4590
 * but xmlin and state (-1 for no change, 0 for paused, 1 for running) do
 * not represent any changes (no error raised), -3 if corrupt image was
 * unlinked (no error raised), and opened fd on success.  */
4591
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
4592 4593 4594
qemuDomainSaveImageOpen(struct qemud_driver *driver,
                        const char *path,
                        virDomainDefPtr *ret_def,
4595
                        struct qemud_save_header *ret_header,
J
Jiri Denemark 已提交
4596 4597
                        bool bypass_cache,
                        virFileWrapperFdPtr *wrapperFd,
4598 4599
                        const char *xmlin, int state, bool edit,
                        bool unlink_corrupt)
J
Jiri Denemark 已提交
4600
{
W
Wen Congyang 已提交
4601
    int fd = -1;
4602
    struct qemud_save_header header;
J
Jiri Denemark 已提交
4603 4604
    char *xml = NULL;
    virDomainDefPtr def = NULL;
4605
    int oflags = edit ? O_RDWR : O_RDONLY;
4606

4607
    if (bypass_cache) {
4608
        int directFlag = virFileDirectFdFlag();
4609
        if (directFlag < 0) {
4610 4611
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
4612 4613
            goto error;
        }
4614
        oflags |= directFlag;
4615
    }
4616

E
Eric Blake 已提交
4617 4618
    if ((fd = qemuOpenFile(driver, path, oflags, NULL, NULL)) < 0)
        goto error;
J
Jiri Denemark 已提交
4619 4620 4621
    if (bypass_cache &&
        !(*wrapperFd = virFileWrapperFdNew(&fd, path,
                                           VIR_FILE_WRAPPER_BYPASS_CACHE)))
4622
        goto error;
4623 4624

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
4625 4626 4627 4628 4629 4630 4631 4632 4633
        if (unlink_corrupt) {
            if (VIR_CLOSE(fd) < 0 || unlink(path) < 0) {
                virReportSystemError(errno,
                                     _("cannot remove corrupt file: %s"),
                                     path);
                goto error;
            }
            return -3;
        }
4634 4635
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to read qemu header"));
J
Jiri Denemark 已提交
4636
        goto error;
4637 4638 4639
    }

    if (memcmp(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic)) != 0) {
E
Eric Blake 已提交
4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654
        const char *msg = _("image magic is incorrect");

        if (memcmp(header.magic, QEMUD_SAVE_PARTIAL,
                   sizeof(header.magic)) == 0) {
            msg = _("save image is incomplete");
            if (unlink_corrupt) {
                if (VIR_CLOSE(fd) < 0 || unlink(path) < 0) {
                    virReportSystemError(errno,
                                         _("cannot remove corrupt file: %s"),
                                         path);
                    goto error;
                }
                return -3;
            }
        }
4655
        virReportError(VIR_ERR_OPERATION_FAILED, "%s", msg);
J
Jiri Denemark 已提交
4656
        goto error;
4657 4658 4659
    }

    if (header.version > QEMUD_SAVE_VERSION) {
4660 4661 4662 4663 4664
        /* convert endianess and try again */
        bswap_header(&header);
    }

    if (header.version > QEMUD_SAVE_VERSION) {
4665 4666 4667
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("image version is not supported (%d > %d)"),
                       header.version, QEMUD_SAVE_VERSION);
J
Jiri Denemark 已提交
4668
        goto error;
4669 4670
    }

4671
    if (header.xml_len <= 0) {
4672 4673
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("invalid XML length: %d"), header.xml_len);
J
Jiri Denemark 已提交
4674
        goto error;
4675 4676
    }

4677 4678
    if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
        virReportOOMError();
J
Jiri Denemark 已提交
4679
        goto error;
4680 4681 4682
    }

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
4683 4684
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to read XML"));
J
Jiri Denemark 已提交
4685
        goto error;
4686 4687
    }

4688 4689
    if (edit && STREQ(xml, xmlin) &&
        (state < 0 || state == header.was_running)) {
4690 4691 4692 4693 4694 4695 4696
        VIR_FREE(xml);
        if (VIR_CLOSE(fd) < 0) {
            virReportSystemError(errno, _("cannot close file: %s"), path);
            goto error;
        }
        return -2;
    }
4697 4698
    if (state >= 0)
        header.was_running = state;
4699

4700
    /* Create a domain from this XML */
4701
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
4702
                                        QEMU_EXPECTED_VIRT_TYPES,
4703
                                        VIR_DOMAIN_XML_INACTIVE)))
J
Jiri Denemark 已提交
4704
        goto error;
4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718
    if (xmlin) {
        virDomainDefPtr def2 = NULL;

        if (!(def2 = virDomainDefParseString(driver->caps, xmlin,
                                             QEMU_EXPECTED_VIRT_TYPES,
                                             VIR_DOMAIN_XML_INACTIVE)))
            goto error;
        if (!virDomainDefCheckABIStability(def, def2)) {
            virDomainDefFree(def2);
            goto error;
        }
        virDomainDefFree(def);
        def = def2;
    }
4719

J
Jiri Denemark 已提交
4720
    VIR_FREE(xml);
4721

J
Jiri Denemark 已提交
4722 4723
    *ret_def = def;
    *ret_header = header;
4724

J
Jiri Denemark 已提交
4725
    return fd;
4726

J
Jiri Denemark 已提交
4727 4728 4729
error:
    virDomainDefFree(def);
    VIR_FREE(xml);
4730
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
4731 4732 4733 4734

    return -1;
}

4735 4736 4737 4738 4739 4740
static int ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(6)
qemuDomainSaveImageStartVM(virConnectPtr conn,
                           struct qemud_driver *driver,
                           virDomainObjPtr vm,
                           int *fd,
                           const struct qemud_save_header *header,
4741 4742
                           const char *path,
                           bool start_paused)
J
Jiri Denemark 已提交
4743 4744 4745 4746
{
    int ret = -1;
    virDomainEventPtr event;
    int intermediatefd = -1;
4747
    virCommandPtr cmd = NULL;
J
Jiri Denemark 已提交
4748 4749 4750

    if (header->version == 2) {
        const char *prog = qemudSaveCompressionTypeToString(header->compressed);
4751
        if (prog == NULL) {
4752 4753 4754
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("Invalid compressed save format %d"),
                           header->compressed);
J
Jiri Denemark 已提交
4755
            goto out;
4756
        }
4757

J
Jiri Denemark 已提交
4758
        if (header->compressed != QEMUD_SAVE_FORMAT_RAW) {
4759
            cmd = virCommandNewArgList(prog, "-dc", NULL);
4760 4761
            intermediatefd = *fd;
            *fd = -1;
4762 4763 4764 4765 4766

            virCommandSetInputFD(cmd, intermediatefd);
            virCommandSetOutputFD(cmd, fd);

            if (virCommandRunAsync(cmd, NULL) < 0) {
4767 4768 4769
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to start decompression binary %s"),
                               prog);
4770
                *fd = intermediatefd;
J
Jiri Denemark 已提交
4771
                goto out;
4772 4773 4774
            }
        }
    }
J
Jiri Denemark 已提交
4775

4776
    /* Set the migration source and start it up. */
4777 4778 4779
    ret = qemuProcessStart(conn, driver, vm, "stdio", *fd, path, NULL,
                           VIR_NETDEV_VPORT_PROFILE_OP_RESTORE,
                           VIR_QEMU_PROCESS_START_PAUSED);
J
Jiri Denemark 已提交
4780

4781
    if (intermediatefd != -1) {
4782
        if (ret < 0) {
4783 4784 4785
            /* if there was an error setting up qemu, the intermediate
             * process will wait forever to write to stdout, so we
             * must manually kill it.
4786 4787
             */
            VIR_FORCE_CLOSE(intermediatefd);
4788
            VIR_FORCE_CLOSE(*fd);
4789 4790
        }

4791 4792
        if (virCommandWait(cmd, NULL) < 0)
            ret = -1;
4793
    }
4794
    VIR_FORCE_CLOSE(intermediatefd);
J
Jiri Denemark 已提交
4795

4796 4797 4798
    if (VIR_CLOSE(*fd) < 0) {
        virReportSystemError(errno, _("cannot close file: %s"), path);
        ret = -1;
4799
    }
J
Jiri Denemark 已提交
4800

4801
    if (ret < 0) {
4802
        virDomainAuditStart(vm, "restored", false);
J
Jiri Denemark 已提交
4803
        goto out;
4804
    }
4805

4806 4807 4808
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
4809
    virDomainAuditStart(vm, "restored", true);
J
Jiri Denemark 已提交
4810 4811 4812
    if (event)
        qemuDomainEventQueue(driver, event);

4813

4814 4815
    /* If it was running before, resume it now unless caller requested pause. */
    if (header->was_running && !start_paused) {
J
Jiri Denemark 已提交
4816
        if (qemuProcessStartCPUs(driver, vm, conn,
4817 4818
                                 VIR_DOMAIN_RUNNING_RESTORED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
4819
            if (virGetLastError() == NULL)
4820 4821
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("failed to resume domain"));
J
Jiri Denemark 已提交
4822
            goto out;
4823
        }
4824 4825
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
J
Jiri Denemark 已提交
4826
            goto out;
4827
        }
4828 4829 4830 4831 4832 4833 4834 4835
    } else {
        int detail = (start_paused ? VIR_DOMAIN_EVENT_SUSPENDED_PAUSED :
                      VIR_DOMAIN_EVENT_SUSPENDED_RESTORED);
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         detail);
        if (event)
            qemuDomainEventQueue(driver, event);
4836
    }
J
Jiri Denemark 已提交
4837

4838
    ret = 0;
4839

J
Jiri Denemark 已提交
4840
out:
4841
    virCommandFree(cmd);
4842
    if (virSecurityManagerRestoreSavedStateLabel(driver->securityManager,
4843
                                                 vm->def, path) < 0)
4844 4845
        VIR_WARN("failed to restore save state label on %s", path);

J
Jiri Denemark 已提交
4846 4847 4848
    return ret;
}

4849
static int
4850 4851 4852 4853
qemuDomainRestoreFlags(virConnectPtr conn,
                       const char *path,
                       const char *dxml,
                       unsigned int flags)
4854
{
J
Jiri Denemark 已提交
4855 4856 4857 4858 4859 4860
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    int fd = -1;
    int ret = -1;
    struct qemud_save_header header;
J
Jiri Denemark 已提交
4861
    virFileWrapperFdPtr wrapperFd = NULL;
4862
    int state = -1;
J
Jiri Denemark 已提交
4863

4864 4865 4866
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
4867

J
Jiri Denemark 已提交
4868 4869
    qemuDriverLock(driver);

4870 4871 4872 4873 4874
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

4875 4876
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
                                 (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
J
Jiri Denemark 已提交
4877
                                 &wrapperFd, dxml, state, false, false);
J
Jiri Denemark 已提交
4878 4879 4880 4881 4882 4883 4884 4885 4886
    if (fd < 0)
        goto cleanup;

    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;

    if (!(vm = virDomainAssignDef(driver->caps,
                                  &driver->domains,
                                  def, true))) {
4887
        /* virDomainAssignDef already set the error */
J
Jiri Denemark 已提交
4888 4889 4890 4891
        goto cleanup;
    }
    def = NULL;

4892
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
J
Jiri Denemark 已提交
4893 4894
        goto cleanup;

4895 4896
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     false);
J
Jiri Denemark 已提交
4897
    if (virFileWrapperFdClose(wrapperFd) < 0)
4898
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
4899

4900
    if (qemuDomainObjEndJob(driver, vm) == 0)
4901
        vm = NULL;
J
Jiri Denemark 已提交
4902
    else if (ret < 0 && !vm->persistent) {
4903
        qemuDomainRemoveInactive(driver, vm);
J
Jiri Denemark 已提交
4904 4905
        vm = NULL;
    }
4906

4907 4908
cleanup:
    virDomainDefFree(def);
4909
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
4910
    virFileWrapperFdFree(wrapperFd);
4911 4912 4913
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
4914
    return ret;
D
Daniel P. Berrange 已提交
4915 4916
}

4917 4918 4919 4920 4921 4922 4923
static int
qemuDomainRestore(virConnectPtr conn,
                  const char *path)
{
    return qemuDomainRestoreFlags(conn, path, NULL, 0);
}

4924 4925 4926 4927 4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939
static char *
qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
                              unsigned int flags)
{
    struct qemud_driver *driver = conn->privateData;
    char *ret = NULL;
    virDomainDefPtr def = NULL;
    int fd = -1;
    struct qemud_save_header header;

    /* We only take subset of virDomainDefFormat flags.  */
    virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);

    qemuDriverLock(driver);

    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
4940
                                 NULL, -1, false, false);
4941 4942 4943 4944

    if (fd < 0)
        goto cleanup;

4945
    ret = qemuDomainDefFormatXML(driver, def, flags, false);
4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964

cleanup:
    virDomainDefFree(def);
    VIR_FORCE_CLOSE(fd);
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path,
                             const char *dxml, unsigned int flags)
{
    struct qemud_driver *driver = conn->privateData;
    int ret = -1;
    virDomainDefPtr def = NULL;
    int fd = -1;
    struct qemud_save_header header;
    char *xml = NULL;
    size_t len;
4965
    int state = -1;
4966

4967 4968
    virCheckFlags(VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
4969 4970 4971

    qemuDriverLock(driver);

4972 4973 4974 4975 4976
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

4977
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
4978
                                 dxml, state, true, false);
4979 4980 4981 4982 4983 4984 4985 4986

    if (fd < 0) {
        /* Check for special case of no change needed.  */
        if (fd == -2)
            ret = 0;
        goto cleanup;
    }

4987 4988 4989 4990
    xml = qemuDomainDefFormatXML(driver, def,
                                 VIR_DOMAIN_XML_INACTIVE |
                                 VIR_DOMAIN_XML_SECURE,
                                 true);
4991 4992 4993 4994 4995
    if (!xml)
        goto cleanup;
    len = strlen(xml) + 1;

    if (len > header.xml_len) {
4996 4997
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("new xml too large to fit in file"));
4998 4999 5000 5001 5002 5003 5004
        goto cleanup;
    }
    if (VIR_EXPAND_N(xml, len, header.xml_len - len) < 0) {
        virReportOOMError();
        goto cleanup;
    }

5005
    if (lseek(fd, 0, SEEK_SET) != 0) {
5006 5007 5008
        virReportSystemError(errno, _("cannot seek in '%s'"), path);
        goto cleanup;
    }
5009 5010
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header) ||
        safewrite(fd, xml, len) != len ||
5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025
        VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("failed to write xml to '%s'"), path);
        goto cleanup;
    }

    ret = 0;

cleanup:
    virDomainDefFree(def);
    VIR_FORCE_CLOSE(fd);
    VIR_FREE(xml);
    qemuDriverUnlock(driver);
    return ret;
}

E
Eric Blake 已提交
5026 5027
/* Return 0 on success, 1 if incomplete saved image was silently unlinked,
 * and -1 on failure with error raised.  */
5028 5029 5030 5031
static int
qemuDomainObjRestore(virConnectPtr conn,
                     struct qemud_driver *driver,
                     virDomainObjPtr vm,
5032
                     const char *path,
5033
                     bool start_paused,
5034
                     bool bypass_cache)
J
Jiri Denemark 已提交
5035 5036 5037 5038 5039
{
    virDomainDefPtr def = NULL;
    int fd = -1;
    int ret = -1;
    struct qemud_save_header header;
J
Jiri Denemark 已提交
5040
    virFileWrapperFdPtr wrapperFd = NULL;
J
Jiri Denemark 已提交
5041

5042
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
J
Jiri Denemark 已提交
5043
                                 bypass_cache, &wrapperFd, NULL, -1, false,
5044
                                 true);
E
Eric Blake 已提交
5045 5046 5047
    if (fd < 0) {
        if (fd == -3)
            ret = 1;
J
Jiri Denemark 已提交
5048
        goto cleanup;
E
Eric Blake 已提交
5049
    }
J
Jiri Denemark 已提交
5050 5051 5052 5053 5054 5055 5056

    if (STRNEQ(vm->def->name, def->name) ||
        memcmp(vm->def->uuid, def->uuid, VIR_UUID_BUFLEN)) {
        char vm_uuidstr[VIR_UUID_STRING_BUFLEN];
        char def_uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(vm->def->uuid, vm_uuidstr);
        virUUIDFormat(def->uuid, def_uuidstr);
5057 5058 5059 5060 5061
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("cannot restore domain '%s' uuid %s from a file"
                         " which belongs to domain '%s' uuid %s"),
                       vm->def->name, vm_uuidstr,
                       def->name, def_uuidstr);
J
Jiri Denemark 已提交
5062 5063 5064 5065 5066 5067
        goto cleanup;
    }

    virDomainObjAssignDef(vm, def, true);
    def = NULL;

5068 5069
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     start_paused);
J
Jiri Denemark 已提交
5070
    if (virFileWrapperFdClose(wrapperFd) < 0)
5071
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
5072 5073 5074

cleanup:
    virDomainDefFree(def);
5075
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
5076
    virFileWrapperFdFree(wrapperFd);
J
Jiri Denemark 已提交
5077 5078 5079
    return ret;
}

D
Daniel P. Berrange 已提交
5080

5081
static char *qemuDomainGetXMLDesc(virDomainPtr dom,
5082 5083
                                  unsigned int flags)
{
5084 5085 5086
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    char *ret = NULL;
5087
    unsigned long long balloon;
5088
    int err = 0;
5089
    qemuDomainObjPrivatePtr priv;
5090

5091
    /* Flags checked by virDomainDefFormat */
5092

5093
    qemuDriverLock(driver);
5094
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5095

D
Daniel P. Berrange 已提交
5096
    if (!vm) {
5097 5098
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5099 5100
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
5101
        goto cleanup;
D
Daniel P. Berrange 已提交
5102 5103
    }

5104 5105
    priv = vm->privateData;

5106 5107 5108
    /* Refresh current memory based on balloon info if supported */
    if ((vm->def->memballoon != NULL) &&
        (vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) &&
5109
        !qemuCapsGet(priv->caps, QEMU_CAPS_BALLOON_EVENT) &&
5110
        (virDomainObjIsActive(vm))) {
5111 5112
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
5113
        if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
5114
            if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_QUERY) < 0)
5115 5116
                goto cleanup;

5117
            if (!virDomainObjIsActive(vm)) {
5118 5119
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("domain is not running"));
5120 5121 5122
                goto endjob;
            }

5123
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
5124
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
5125
            qemuDomainObjExitMonitorWithDriver(driver, vm);
5126 5127

endjob:
5128
            if (qemuDomainObjEndJob(driver, vm) == 0) {
5129 5130 5131
                vm = NULL;
                goto cleanup;
            }
5132 5133 5134
            if (err < 0)
                goto cleanup;
            if (err > 0)
5135
                vm->def->mem.cur_balloon = balloon;
5136 5137
            /* err == 0 indicates no balloon support, so ignore it */
        }
5138
    }
5139

5140
    ret = qemuDomainFormatXML(driver, vm, flags, false);
5141 5142

cleanup:
5143 5144
    if (vm)
        virDomainObjUnlock(vm);
5145
    qemuDriverUnlock(driver);
5146
    return ret;
D
Daniel P. Berrange 已提交
5147 5148 5149
}


5150 5151 5152
static char *qemuDomainXMLFromNative(virConnectPtr conn,
                                     const char *format,
                                     const char *config,
E
Eric Blake 已提交
5153 5154
                                     unsigned int flags)
{
5155
    struct qemud_driver *driver = conn->privateData;
5156 5157 5158
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
5159 5160
    virCheckFlags(0, NULL);

5161
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
5162 5163
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), format);
5164 5165 5166
        goto cleanup;
    }

5167
    qemuDriverLock(driver);
5168 5169
    def = qemuParseCommandLineString(driver->caps, config,
                                     NULL, NULL, NULL);
5170
    qemuDriverUnlock(driver);
5171 5172 5173
    if (!def)
        goto cleanup;

5174 5175 5176 5177 5178 5179
    if (!def->name &&
        !(def->name = strdup("unnamed"))) {
        virReportOOMError();
        goto cleanup;
    }

5180
    xml = qemuDomainDefFormatXML(driver, def, VIR_DOMAIN_XML_INACTIVE, false);
5181 5182 5183 5184 5185 5186

cleanup:
    virDomainDefFree(def);
    return xml;
}

5187 5188 5189
static char *qemuDomainXMLToNative(virConnectPtr conn,
                                   const char *format,
                                   const char *xmlData,
E
Eric Blake 已提交
5190 5191
                                   unsigned int flags)
{
5192 5193
    struct qemud_driver *driver = conn->privateData;
    virDomainDefPtr def = NULL;
5194
    virDomainChrSourceDef monConfig;
5195
    qemuCapsPtr caps = NULL;
T
tangchen 已提交
5196
    bool monitor_json = false;
E
Eric Blake 已提交
5197
    virCommandPtr cmd = NULL;
5198 5199 5200
    char *ret = NULL;
    int i;

E
Eric Blake 已提交
5201 5202
    virCheckFlags(0, NULL);

5203 5204
    qemuDriverLock(driver);

5205
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
5206 5207
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), format);
5208 5209 5210
        goto cleanup;
    }

M
Matthias Bolte 已提交
5211 5212
    def = virDomainDefParseString(driver->caps, xmlData,
                                  QEMU_EXPECTED_VIRT_TYPES, 0);
5213 5214 5215
    if (!def)
        goto cleanup;

5216 5217
    /* Since we're just exporting args, we can't do bridge/network/direct
     * setups, since libvirt will normally create TAP/macvtap devices
5218 5219 5220 5221 5222
     * directly. We convert those configs into generic 'ethernet'
     * config and assume the user has suitable 'ifup-qemu' scripts
     */
    for (i = 0 ; i < def->nnets ; i++) {
        virDomainNetDefPtr net = def->nets[i];
5223
        int bootIndex = net->info.bootIndex;
5224 5225 5226 5227
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            int actualType = virDomainNetGetActualType(net);
            const char *brname;

5228
            VIR_FREE(net->data.network.name);
5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240
            VIR_FREE(net->data.network.portgroup);
            if ((actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
                (brname = virDomainNetGetActualBridgeName(net))) {

                char *brnamecopy = strdup(brname);
                if (!brnamecopy) {
                    virReportOOMError();
                    goto cleanup;
                }

                virDomainActualNetDefFree(net->data.network.actual);

5241
                memset(net, 0, sizeof(*net));
5242 5243

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5244
                net->script = NULL;
5245 5246 5247 5248 5249 5250 5251
                net->data.ethernet.dev = brnamecopy;
                net->data.ethernet.ipaddr = NULL;
            } else {
                /* actualType is either NETWORK or DIRECT. In either
                 * case, the best we can do is NULL everything out.
                 */
                virDomainActualNetDefFree(net->data.network.actual);
5252
                memset(net, 0, sizeof(*net));
5253 5254

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5255
                net->script = NULL;
5256 5257 5258 5259 5260
                net->data.ethernet.dev = NULL;
                net->data.ethernet.ipaddr = NULL;
            }
        } else if (net->type == VIR_DOMAIN_NET_TYPE_DIRECT) {
            VIR_FREE(net->data.direct.linkdev);
5261

5262
            memset(net, 0, sizeof(*net));
5263 5264

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5265
            net->script = NULL;
5266 5267 5268
            net->data.ethernet.dev = NULL;
            net->data.ethernet.ipaddr = NULL;
        } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
5269
            char *script = net->script;
5270 5271 5272
            char *brname = net->data.bridge.brname;
            char *ipaddr = net->data.bridge.ipaddr;

5273
            memset(net, 0, sizeof(*net));
5274 5275

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5276
            net->script = script;
5277 5278 5279
            net->data.ethernet.dev = brname;
            net->data.ethernet.ipaddr = ipaddr;
        }
5280
        VIR_FREE(net->virtPortProfile);
5281
        net->info.bootIndex = bootIndex;
5282 5283
    }

5284
    if (qemuCapsExtractVersionInfo(def->emulator, def->os.arch,
5285
                                   false,
5286
                                   NULL,
5287
                                   &caps) < 0)
5288 5289
        goto cleanup;

5290
    monitor_json = qemuCapsGet(caps, QEMU_CAPS_MONITOR_JSON);
T
tangchen 已提交
5291

5292
    if (qemuProcessPrepareMonitorChr(driver, &monConfig, def->name) < 0)
5293
        goto cleanup;
5294

5295
    if (qemuAssignDeviceAliases(def, caps) < 0)
5296 5297
        goto cleanup;

5298
    if (!(cmd = qemuBuildCommandLine(conn, driver, def,
5299
                                     &monConfig, monitor_json, caps,
5300
                                     NULL, -1, NULL, VIR_NETDEV_VPORT_PROFILE_OP_NO_OP)))
5301 5302
        goto cleanup;

E
Eric Blake 已提交
5303
    ret = virCommandToString(cmd);
5304 5305

cleanup:
5306
    qemuDriverUnlock(driver);
5307

5308
    virObjectUnref(caps);
E
Eric Blake 已提交
5309
    virCommandFree(cmd);
5310 5311 5312 5313 5314
    virDomainDefFree(def);
    return ret;
}


5315
static int qemudListDefinedDomains(virConnectPtr conn,
5316
                            char **const names, int nnames) {
5317
    struct qemud_driver *driver = conn->privateData;
5318
    int n;
5319

5320
    qemuDriverLock(driver);
5321
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
5322
    qemuDriverUnlock(driver);
5323
    return n;
D
Daniel P. Berrange 已提交
5324 5325
}

5326
static int qemudNumDefinedDomains(virConnectPtr conn) {
5327
    struct qemud_driver *driver = conn->privateData;
5328
    int n;
5329

5330
    qemuDriverLock(driver);
5331
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
5332
    qemuDriverUnlock(driver);
5333

5334
    return n;
D
Daniel P. Berrange 已提交
5335 5336 5337
}


5338 5339 5340 5341
static int
qemuDomainObjStart(virConnectPtr conn,
                   struct qemud_driver *driver,
                   virDomainObjPtr vm,
5342
                   unsigned int flags)
J
Jiri Denemark 已提交
5343 5344 5345
{
    int ret = -1;
    char *managed_save;
5346 5347 5348 5349
    bool start_paused = (flags & VIR_DOMAIN_START_PAUSED) != 0;
    bool autodestroy = (flags & VIR_DOMAIN_START_AUTODESTROY) != 0;
    bool bypass_cache = (flags & VIR_DOMAIN_START_BYPASS_CACHE) != 0;
    bool force_boot = (flags & VIR_DOMAIN_START_FORCE_BOOT) != 0;
5350 5351 5352 5353
    unsigned int start_flags = VIR_QEMU_PROCESS_START_COLD;

    start_flags |= start_paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
    start_flags |= autodestroy ? VIR_QEMU_PROCESS_START_AUTODESROY : 0;
J
Jiri Denemark 已提交
5354 5355 5356

    /*
     * If there is a managed saved state restore it instead of starting
5357
     * from scratch. The old state is removed once the restoring succeeded.
J
Jiri Denemark 已提交
5358 5359
     */
    managed_save = qemuDomainManagedSavePath(driver, vm);
5360 5361 5362 5363

    if (!managed_save)
        goto cleanup;

E
Eric Blake 已提交
5364
    if (virFileExists(managed_save)) {
5365 5366 5367 5368 5369 5370 5371 5372 5373
        if (force_boot) {
            if (unlink(managed_save) < 0) {
                virReportSystemError(errno,
                                     _("cannot remove managed save file %s"),
                                     managed_save);
                goto cleanup;
            }
        } else {
            ret = qemuDomainObjRestore(conn, driver, vm, managed_save,
5374
                                       start_paused, bypass_cache);
J
Jiri Denemark 已提交
5375

5376 5377 5378 5379 5380 5381 5382
            if (ret == 0) {
                if (unlink(managed_save) < 0)
                    VIR_WARN("Failed to remove the managed state %s", managed_save);
                else
                    vm->hasManagedSave = false;
            }

E
Eric Blake 已提交
5383 5384 5385 5386
            if (ret > 0)
                VIR_WARN("Ignoring incomplete managed state %s", managed_save);
            else
                goto cleanup;
5387
        }
J
Jiri Denemark 已提交
5388 5389
    }

5390 5391
    ret = qemuProcessStart(conn, driver, vm, NULL, -1, NULL, NULL,
                           VIR_NETDEV_VPORT_PROFILE_OP_CREATE, start_flags);
5392
    virDomainAuditStart(vm, "booted", ret >= 0);
5393
    if (ret >= 0) {
J
Jiri Denemark 已提交
5394 5395 5396 5397
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
5398
        if (event) {
J
Jiri Denemark 已提交
5399
            qemuDomainEventQueue(driver, event);
5400 5401 5402 5403 5404 5405 5406 5407
            if (start_paused) {
                event = virDomainEventNewFromObj(vm,
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
                if (event)
                    qemuDomainEventQueue(driver, event);
            }
        }
J
Jiri Denemark 已提交
5408 5409 5410 5411 5412 5413 5414
    }

cleanup:
    VIR_FREE(managed_save);
    return ret;
}

5415
static int
5416
qemuDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
5417
{
5418 5419 5420
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
5421

5422
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
5423
                  VIR_DOMAIN_START_AUTODESTROY |
5424 5425
                  VIR_DOMAIN_START_BYPASS_CACHE |
                  VIR_DOMAIN_START_FORCE_BOOT, -1);
5426

5427
    qemuDriverLock(driver);
5428
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5429

5430
    if (!vm) {
5431 5432
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5433 5434
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
5435
        goto cleanup;
5436 5437
    }

5438
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
5439 5440 5441
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
5442 5443
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is already running"));
5444 5445 5446
        goto endjob;
    }

5447
    if (qemuDomainObjStart(dom->conn, driver, vm, flags) < 0)
5448 5449 5450
        goto endjob;

    ret = 0;
5451

5452
endjob:
5453
    if (qemuDomainObjEndJob(driver, vm) == 0)
5454
        vm = NULL;
5455

5456
cleanup:
5457 5458
    if (vm)
        virDomainObjUnlock(vm);
5459
    qemuDriverUnlock(driver);
5460
    return ret;
D
Daniel P. Berrange 已提交
5461 5462
}

5463
static int
5464
qemuDomainStart(virDomainPtr dom)
5465
{
5466
    return qemuDomainStartWithFlags(dom, 0);
5467 5468
}

5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483
static int
qemudCanonicalizeMachineFromInfo(virDomainDefPtr def,
                                 virCapsGuestDomainInfoPtr info,
                                 char **canonical)
{
    int i;

    *canonical = NULL;

    for (i = 0; i < info->nmachines; i++) {
        virCapsGuestMachinePtr machine = info->machines[i];

        if (!machine->canonical)
            continue;

5484
        if (def->os.machine && STRNEQ(def->os.machine, machine->name))
5485 5486 5487
            continue;

        if (!(*canonical = strdup(machine->canonical))) {
5488
            virReportOOMError();
5489 5490 5491 5492 5493 5494 5495 5496 5497
            return -1;
        }

        break;
    }

    return 0;
}

5498 5499 5500 5501
static int
qemudCanonicalizeMachineDirect(virDomainDefPtr def, char **canonical)
{
    virCapsGuestMachinePtr *machines = NULL;
5502
    size_t i, nmachines = 0;
5503

5504
    /* XXX we should be checking emulator capabilities and pass them instead
5505
     * of NULL so that -nodefconfig or -no-user-config is properly added when
5506 5507 5508 5509 5510 5511
     * probing machine types. Luckily, qemu does not support specifying new
     * machine types in its configuration files yet, which means passing this
     * additional parameter makes no difference now.
     */
    if (qemuCapsProbeMachineTypes(def->emulator, NULL,
                                  &machines, &nmachines) < 0)
5512 5513 5514 5515 5516 5517
        return -1;

    for (i = 0; i < nmachines; i++) {
        if (!machines[i]->canonical)
            continue;

5518
        if (def->os.machine && STRNEQ(def->os.machine, machines[i]->name))
5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530
            continue;

        *canonical = machines[i]->canonical;
        machines[i]->canonical = NULL;
        break;
    }

    virCapabilitiesFreeMachines(machines, nmachines);

    return 0;
}

5531 5532
int
qemudCanonicalizeMachine(struct qemud_driver *driver, virDomainDefPtr def)
5533 5534 5535 5536 5537 5538
{
    char *canonical = NULL;
    int i;

    for (i = 0; i < driver->caps->nguests; i++) {
        virCapsGuestPtr guest = driver->caps->guests[i];
5539
        virCapsGuestDomainInfoPtr info;
5540 5541 5542
        int j;

        for (j = 0; j < guest->arch.ndomains; j++) {
5543
            info = &guest->arch.domains[j]->info;
5544

5545 5546 5547 5548 5549 5550 5551 5552 5553
            if (!info->emulator || !STREQ(info->emulator, def->emulator))
                continue;

            if (!info->nmachines)
                info = &guest->arch.defaultInfo;

            if (qemudCanonicalizeMachineFromInfo(def, info, &canonical) < 0)
                return -1;
            goto out;
5554 5555
        }

5556 5557 5558 5559
        info = &guest->arch.defaultInfo;

        if (info->emulator && STREQ(info->emulator, def->emulator)) {
            if (qemudCanonicalizeMachineFromInfo(def, info, &canonical) < 0)
5560 5561 5562 5563
                return -1;
            goto out;
        }
    }
5564 5565 5566 5567

    if (qemudCanonicalizeMachineDirect(def, &canonical) < 0)
        return -1;

5568 5569 5570 5571 5572 5573 5574
out:
    if (canonical) {
        VIR_FREE(def->os.machine);
        def->os.machine = canonical;
    }
    return 0;
}
D
Daniel P. Berrange 已提交
5575

5576
static virDomainPtr qemudDomainDefine(virConnectPtr conn, const char *xml) {
5577
    struct qemud_driver *driver = conn->privateData;
5578
    virDomainDefPtr def;
M
Michal Privoznik 已提交
5579
    virDomainDefPtr def_backup = NULL;
5580
    virDomainObjPtr vm = NULL;
5581
    virDomainPtr dom = NULL;
5582
    virDomainEventPtr event = NULL;
5583
    int dupVM;
5584

5585
    qemuDriverLock(driver);
5586
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
5587
                                        QEMU_EXPECTED_VIRT_TYPES,
5588
                                        VIR_DOMAIN_XML_INACTIVE)))
5589
        goto cleanup;
5590

5591
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
5592 5593
        goto cleanup;

5594 5595
    if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
        goto cleanup;
5596

5597
    if (qemudCanonicalizeMachine(driver, def) < 0)
5598 5599
        goto cleanup;

5600
    if (qemuDomainAssignAddresses(def, NULL, NULL) < 0)
5601 5602
        goto cleanup;

M
Michal Privoznik 已提交
5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621
    /* We need to differentiate two cases:
     * a) updating an existing domain - must preserve previous definition
     *                                  so we can roll back if something fails
     * b) defining a brand new domain - virDomainAssignDef is just sufficient
     */
    if ((vm = virDomainFindByUUID(&driver->domains, def->uuid))) {
        if (virDomainObjIsActive(vm)) {
            def_backup = vm->newDef;
            vm->newDef = def;
        } else {
            def_backup = vm->def;
            vm->def = def;
        }
    } else {
        if (!(vm = virDomainAssignDef(driver->caps,
                                      &driver->domains,
                                      def, false))) {
            goto cleanup;
        }
5622
    }
5623
    def = NULL;
5624
    vm->persistent = 1;
5625

5626
    if (virDomainSaveConfig(driver->configDir,
5627
                            vm->newDef ? vm->newDef : vm->def) < 0) {
M
Michal Privoznik 已提交
5628 5629 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641
        if (def_backup) {
            /* There is backup so this VM was defined before.
             * Just restore the backup. */
            VIR_INFO("Restoring domain '%s' definition", vm->def->name);
            if (virDomainObjIsActive(vm))
                vm->newDef = def_backup;
            else
                vm->def = def_backup;
        } else {
            /* Brand new domain. Remove it */
            VIR_INFO("Deleting domain '%s'", vm->def->name);
            qemuDomainRemoveInactive(driver, vm);
            vm = NULL;
        }
5642
        goto cleanup;
M
Michal Privoznik 已提交
5643 5644
    } else {
        virDomainDefFree(def_backup);
5645 5646
    }

5647 5648
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
5649
                                     !dupVM ?
5650 5651
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
5652

5653
    VIR_INFO("Creating domain '%s'", vm->def->name);
5654
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
5655
    if (dom) dom->id = vm->def->id;
5656 5657

cleanup:
5658
    virDomainDefFree(def);
5659 5660
    if (vm)
        virDomainObjUnlock(vm);
5661 5662
    if (event)
        qemuDomainEventQueue(driver, event);
5663
    qemuDriverUnlock(driver);
5664
    return dom;
D
Daniel P. Berrange 已提交
5665 5666
}

5667 5668
static int
qemuDomainUndefineFlags(virDomainPtr dom,
5669
                        unsigned int flags)
5670
{
5671 5672
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
5673
    virDomainEventPtr event = NULL;
5674
    char *name = NULL;
5675
    int ret = -1;
5676
    int nsnapshots;
D
Daniel P. Berrange 已提交
5677

5678 5679
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
                  VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
5680

5681
    qemuDriverLock(driver);
5682
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
5683

D
Daniel P. Berrange 已提交
5684
    if (!vm) {
5685 5686
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5687 5688
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
5689
        goto cleanup;
D
Daniel P. Berrange 已提交
5690 5691
    }

5692
    if (!vm->persistent) {
5693 5694
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
5695 5696 5697
        goto cleanup;
    }

5698
    if (!virDomainObjIsActive(vm) &&
5699
        (nsnapshots = virDomainSnapshotObjListNum(vm->snapshots, NULL, 0))) {
5700
        if (!(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
5701 5702 5703 5704
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("cannot delete inactive domain with %d "
                             "snapshots"),
                           nsnapshots);
5705 5706
            goto cleanup;
        }
5707
        if (qemuDomainSnapshotDiscardAllMetadata(driver, vm) < 0)
5708
            goto cleanup;
5709 5710
    }

5711 5712 5713 5714 5715 5716 5717
    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    if (virFileExists(name)) {
        if (flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE) {
            if (unlink(name) < 0) {
5718 5719 5720
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to remove domain managed "
                                 "save image"));
5721 5722 5723
                goto cleanup;
            }
        } else {
5724 5725 5726
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Refusing to undefine while domain managed "
                             "save image exists"));
5727 5728 5729 5730
            goto cleanup;
        }
    }

5731
    if (virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm) < 0)
5732
        goto cleanup;
D
Daniel P. Berrange 已提交
5733

5734 5735 5736
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
5737

5738
    VIR_INFO("Undefining domain '%s'", vm->def->name);
5739 5740 5741 5742 5743 5744 5745 5746

    /* If the domain is active, keep it running but set it as transient.
     * domainDestroy and domainShutdown will take care of removing the
     * domain obj from the hash table.
     */
    if (virDomainObjIsActive(vm)) {
        vm->persistent = 0;
    } else {
5747
        qemuDomainRemoveInactive(driver, vm);
5748 5749 5750
        vm = NULL;
    }

5751
    ret = 0;
D
Daniel P. Berrange 已提交
5752

5753
cleanup:
5754
    VIR_FREE(name);
5755 5756
    if (vm)
        virDomainObjUnlock(vm);
5757 5758
    if (event)
        qemuDomainEventQueue(driver, event);
5759
    qemuDriverUnlock(driver);
5760
    return ret;
D
Daniel P. Berrange 已提交
5761 5762
}

5763 5764 5765 5766 5767 5768
static int
qemudDomainUndefine(virDomainPtr dom)
{
    return qemuDomainUndefineFlags(dom, 0);
}

5769
static int
5770 5771
qemuDomainAttachDeviceDiskLive(virConnectPtr conn,
                               struct qemud_driver *driver,
5772
                               virDomainObjPtr vm,
5773
                               virDomainDeviceDefPtr dev)
5774 5775 5776 5777
{
    virDomainDiskDefPtr disk = dev->data.disk;
    virCgroupPtr cgroup = NULL;
    int ret = -1;
5778

5779
    if (disk->driverName != NULL && !STREQ(disk->driverName, "qemu")) {
5780 5781 5782
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unsupported driver name '%s' for disk '%s'"),
                       disk->driverName, disk->src);
5783 5784 5785 5786 5787
        goto end;
    }

    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0)) {
5788 5789 5790
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to find cgroup for %s"),
                           vm->def->name);
5791 5792 5793 5794 5795 5796 5797 5798
            goto end;
        }
        if (qemuSetupDiskCgroup(driver, vm, cgroup, disk) < 0)
            goto end;
    }
    switch (disk->device)  {
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
5799
        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, false);
5800 5801
        break;
    case VIR_DOMAIN_DISK_DEVICE_DISK:
5802
    case VIR_DOMAIN_DISK_DEVICE_LUN:
5803 5804
        if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
            if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
5805 5806
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("disk device='lun' is not supported for usb bus"));
5807 5808
                break;
            }
5809
            ret = qemuDomainAttachUsbMassstorageDevice(conn, driver, vm,
5810
                                                       disk);
5811
        } else if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
5812
            ret = qemuDomainAttachPciDiskDevice(conn, driver, vm, disk);
5813
        } else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
5814
            ret = qemuDomainAttachSCSIDisk(conn, driver, vm, disk);
5815
        } else {
5816 5817 5818
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("disk bus '%s' cannot be hotplugged."),
                           virDomainDiskBusTypeToString(disk->bus));
5819
        }
5820 5821
        break;
    default:
5822 5823 5824
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk device type '%s' cannot be hotplugged"),
                       virDomainDiskDeviceTypeToString(disk->device));
5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841
        break;
    }

    if (ret != 0 && cgroup) {
        if (qemuTeardownDiskCgroup(driver, vm, cgroup, disk) < 0)
            VIR_WARN("Failed to teardown cgroup for disk path %s",
                     NULLSTR(disk->src));
    }
end:
    if (cgroup)
        virCgroupFree(&cgroup);
    return ret;
}

static int
qemuDomainAttachDeviceControllerLive(struct qemud_driver *driver,
                                     virDomainObjPtr vm,
5842
                                     virDomainDeviceDefPtr dev)
5843 5844 5845 5846 5847 5848
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
5849
        ret = qemuDomainAttachPciControllerDevice(driver, vm, cont);
5850 5851
        break;
    default:
5852 5853 5854
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk controller bus '%s' cannot be hotplugged."),
                       virDomainControllerTypeToString(cont->type));
5855 5856 5857 5858 5859 5860 5861 5862
        break;
    }
    return ret;
}

static int
qemuDomainAttachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
5863
                           virDomainPtr dom)
5864 5865 5866 5867 5868 5869
{
    struct qemud_driver *driver = dom->conn->privateData;
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
5870
        qemuDomainObjCheckDiskTaint(driver, vm, dev->data.disk, -1);
5871
        ret = qemuDomainAttachDeviceDiskLive(dom->conn, driver, vm, dev);
5872 5873 5874 5875 5876
        if (!ret)
            dev->data.disk = NULL;
        break;

    case VIR_DOMAIN_DEVICE_CONTROLLER:
5877
        ret = qemuDomainAttachDeviceControllerLive(driver, vm, dev);
5878 5879 5880 5881
        if (!ret)
            dev->data.controller = NULL;
        break;

5882 5883 5884 5885 5886 5887 5888
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainAttachLease(driver, vm,
                                    dev->data.lease);
        if (ret == 0)
            dev->data.lease = NULL;
        break;

5889
    case VIR_DOMAIN_DEVICE_NET:
5890
        qemuDomainObjCheckNetTaint(driver, vm, dev->data.net, -1);
5891
        ret = qemuDomainAttachNetDevice(dom->conn, driver, vm,
5892
                                        dev->data.net);
5893 5894 5895 5896 5897 5898
        if (!ret)
            dev->data.net = NULL;
        break;

    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = qemuDomainAttachHostDevice(driver, vm,
5899
                                         dev->data.hostdev);
5900 5901 5902 5903
        if (!ret)
            dev->data.hostdev = NULL;
        break;

5904 5905 5906 5907 5908 5909 5910
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        ret = qemuDomainAttachRedirdevDevice(driver, vm,
                                             dev->data.redirdev);
        if (!ret)
            dev->data.redirdev = NULL;
        break;

5911
    default:
5912 5913 5914
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
5915 5916 5917 5918 5919 5920 5921 5922 5923
        break;
    }

    return ret;
}

static int
qemuDomainDetachDeviceDiskLive(struct qemud_driver *driver,
                               virDomainObjPtr vm,
5924
                               virDomainDeviceDefPtr dev)
5925 5926 5927 5928 5929 5930
{
    virDomainDiskDefPtr disk = dev->data.disk;
    int ret = -1;

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_DISK:
5931
    case VIR_DOMAIN_DISK_DEVICE_LUN:
5932
        if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
5933
            ret = qemuDomainDetachPciDiskDevice(driver, vm, dev);
5934
        else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI)
5935
            ret =  qemuDomainDetachDiskDevice(driver, vm, dev);
5936
        else if (dev->data.disk->bus == VIR_DOMAIN_DISK_BUS_USB)
5937
            ret = qemuDomainDetachDiskDevice(driver, vm, dev);
5938
        else
5939 5940
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("This type of disk cannot be hot unplugged"));
5941 5942
        break;
    default:
5943 5944 5945
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk device type '%s' cannot be detached"),
                       virDomainDiskDeviceTypeToString(disk->type));
5946 5947 5948 5949 5950 5951 5952 5953
        break;
    }
    return ret;
}

static int
qemuDomainDetachDeviceControllerLive(struct qemud_driver *driver,
                                     virDomainObjPtr vm,
5954
                                     virDomainDeviceDefPtr dev)
5955 5956 5957 5958 5959 5960
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
5961
        ret = qemuDomainDetachPciControllerDevice(driver, vm, dev);
5962 5963
        break;
    default :
5964 5965 5966
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk controller bus '%s' cannot be hotunplugged."),
                       virDomainControllerTypeToString(cont->type));
5967 5968 5969 5970 5971 5972 5973
    }
    return ret;
}

static int
qemuDomainDetachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
5974
                           virDomainPtr dom)
5975 5976 5977 5978 5979 5980
{
    struct qemud_driver *driver = dom->conn->privateData;
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
5981
        ret = qemuDomainDetachDeviceDiskLive(driver, vm, dev);
5982 5983
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
5984
        ret = qemuDomainDetachDeviceControllerLive(driver, vm, dev);
5985
        break;
5986 5987 5988
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainDetachLease(driver, vm, dev->data.lease);
        break;
5989
    case VIR_DOMAIN_DEVICE_NET:
5990
        ret = qemuDomainDetachNetDevice(driver, vm, dev);
5991 5992
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
5993
        ret = qemuDomainDetachHostDevice(driver, vm, dev);
5994 5995
        break;
    default:
5996 5997
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("This type of device cannot be hot unplugged"));
5998 5999 6000 6001 6002 6003
        break;
    }

    return ret;
}

6004 6005 6006 6007 6008 6009 6010 6011
static int
qemuDomainChangeDiskMediaLive(virDomainObjPtr vm,
                              virDomainDeviceDefPtr dev,
                              struct qemud_driver *driver,
                              bool force)
{
    virDomainDiskDefPtr disk = dev->data.disk;
    virCgroupPtr cgroup = NULL;
6012
    int ret = -1;
6013 6014 6015

    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        if (virCgroupForDomain(driver->cgroup,
6016
                               vm->def->name, &cgroup, 0) != 0) {
6017 6018 6019
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to find cgroup for %s"),
                           vm->def->name);
6020 6021 6022 6023 6024 6025 6026 6027 6028
            goto end;
        }
        if (qemuSetupDiskCgroup(driver, vm, cgroup, disk) < 0)
            goto end;
    }

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
6029
        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, force);
6030 6031 6032 6033
        if (ret == 0)
            dev->data.disk = NULL;
        break;
    default:
6034 6035 6036
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk bus '%s' cannot be updated."),
                       virDomainDiskBusTypeToString(disk->bus));
6037 6038 6039 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061
        break;
    }

    if (ret != 0 && cgroup) {
        if (qemuTeardownDiskCgroup(driver, vm, cgroup, disk) < 0)
             VIR_WARN("Failed to teardown cgroup for disk path %s",
                      NULLSTR(disk->src));
    }
end:
    if (cgroup)
        virCgroupFree(&cgroup);
    return ret;
}

static int
qemuDomainUpdateDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
                           virDomainPtr dom,
                           bool force)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
6062
        ret = qemuDomainChangeDiskMediaLive(vm, dev, driver, force);
6063 6064 6065 6066
        break;
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
        break;
6067 6068 6069
    case VIR_DOMAIN_DEVICE_NET:
        ret = qemuDomainChangeNet(driver, vm, dom, dev->data.net);
        break;
6070
    default:
6071 6072 6073
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be updated"),
                       virDomainDeviceTypeToString(dev->type));
6074 6075 6076 6077 6078 6079
        break;
    }

    return ret;
}

6080
static int
6081
qemuDomainAttachDeviceConfig(virDomainDefPtr vmdef,
6082 6083
                             virDomainDeviceDefPtr dev)
{
6084
    virDomainDiskDefPtr disk;
6085
    virDomainNetDefPtr net;
6086
    virDomainHostdevDefPtr hostdev;
6087
    virDomainLeaseDefPtr lease;
6088
    virDomainControllerDefPtr controller;
6089

6090
    switch (dev->type) {
6091 6092
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6093
        if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
6094 6095
            virReportError(VIR_ERR_INVALID_ARG,
                           _("target %s already exists."), disk->dst);
6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106
            return -1;
        }
        if (virDomainDiskInsert(vmdef, disk)) {
            virReportOOMError();
            return -1;
        }
        /* vmdef has the pointer. Generic codes for vmdef will do all jobs */
        dev->data.disk = NULL;
        if (disk->bus != VIR_DOMAIN_DISK_BUS_VIRTIO)
            if (virDomainDefAddImplicitControllers(vmdef) < 0)
                return -1;
6107
        if (qemuDomainAssignAddresses(vmdef, NULL, NULL) < 0)
6108 6109 6110
            return -1;
        break;

6111 6112
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
6113
        if (virDomainNetIndexByMac(vmdef, &net->mac) >= 0) {
6114
            char macbuf[VIR_MAC_STRING_BUFLEN];
6115 6116

            virMacAddrFormat(&net->mac, macbuf);
6117 6118
            virReportError(VIR_ERR_INVALID_ARG,
                           _("mac %s already exists"), macbuf);
6119 6120 6121 6122 6123 6124 6125
            return -1;
        }
        if (virDomainNetInsert(vmdef, net)) {
            virReportOOMError();
            return -1;
        }
        dev->data.net = NULL;
6126
        if (qemuDomainAssignAddresses(vmdef, NULL, NULL) < 0)
6127 6128
            return -1;
        break;
6129

6130 6131 6132
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        hostdev = dev->data.hostdev;
        if (virDomainHostdevFind(vmdef, hostdev, NULL) >= 0) {
6133 6134
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("device is already in the domain configuration"));
6135 6136 6137 6138 6139 6140 6141
            return -1;
        }
        if (virDomainHostdevInsert(vmdef, hostdev)) {
            virReportOOMError();
            return -1;
        }
        dev->data.hostdev = NULL;
6142
        if (qemuDomainAssignAddresses(vmdef, NULL, NULL) < 0)
6143 6144 6145
            return -1;
        break;

6146 6147 6148
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
        if (virDomainLeaseIndex(vmdef, lease) >= 0) {
6149 6150 6151
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Lease %s in lockspace %s already exists"),
                           lease->key, NULLSTR(lease->lockspace));
6152 6153 6154 6155 6156 6157 6158 6159 6160
            return -1;
        }
        if (virDomainLeaseInsert(vmdef, lease) < 0)
            return -1;

        /* vmdef has the pointer. Generic codes for vmdef will do all jobs */
        dev->data.lease = NULL;
        break;

6161 6162 6163 6164 6165 6166 6167 6168 6169 6170 6171 6172 6173 6174 6175 6176 6177
    case VIR_DOMAIN_DEVICE_CONTROLLER:
        controller = dev->data.controller;
        if (virDomainControllerFind(vmdef, controller->type,
                                    controller->idx) > 0) {
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("Target already exists"));
            return -1;
        }

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

        if (qemuDomainAssignAddresses(vmdef, NULL, NULL) < 0)
            return -1;
        break;

6178
    default:
6179 6180
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("persistent attach of device is not supported"));
6181 6182 6183 6184 6185 6186 6187
         return -1;
    }
    return 0;
}


static int
6188
qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
6189 6190
                             virDomainDeviceDefPtr dev)
{
6191 6192
    virDomainDiskDefPtr disk, det_disk;
    virDomainNetDefPtr net, det_net;
6193
    virDomainHostdevDefPtr hostdev, det_hostdev;
6194
    virDomainLeaseDefPtr lease, det_lease;
6195 6196
    virDomainControllerDefPtr cont, det_cont;
    int idx;
6197

6198
    switch (dev->type) {
6199 6200
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6201
        if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) {
6202 6203
            virReportError(VIR_ERR_INVALID_ARG,
                           _("no target device %s"), disk->dst);
6204 6205
            return -1;
        }
6206
        virDomainDiskDefFree(det_disk);
6207
        break;
6208

6209 6210
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
6211
        if (!(det_net = virDomainNetRemoveByMac(vmdef, &net->mac))) {
6212 6213
            char macbuf[VIR_MAC_STRING_BUFLEN];

6214
            virMacAddrFormat(&net->mac, macbuf);
6215 6216
            virReportError(VIR_ERR_INVALID_ARG,
                           _("no nic of mac %s"), macbuf);
6217 6218
            return -1;
        }
6219
        virDomainNetDefFree(det_net);
6220
        break;
6221

6222 6223 6224
    case VIR_DOMAIN_DEVICE_HOSTDEV: {
        hostdev = dev->data.hostdev;
        if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) {
6225 6226
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("device not present in domain configuration"));
6227 6228 6229 6230 6231 6232 6233
            return -1;
        }
        virDomainHostdevRemove(vmdef, idx);
        virDomainHostdevDefFree(det_hostdev);
        break;
    }

6234 6235
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
6236
        if (!(det_lease = virDomainLeaseRemove(vmdef, lease))) {
6237 6238 6239
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Lease %s in lockspace %s does not exist"),
                           lease->key, NULLSTR(lease->lockspace));
6240 6241
            return -1;
        }
6242
        virDomainLeaseDefFree(det_lease);
6243 6244
        break;

6245 6246 6247 6248 6249 6250 6251 6252 6253 6254 6255 6256 6257
    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;

6258
    default:
6259 6260
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent detach of device is not supported"));
6261 6262 6263 6264 6265 6266
        return -1;
    }
    return 0;
}

static int
6267
qemuDomainUpdateDeviceConfig(virDomainDefPtr vmdef,
6268 6269
                             virDomainDeviceDefPtr dev)
{
6270
    virDomainDiskDefPtr orig, disk;
6271
    virDomainNetDefPtr net;
6272 6273
    int pos;

6274
    switch (dev->type) {
6275 6276
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6277
        pos = virDomainDiskIndexByName(vmdef, disk->dst, false);
6278
        if (pos < 0) {
6279 6280
            virReportError(VIR_ERR_INVALID_ARG,
                           _("target %s doesn't exist."), disk->dst);
6281 6282 6283 6284 6285
            return -1;
        }
        orig = vmdef->disks[pos];
        if (!(orig->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
            !(orig->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)) {
6286 6287
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("this disk doesn't support update"));
6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 6309
            return -1;
        }
        /*
         * Update 'orig'
         * We allow updating src/type//driverType/cachemode/
         */
        VIR_FREE(orig->src);
        orig->src = disk->src;
        orig->type = disk->type;
        orig->cachemode = disk->cachemode;
        if (disk->driverName) {
            VIR_FREE(orig->driverName);
            orig->driverName = disk->driverName;
            disk->driverName = NULL;
        }
        if (disk->driverType) {
            VIR_FREE(orig->driverType);
            orig->driverType = disk->driverType;
            disk->driverType = NULL;
        }
        disk->src = NULL;
        break;
6310 6311 6312

    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
6313
        if ((pos = virDomainNetIndexByMac(vmdef, &net->mac)) < 0) {
6314
            char macbuf[VIR_MAC_STRING_BUFLEN];
6315 6316

            virMacAddrFormat(&net->mac, macbuf);
6317 6318
            virReportError(VIR_ERR_INVALID_ARG,
                           _("mac %s doesn't exist"), macbuf);
6319 6320 6321
            return -1;
        }

6322
        virDomainNetDefFree(vmdef->nets[pos]);
6323 6324 6325 6326

        vmdef->nets[pos] = net;
        dev->data.net = NULL;

6327
        if (qemuDomainAssignAddresses(vmdef, NULL, NULL) < 0)
6328 6329 6330
            return -1;
        break;

6331
    default:
6332 6333
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent update of device is not supported"));
6334 6335 6336 6337 6338
        return -1;
    }
    return 0;
}

6339 6340 6341 6342 6343 6344 6345 6346 6347 6348 6349
/* Actions for qemuDomainModifyDeviceFlags */
enum {
    QEMU_DEVICE_ATTACH,
    QEMU_DEVICE_DETACH,
    QEMU_DEVICE_UPDATE,
};


static int
qemuDomainModifyDeviceFlags(virDomainPtr dom, const char *xml,
                            unsigned int flags, int action)
6350
{
6351
    struct qemud_driver *driver = dom->conn->privateData;
6352
    virDomainObjPtr vm = NULL;
6353
    virDomainDefPtr vmdef = NULL;
6354
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
6355
    bool force = (flags & VIR_DOMAIN_DEVICE_MODIFY_FORCE) != 0;
6356
    int ret = -1;
6357
    unsigned int affect;
6358

6359 6360
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
6361 6362 6363
                  (action == QEMU_DEVICE_UPDATE ?
                   VIR_DOMAIN_DEVICE_MODIFY_FORCE : 0), -1);

6364 6365
    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);

6366 6367 6368 6369 6370
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6371 6372
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
6373 6374 6375
        goto cleanup;
    }

6376
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
6377
        goto cleanup;
6378

6379
    if (virDomainObjIsActive(vm)) {
6380
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
6381
            flags |= VIR_DOMAIN_AFFECT_LIVE;
6382
    } else {
6383
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
6384
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
6385
        /* check consistency between flags and the vm state */
6386
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6387
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6388 6389
                           _("cannot do live update a device on "
                             "inactive domain"));
6390 6391
            goto endjob;
        }
6392
    }
6393

6394
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
6395 6396
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot modify device on transient domain"));
6397 6398
         goto endjob;
    }
6399

6400 6401 6402 6403 6404 6405 6406 6407 6408 6409 6410 6411 6412
    dev = dev_copy = virDomainDeviceDefParse(driver->caps, vm->def, xml,
                                             VIR_DOMAIN_XML_INACTIVE);
    if (dev == NULL)
        goto endjob;

    if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
        flags & VIR_DOMAIN_AFFECT_LIVE) {
        /* If we are affecting both CONFIG and LIVE
         * create a deep copy of device as adding
         * to CONFIG takes one instance.
         */
        dev_copy = virDomainDeviceDefCopy(driver->caps, vm->def, dev);
        if (!dev_copy)
6413
            goto endjob;
6414
    }
6415

6416
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6417
        if (virDomainDefCompatibleDevice(vm->def, dev) < 0)
6418 6419
            goto endjob;

6420 6421 6422 6423 6424 6425 6426 6427 6428 6429 6430 6431 6432 6433 6434
        /* Make a copy for updated domain. */
        vmdef = virDomainObjCopyPersistentDef(driver->caps, vm);
        if (!vmdef)
            goto endjob;
        switch (action) {
        case QEMU_DEVICE_ATTACH:
            ret = qemuDomainAttachDeviceConfig(vmdef, dev);
            break;
        case QEMU_DEVICE_DETACH:
            ret = qemuDomainDetachDeviceConfig(vmdef, dev);
            break;
        case QEMU_DEVICE_UPDATE:
            ret = qemuDomainUpdateDeviceConfig(vmdef, dev);
            break;
        default:
6435 6436
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown domain modify action %d"), action);
6437 6438
            break;
        }
6439

6440 6441 6442 6443 6444
        if (ret == -1)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6445 6446 6447
        if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
            goto endjob;

6448 6449
        switch (action) {
        case QEMU_DEVICE_ATTACH:
6450
            ret = qemuDomainAttachDeviceLive(vm, dev_copy, dom);
6451 6452
            break;
        case QEMU_DEVICE_DETACH:
6453
            ret = qemuDomainDetachDeviceLive(vm, dev_copy, dom);
6454 6455
            break;
        case QEMU_DEVICE_UPDATE:
6456
            ret = qemuDomainUpdateDeviceLive(vm, dev_copy, dom, force);
6457 6458
            break;
        default:
6459 6460
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown domain modify action %d"), action);
6461
            ret = -1;
6462 6463
            break;
        }
6464 6465 6466

        if (ret == -1)
            goto endjob;
6467 6468
        /*
         * update domain status forcibly because the domain status may be
6469 6470
         * changed even if we failed to attach the device. For example,
         * a new controller may be created.
6471
         */
6472
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
6473
            ret = -1;
6474 6475
            goto endjob;
        }
6476
    }
6477

6478
    /* Finally, if no error until here, we can save config. */
6479
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6480 6481 6482 6483 6484 6485
        ret = virDomainSaveConfig(driver->configDir, vmdef);
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false);
            vmdef = NULL;
        }
    }
6486 6487

endjob:
6488
    if (qemuDomainObjEndJob(driver, vm) == 0)
6489 6490 6491
        vm = NULL;

cleanup:
6492
    virDomainDefFree(vmdef);
6493 6494
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
6495 6496 6497 6498
    virDomainDeviceDefFree(dev);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
6499 6500 6501
    return ret;
}

6502 6503 6504 6505 6506 6507
static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_ATTACH);
}

6508 6509 6510
static int qemuDomainAttachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainAttachDeviceFlags(dom, xml,
6511
                                       VIR_DOMAIN_AFFECT_LIVE);
6512
}
6513

6514

6515 6516 6517 6518
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
                                       const char *xml,
                                       unsigned int flags)
{
6519
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_UPDATE);
6520 6521
}

6522 6523 6524
static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
6525
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_DETACH);
6526 6527
}

6528 6529 6530
static int qemuDomainDetachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainDetachDeviceFlags(dom, xml,
6531
                                       VIR_DOMAIN_AFFECT_LIVE);
6532 6533
}

6534
static int qemudDomainGetAutostart(virDomainPtr dom,
6535
                                   int *autostart) {
6536 6537 6538
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
6539

6540
    qemuDriverLock(driver);
6541
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
6542 6543
    qemuDriverUnlock(driver);

6544
    if (!vm) {
6545 6546
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6547 6548
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
6549
        goto cleanup;
6550 6551 6552
    }

    *autostart = vm->autostart;
6553
    ret = 0;
6554

6555
cleanup:
6556 6557
    if (vm)
        virDomainObjUnlock(vm);
6558
    return ret;
6559 6560
}

6561
static int qemudDomainSetAutostart(virDomainPtr dom,
6562
                                   int autostart) {
6563 6564
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
6565 6566
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
6567

6568
    qemuDriverLock(driver);
6569
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
6570

6571
    if (!vm) {
6572 6573
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6574 6575
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
6576
        goto cleanup;
6577 6578
    }

6579
    if (!vm->persistent) {
6580 6581
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient domain"));
6582
        goto cleanup;
6583 6584
    }

6585 6586
    autostart = (autostart != 0);

6587
    if (vm->autostart != autostart) {
6588
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
6589
            goto cleanup;
6590
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
6591
            goto cleanup;
6592

6593
        if (autostart) {
6594 6595
            if (virFileMakePath(driver->autostartDir) < 0) {
                virReportSystemError(errno,
6596 6597
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
6598 6599
                goto cleanup;
            }
6600

6601
            if (symlink(configFile, autostartLink) < 0) {
6602
                virReportSystemError(errno,
6603 6604
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
6605 6606 6607 6608
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
6609
                virReportSystemError(errno,
6610 6611
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
6612 6613
                goto cleanup;
            }
6614 6615
        }

6616
        vm->autostart = autostart;
6617
    }
6618
    ret = 0;
6619

6620 6621 6622
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
6623 6624
    if (vm)
        virDomainObjUnlock(vm);
6625
    qemuDriverUnlock(driver);
6626
    return ret;
6627 6628
}

6629

6630 6631 6632 6633 6634 6635 6636 6637 6638 6639 6640 6641 6642 6643 6644 6645 6646 6647 6648 6649 6650 6651 6652 6653 6654 6655 6656 6657 6658 6659 6660 6661 6662
/*
 * check whether the host supports CFS bandwidth
 *
 * Return 1 when CFS bandwidth is supported, 0 when CFS bandwidth is not
 * supported, -1 on error.
 */
static int qemuGetCpuBWStatus(virCgroupPtr cgroup)
{
    char *cfs_period_path = NULL;
    int ret = -1;

    if (!cgroup)
        return 0;

    if (virCgroupPathOfController(cgroup, VIR_CGROUP_CONTROLLER_CPU,
                                  "cpu.cfs_period_us", &cfs_period_path) < 0) {
        VIR_INFO("cannot get the path of cgroup CPU controller");
        ret = 0;
        goto cleanup;
    }

    if (access(cfs_period_path, F_OK) < 0) {
        ret = 0;
    } else {
        ret = 1;
    }

cleanup:
    VIR_FREE(cfs_period_path);
    return ret;
}


6663 6664 6665 6666
static char *qemuGetSchedulerType(virDomainPtr dom,
                                  int *nparams)
{
    struct qemud_driver *driver = dom->conn->privateData;
6667
    char *ret = NULL;
6668
    int rc;
6669

6670
    qemuDriverLock(driver);
6671
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
6672 6673
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
6674
        goto cleanup;
6675 6676
    }

6677 6678 6679 6680 6681 6682 6683
    if (nparams) {
        rc = qemuGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        else if (rc == 0)
            *nparams = 1;
        else
6684
            *nparams = 5;
6685
    }
6686 6687 6688

    ret = strdup("posix");
    if (!ret)
6689
        virReportOOMError();
6690 6691 6692

cleanup:
    qemuDriverUnlock(driver);
6693 6694 6695
    return ret;
}

6696 6697 6698 6699
/* deviceWeightStr in the form of /device/path,weight,/device/path,weight
 * for example, /dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0,800
 */
static int
6700 6701
qemuDomainParseDeviceWeightStr(char *deviceWeightStr,
                               virBlkioDeviceWeightPtr *dw, size_t *size)
6702 6703 6704 6705 6706 6707 6708
{
    char *temp;
    int ndevices = 0;
    int nsep = 0;
    int i;
    virBlkioDeviceWeightPtr result = NULL;

6709 6710 6711 6712 6713 6714
    *dw = NULL;
    *size = 0;

    if (STREQ(deviceWeightStr, ""))
        return 0;

6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 6739 6740 6741 6742 6743 6744 6745 6746 6747 6748 6749 6750 6751 6752 6753 6754 6755 6756 6757 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775
    temp = deviceWeightStr;
    while (temp) {
        temp = strchr(temp, ',');
        if (temp) {
            temp++;
            nsep++;
        }
    }

    /* A valid string must have even number of fields, hence an odd
     * number of commas.  */
    if (!(nsep & 1))
        goto error;

    ndevices = (nsep + 1) / 2;

    if (VIR_ALLOC_N(result, ndevices) < 0) {
        virReportOOMError();
        return -1;
    }

    i = 0;
    temp = deviceWeightStr;
    while (temp) {
        char *p = temp;

        /* device path */
        p = strchr(p, ',');
        if (!p)
            goto error;

        result[i].path = strndup(temp, p - temp);
        if (!result[i].path) {
            virReportOOMError();
            goto cleanup;
        }

        /* weight */
        temp = p + 1;

        if (virStrToLong_ui(temp, &p, 10, &result[i].weight) < 0)
            goto error;

        i++;

        if (*p == '\0')
            break;
        else if (*p != ',')
            goto error;
        temp = p + 1;
    }

    if (!i)
        VIR_FREE(result);

    *dw = result;
    *size = i;

    return 0;

error:
6776 6777
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unable to parse device weight '%s'"), deviceWeightStr);
6778 6779 6780 6781 6782 6783
cleanup:
    virBlkioDeviceWeightArrayClear(result, ndevices);
    VIR_FREE(result);
    return -1;
}

6784 6785
/* Modify dest_array to reflect all device weight changes described in
 * src_array.  */
6786
static int
6787 6788 6789 6790
qemuDomainMergeDeviceWeights(virBlkioDeviceWeightPtr *dest_array,
                             size_t *dest_size,
                             virBlkioDeviceWeightPtr src_array,
                             size_t src_size)
6791 6792
{
    int i, j;
6793
    virBlkioDeviceWeightPtr dest, src;
6794

6795
    for (i = 0; i < src_size; i++) {
6796 6797
        bool found = false;

6798 6799 6800 6801
        src = &src_array[i];
        for (j = 0; j < *dest_size; j++) {
            dest = &(*dest_array)[j];
            if (STREQ(src->path, dest->path)) {
6802
                found = true;
6803
                dest->weight = src->weight;
6804 6805 6806 6807
                break;
            }
        }
        if (!found) {
6808
            if (!src->weight)
6809
                continue;
6810
            if (VIR_EXPAND_N(*dest_array, *dest_size, 1) < 0) {
6811 6812 6813
                virReportOOMError();
                return -1;
            }
6814 6815 6816 6817
            dest = &(*dest_array)[*dest_size - 1];
            dest->path = src->path;
            dest->weight = src->weight;
            src->path = NULL;
6818 6819 6820 6821 6822 6823
        }
    }

    return 0;
}

6824 6825 6826 6827 6828
static int
qemuDomainSetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
6829 6830 6831 6832 6833
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
6834
    virDomainDefPtr persistentDef = NULL;
6835 6836
    int ret = -1;

6837 6838
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6839 6840 6841 6842 6843 6844 6845
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_BLKIO_WEIGHT,
                                       VIR_TYPED_PARAM_UINT,
                                       VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                                       VIR_TYPED_PARAM_STRING,
                                       NULL) < 0)
        return -1;
6846

6847
    qemuDriverLock(driver);
6848 6849 6850
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
6851 6852
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
6853 6854 6855
        goto cleanup;
    }

6856 6857 6858
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
6859

6860 6861
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
6862 6863
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
6864 6865 6866 6867
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
6868 6869 6870
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
6871 6872 6873 6874
            goto cleanup;
        }
    }

6875
    ret = 0;
6876 6877
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        for (i = 0; i < nparams; i++) {
6878
            int rc;
6879 6880 6881 6882
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
6883 6884
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
6885 6886 6887
                    ret = -1;
                    continue;
                }
6888

6889 6890 6891 6892 6893 6894
                rc = virCgroupSetBlkioWeight(group, params[i].value.ui);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set blkio weight tunable"));
                    ret = -1;
                }
6895
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
6896
                size_t ndevices;
6897
                virBlkioDeviceWeightPtr devices = NULL;
6898 6899
                int j;

6900 6901 6902
                if (qemuDomainParseDeviceWeightStr(params[i].value.s,
                                                   &devices,
                                                   &ndevices) < 0) {
6903 6904 6905
                    ret = -1;
                    continue;
                }
6906
                for (j = 0; j < ndevices; j++) {
6907
                    rc = virCgroupSetBlkioDeviceWeight(group,
6908 6909
                                                       devices[j].path,
                                                       devices[j].weight);
6910 6911 6912 6913
                    if (rc < 0) {
                        virReportSystemError(-rc,
                                             _("Unable to set io device weight "
                                               "for path %s"),
6914
                                             devices[j].path);
6915 6916 6917
                        break;
                    }
                }
6918 6919
                if (j != ndevices ||
                    qemuDomainMergeDeviceWeights(&vm->def->blkio.devices,
6920 6921 6922 6923 6924
                                                 &vm->def->blkio.ndevices,
                                                 devices, ndevices) < 0)
                    ret = -1;
                virBlkioDeviceWeightArrayClear(devices, ndevices);
                VIR_FREE(devices);
6925
            }
6926
        }
E
Eric Blake 已提交
6927 6928 6929 6930
    }
    if (ret < 0)
        goto cleanup;
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
6931 6932 6933
        /* Clang can't see that if we get here, persistentDef was set.  */
        sa_assert(persistentDef);

6934 6935 6936 6937 6938
        for (i = 0; i < nparams; i++) {
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
6939 6940
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
6941 6942 6943 6944 6945
                    ret = -1;
                    continue;
                }

                persistentDef->blkio.weight = params[i].value.ui;
6946 6947
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
                virBlkioDeviceWeightPtr devices = NULL;
6948
                size_t ndevices;
6949

6950 6951 6952
                if (qemuDomainParseDeviceWeightStr(params[i].value.s,
                                                   &devices,
                                                   &ndevices) < 0) {
6953 6954 6955
                    ret = -1;
                    continue;
                }
6956 6957
                if (qemuDomainMergeDeviceWeights(&persistentDef->blkio.devices,
                                                 &persistentDef->blkio.ndevices,
6958 6959 6960 6961
                                                 devices, ndevices) < 0)
                    ret = -1;
                virBlkioDeviceWeightArrayClear(devices, ndevices);
                VIR_FREE(devices);
6962 6963
            }
        }
A
Alex Jia 已提交
6964 6965 6966

        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            ret = -1;
6967 6968 6969 6970 6971 6972 6973 6974 6975 6976
    }

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

6977 6978 6979 6980 6981
static int
qemuDomainGetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
6982 6983
{
    struct qemud_driver *driver = dom->conn->privateData;
6984
    int i, j;
6985 6986
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
6987
    virDomainDefPtr persistentDef = NULL;
6988 6989 6990 6991
    unsigned int val;
    int ret = -1;
    int rc;

6992
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
6993 6994
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
6995 6996
    qemuDriverLock(driver);

6997 6998 6999
    /* 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.  */
7000 7001
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

7002 7003 7004
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
7005 7006
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7007 7008 7009 7010 7011 7012 7013 7014 7015 7016
        goto cleanup;
    }

    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = QEMU_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
    }

7017 7018 7019
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
7020

7021 7022
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
7023 7024
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
7025 7026 7027 7028
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7029 7030
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
7031 7032 7033 7034 7035
            goto cleanup;
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7036
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047
            virTypedParameterPtr param = &params[i];
            val = 0;

            switch (i) {
            case 0: /* fill blkio weight here */
                rc = virCgroupGetBlkioWeight(group, &val);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to get blkio weight"));
                    goto cleanup;
                }
7048 7049
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT, val) < 0)
7050 7051
                    goto cleanup;
                break;
7052 7053 7054 7055
            case 1: /* blkiotune.device_weight */
                if (vm->def->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;
7056

7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 7067 7068 7069 7070 7071 7072 7073
                    for (j = 0; j < vm->def->blkio.ndevices; j++) {
                        if (!vm->def->blkio.devices[j].weight)
                            continue;
                        if (comma)
                            virBufferAddChar(&buf, ',');
                        else
                            comma = true;
                        virBufferAsprintf(&buf, "%s,%u",
                                          vm->def->blkio.devices[j].path,
                                          vm->def->blkio.devices[j].weight);
                    }
                    if (virBufferError(&buf)) {
                        virReportOOMError();
                        goto cleanup;
                    }
                    param->value.s = virBufferContentAndReset(&buf);
                }
7074 7075 7076 7077
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                                            VIR_TYPED_PARAM_STRING,
                                            param->value.s) < 0)
7078 7079
                    goto cleanup;
                break;
7080 7081 7082 7083

            default:
                break;
                /* should not hit here */
7084
            }
7085 7086
        }
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7087
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
7088 7089 7090 7091 7092 7093 7094 7095
            virTypedParameterPtr param = &params[i];
            val = 0;
            param->value.ui = 0;
            param->type = VIR_TYPED_PARAM_UINT;

            switch (i) {
            case 0: /* fill blkio weight here */
                if (virStrcpyStatic(param->field, VIR_DOMAIN_BLKIO_WEIGHT) == NULL) {
7096 7097 7098
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_WEIGHT);
7099 7100 7101 7102
                    goto cleanup;
                }
                param->value.ui = persistentDef->blkio.weight;
                break;
7103

7104 7105 7106
            case 1: /* blkiotune.device_weight */
                if (persistentDef->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
7107 7108
                    bool comma = false;

7109
                    for (j = 0; j < persistentDef->blkio.ndevices; j++) {
7110 7111 7112
                        if (!persistentDef->blkio.devices[j].weight)
                            continue;
                        if (comma)
7113
                            virBufferAddChar(&buf, ',');
7114 7115
                        else
                            comma = true;
7116 7117 7118 7119 7120 7121 7122 7123 7124
                        virBufferAsprintf(&buf, "%s,%u",
                                          persistentDef->blkio.devices[j].path,
                                          persistentDef->blkio.devices[j].weight);
                    }
                    if (virBufferError(&buf)) {
                        virReportOOMError();
                        goto cleanup;
                    }
                    param->value.s = virBufferContentAndReset(&buf);
7125 7126
                }
                if (!param->value.s) {
7127 7128 7129 7130 7131 7132 7133 7134 7135
                    param->value.s = strdup("");
                    if (!param->value.s) {
                        virReportOOMError();
                        goto cleanup;
                    }
                }
                param->type = VIR_TYPED_PARAM_STRING;
                if (virStrcpyStatic(param->field,
                                    VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) == NULL) {
7136 7137 7138
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_DEVICE_WEIGHT);
7139 7140 7141 7142
                    goto cleanup;
                }
                break;

7143 7144 7145 7146
            default:
                break;
                /* should not hit here */
            }
7147 7148 7149
        }
    }

7150 7151
    if (QEMU_NB_BLKIO_PARAM < *nparams)
        *nparams = QEMU_NB_BLKIO_PARAM;
7152 7153 7154 7155 7156 7157 7158 7159 7160 7161
    ret = 0;

cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
7162

7163 7164 7165 7166 7167
static int
qemuDomainSetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int nparams,
                              unsigned int flags)
7168 7169 7170
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
7171
    virDomainDefPtr persistentDef = NULL;
7172 7173
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7174 7175 7176 7177 7178 7179
    virTypedParameterPtr hard_limit = NULL;
    virTypedParameterPtr swap_hard_limit = NULL;
    int hard_limit_index = 0;
    int swap_hard_limit_index = 0;
    unsigned long long val = 0;

7180
    int ret = -1;
7181
    int rc;
7182

7183 7184
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7185

7186 7187 7188 7189 7190 7191 7192 7193 7194
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                       VIR_TYPED_PARAM_ULLONG,
                                       NULL) < 0)
        return -1;
7195 7196 7197 7198 7199 7200

    qemuDriverLock(driver);

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
7201 7202
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7203 7204 7205
        goto cleanup;
    }

7206 7207 7208
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
7209

7210
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7211
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
7212 7213
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
7214 7215 7216 7217
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7218 7219
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
7220 7221 7222 7223
            goto cleanup;
        }
    }

7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242
    for (i = 0; i < nparams; i++) {
        if (STREQ(params[i].field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
            hard_limit = &params[i];
            hard_limit_index = i;
        } else if (STREQ(params[i].field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
            swap_hard_limit = &params[i];
            swap_hard_limit_index = i;
        }
    }

    /* It will fail if hard limit greater than swap hard limit anyway */
    if (swap_hard_limit &&
        hard_limit &&
        (hard_limit->value.ul > swap_hard_limit->value.ul)) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("hard limit must be lower than swap hard limit"));
        goto cleanup;
    }

7243 7244 7245 7246 7247 7248 7249 7250
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        /* Get current swap hard limit */
        rc = virCgroupGetMemSwapHardLimit(group, &val);
        if (rc != 0) {
            virReportSystemError(-rc, "%s",
                                 _("unable to get swap hard limit"));
            goto cleanup;
        }
7251

7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270
        /* Swap hard_limit and swap_hard_limit to ensure the setting
         * could succeed if both of them are provided.
         */
        if (swap_hard_limit && hard_limit) {
            virTypedParameter param;

            if (swap_hard_limit->value.ul > val) {
                if (hard_limit_index < swap_hard_limit_index) {
                    param = params[hard_limit_index];
                    params[hard_limit_index] = params[swap_hard_limit_index];
                    params[swap_hard_limit_index] = param;
                }
            } else {
                if (hard_limit_index > swap_hard_limit_index) {
                    param = params[hard_limit_index];
                    params[hard_limit_index] = params[swap_hard_limit_index];
                    params[swap_hard_limit_index] = param;
                }
            }
7271 7272 7273
        }
    }

7274 7275
    ret = 0;
    for (i = 0; i < nparams; i++) {
7276
        virTypedParameterPtr param = &params[i];
7277 7278

        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
7279
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7280
                rc = virCgroupSetMemoryHardLimit(group, param->value.ul);
7281 7282 7283 7284 7285 7286 7287
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set memory hard_limit tunable"));
                    ret = -1;
                }
            }

7288
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7289
                persistentDef->mem.hard_limit = param->value.ul;
7290 7291
            }
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
7292
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7293
                rc = virCgroupSetMemorySoftLimit(group, param->value.ul);
7294 7295 7296 7297 7298 7299 7300
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set memory soft_limit tunable"));
                    ret = -1;
                }
            }

7301
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7302
                persistentDef->mem.soft_limit = param->value.ul;
7303
            }
7304
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
7305
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7306
                rc = virCgroupSetMemSwapHardLimit(group, param->value.ul);
7307 7308 7309 7310 7311 7312
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set swap_hard_limit tunable"));
                    ret = -1;
                }
            }
7313
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7314
                persistentDef->mem.swap_hard_limit = param->value.ul;
7315 7316 7317 7318
            }
        }
    }

7319
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7320 7321
        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            ret = -1;
7322 7323
    }

7324 7325 7326 7327 7328 7329 7330 7331
cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

7332 7333 7334 7335 7336
static int
qemuDomainGetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int *nparams,
                              unsigned int flags)
7337 7338 7339 7340 7341
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7342
    virDomainDefPtr persistentDef = NULL;
7343 7344 7345
    int ret = -1;
    int rc;

7346
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
7347 7348
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
7349

7350
    qemuDriverLock(driver);
7351

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

7355 7356 7357
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
7358 7359
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7360 7361 7362
        goto cleanup;
    }

7363 7364 7365
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
7366

7367
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7368
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
7369 7370
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
7371 7372 7373 7374
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7375 7376
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
7377 7378 7379 7380
            goto cleanup;
        }
    }

7381 7382 7383 7384 7385 7386 7387
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = QEMU_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

7388
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7389
        for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
7390 7391 7392 7393
            virMemoryParameterPtr param = &params[i];

            switch (i) {
            case 0: /* fill memory hard limit here */
7394 7395 7396 7397
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.hard_limit) < 0)
7398 7399 7400 7401
                    goto cleanup;
                break;

            case 1: /* fill memory soft limit here */
7402 7403 7404 7405
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.soft_limit) < 0)
7406 7407 7408 7409
                    goto cleanup;
                break;

            case 2: /* fill swap hard limit here */
7410 7411 7412 7413
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.swap_hard_limit) < 0)
7414 7415 7416 7417 7418 7419 7420 7421 7422
                    goto cleanup;
                break;

            default:
                break;
                /* should not hit here */
            }
        }
        goto out;
7423 7424
    }

7425
    for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
7426
        virTypedParameterPtr param = &params[i];
7427
        unsigned long long val = 0;
7428

7429 7430 7431
        /* Coverity does not realize that if we get here, group is set.  */
        sa_assert(group);

7432
        switch (i) {
7433 7434 7435 7436 7437
        case 0: /* fill memory hard limit here */
            rc = virCgroupGetMemoryHardLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory hard limit"));
7438
                goto cleanup;
7439
            }
7440 7441 7442
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
7443
                goto cleanup;
7444 7445 7446 7447 7448 7449 7450
            break;

        case 1: /* fill memory soft limit here */
            rc = virCgroupGetMemorySoftLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory soft limit"));
7451
                goto cleanup;
7452
            }
7453 7454 7455
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
7456
                goto cleanup;
7457 7458 7459
            break;

        case 2: /* fill swap hard limit here */
7460
            rc = virCgroupGetMemSwapHardLimit(group, &val);
7461 7462 7463
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get swap hard limit"));
7464
                goto cleanup;
7465
            }
7466 7467 7468
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
7469
                goto cleanup;
7470 7471 7472 7473 7474 7475 7476 7477
            break;

        default:
            break;
            /* should not hit here */
        }
    }

7478
out:
7479 7480
    if (QEMU_NB_MEM_PARAM < *nparams)
        *nparams = QEMU_NB_MEM_PARAM;
7481 7482
    ret = 0;

7483 7484 7485 7486 7487 7488 7489 7490 7491
cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

7492 7493 7494 7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506
static int
qemuDomainSetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virDomainDefPtr persistentDef = NULL;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7507 7508 7509 7510 7511 7512 7513
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_NUMA_MODE,
                                       VIR_TYPED_PARAM_INT,
                                       VIR_DOMAIN_NUMA_NODESET,
                                       VIR_TYPED_PARAM_STRING,
                                       NULL) < 0)
        return -1;
7514 7515 7516 7517 7518 7519

    qemuDriverLock(driver);

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
7520 7521
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7522 7523 7524 7525 7526 7527 7528 7529 7530
        goto cleanup;
    }

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

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUSET)) {
7531 7532
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup cpuset controller is not mounted"));
7533 7534 7535 7536
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7537 7538 7539
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
7540 7541 7542 7543 7544 7545 7546 7547 7548 7549 7550
            goto cleanup;
        }
    }

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

        if (STREQ(param->field, VIR_DOMAIN_NUMA_MODE)) {
            if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
                vm->def->numatune.memory.mode != params[i].value.i) {
7551 7552
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("can't change numa mode for running domain"));
7553 7554 7555 7556 7557 7558 7559 7560 7561
                ret = -1;
                goto cleanup;
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
                persistentDef->numatune.memory.mode = params[i].value.i;
            }
        } else if (STREQ(param->field, VIR_DOMAIN_NUMA_NODESET)) {
            int rc;
7562
            virBitmapPtr nodeset = NULL;
7563 7564
            char *nodeset_str = NULL;

7565 7566 7567
            if (virBitmapParse(params[i].value.s,
                               0, &nodeset,
                               VIR_DOMAIN_CPUMASK_LEN) < 0) {
7568 7569 7570 7571 7572
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to parse nodeset"));
                ret = -1;
                continue;
            }
7573 7574 7575 7576

            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                if (vm->def->numatune.memory.mode !=
                    VIR_DOMAIN_NUMATUNE_MEM_STRICT) {
7577 7578 7579
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("change of nodeset for running domain "
                                     "requires strict numa mode"));
7580
                    virBitmapFree(nodeset);
7581 7582 7583
                    ret = -1;
                    continue;
                }
7584 7585

                /* Ensure the cpuset string is formated before passing to cgroup */
7586
                if (!(nodeset_str = virBitmapFormat(nodeset))) {
7587 7588
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("Failed to format nodeset"));
7589
                    virBitmapFree(nodeset);
7590 7591 7592 7593 7594
                    ret = -1;
                    continue;
                }

                if ((rc = virCgroupSetCpusetMems(group, nodeset_str) != 0)) {
7595 7596
                    virReportSystemError(-rc, "%s",
                                         _("unable to set numa tunable"));
7597
                    virBitmapFree(nodeset);
7598
                    VIR_FREE(nodeset_str);
7599 7600 7601
                    ret = -1;
                    continue;
                }
7602
                VIR_FREE(nodeset_str);
7603 7604 7605

                /* update vm->def here so that dumpxml can read the new
                 * values from vm->def. */
7606
                virBitmapFree(vm->def->numatune.memory.nodemask);
7607

7608 7609
                vm->def->numatune.memory.placement_mode =
                    VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_STATIC;
7610
                vm->def->numatune.memory.nodemask = virBitmapNewCopy(nodeset);
7611 7612 7613
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7614
                virBitmapFree(persistentDef->numatune.memory.nodemask);
7615 7616

                persistentDef->numatune.memory.nodemask = nodeset;
7617 7618
                persistentDef->numatune.memory.placement_mode =
                    VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_STATIC;
7619
                nodeset = NULL;
7620
            }
7621
            virBitmapFree(nodeset);
7622 7623 7624 7625
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7626 7627 7628
        if (!persistentDef->numatune.memory.placement_mode)
            persistentDef->numatune.memory.placement_mode =
                VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_AUTO;
7629 7630 7631 7632 7633 7634 7635 7636 7637 7638 7639 7640 7641 7642 7643 7644 7645 7646 7647 7648 7649 7650 7651 7652 7653 7654 7655 7656 7657 7658 7659 7660 7661 7662 7663 7664 7665 7666 7667 7668 7669
        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            ret = -1;
    }

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainGetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    char *nodeset = NULL;
    int ret = -1;
    int rc;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    qemuDriverLock(driver);

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

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
7670 7671
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7672 7673 7674 7675 7676 7677 7678 7679 7680 7681 7682 7683 7684 7685 7686
        goto cleanup;
    }

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

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

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
7687 7688
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
7689 7690 7691 7692
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7693 7694 7695
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
7696 7697 7698 7699 7700 7701 7702 7703 7704
            goto cleanup;
        }
    }

    for (i = 0; i < QEMU_NB_NUMA_PARAM && i < *nparams; i++) {
        virMemoryParameterPtr param = &params[i];

        switch (i) {
        case 0: /* fill numa mode here */
7705 7706
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_MODE,
                                        VIR_TYPED_PARAM_INT, 0) < 0)
7707 7708 7709 7710 7711 7712 7713 7714 7715
                goto cleanup;
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                param->value.i = persistentDef->numatune.memory.mode;
            else
                param->value.i = vm->def->numatune.memory.mode;
            break;

        case 1: /* fill numa nodeset here */
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7716 7717
                nodeset = virBitmapFormat(persistentDef->numatune.memory.nodemask);
                if (!nodeset)
7718 7719 7720 7721 7722 7723 7724 7725 7726
                    nodeset = strdup("");
            } else {
                rc = virCgroupGetCpusetMems(group, &nodeset);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to get numa nodeset"));
                    goto cleanup;
                }
            }
7727 7728
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_NODESET,
                                        VIR_TYPED_PARAM_STRING, nodeset) < 0)
7729
                goto cleanup;
S
Stefan Berger 已提交
7730 7731 7732

            nodeset = NULL;

7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745
            break;

        default:
            break;
            /* should not hit here */
        }
    }

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

cleanup:
S
Stefan Berger 已提交
7746
    VIR_FREE(nodeset);
7747 7748 7749 7750 7751 7752 7753
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765
static int
qemuSetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup,
                   unsigned long long period, long long quota)
{
    int i;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virCgroupPtr cgroup_vcpu = NULL;
    int rc;

    if (period == 0 && quota == 0)
        return 0;

W
Wen Congyang 已提交
7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776 7777 7778 7779 7780 7781 7782 7783 7784 7785
    /* If we does not know VCPU<->PID mapping or all vcpu runs in the same
     * thread, we cannot control each vcpu. So we only modify cpu bandwidth
     * when each vcpu has a separated thread.
     */
    if (priv->nvcpupids != 0 && priv->vcpupids[0] != vm->pid) {
        for (i = 0; i < priv->nvcpupids; i++) {
            rc = virCgroupForVcpu(cgroup, i, &cgroup_vcpu, 0);
            if (rc < 0) {
                virReportSystemError(-rc,
                                     _("Unable to find vcpu cgroup for %s(vcpu:"
                                       " %d)"),
                                     vm->def->name, i);
                goto cleanup;
            }

            if (qemuSetupCgroupVcpuBW(cgroup_vcpu, period, quota) < 0)
                goto cleanup;

            virCgroupFree(&cgroup_vcpu);
        }
7786 7787 7788 7789 7790 7791 7792 7793 7794
    }

    return 0;

cleanup:
    virCgroupFree(&cgroup_vcpu);
    return -1;
}

7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828
static int
qemuSetEmulatorBandwidthLive(virDomainObjPtr vm, virCgroupPtr cgroup,
                             unsigned long long period, long long quota)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virCgroupPtr cgroup_emulator = NULL;
    int rc;

    if (period == 0 && quota == 0)
        return 0;

    if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) {
        return 0;
    }

    rc = virCgroupForEmulator(cgroup, &cgroup_emulator, 0);
    if (rc < 0) {
        virReportSystemError(-rc,
                             _("Unable to find emulator cgroup for %s"),
                             vm->def->name);
        goto cleanup;
    }

    if (qemuSetupCgroupVcpuBW(cgroup_emulator, period, quota) < 0)
        goto cleanup;

    virCgroupFree(&cgroup_emulator);
    return 0;

cleanup:
    virCgroupFree(&cgroup_emulator);
    return -1;
}

7829 7830 7831 7832 7833 7834 7835 7836 7837
#define SCHED_RANGE_CHECK(VAR, NAME, MIN, MAX)                              \
    if (((VAR) > 0 && (VAR) < (MIN)) || (VAR) > (MAX)) {                    \
        virReportError(VIR_ERR_INVALID_ARG,                                 \
                       _("value of '%s' is out of range [%lld, %lld]"),     \
                       NAME, MIN, MAX);                                     \
        rc = -1;                                                            \
        goto cleanup;                                                       \
    }

7838 7839 7840 7841 7842
static int
qemuSetSchedulerParametersFlags(virDomainPtr dom,
                                virTypedParameterPtr params,
                                int nparams,
                                unsigned int flags)
7843 7844 7845 7846 7847
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7848
    virDomainDefPtr vmdef = NULL;
7849 7850
    unsigned long long value_ul;
    long long value_l;
7851
    int ret = -1;
7852
    int rc;
7853

7854 7855
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7856 7857 7858 7859 7860 7861 7862
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                       VIR_TYPED_PARAM_LLONG,
7863 7864 7865 7866
                                       VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
                                       VIR_TYPED_PARAM_LLONG,
7867 7868
                                       NULL) < 0)
        return -1;
7869

7870
    qemuDriverLock(driver);
7871 7872 7873 7874

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
7875 7876
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7877 7878 7879
        goto cleanup;
    }

7880 7881 7882
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &vmdef) < 0)
        goto cleanup;
7883

7884 7885 7886 7887 7888
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
        vmdef = virDomainObjCopyPersistentDef(driver->caps, vm);
        if (!vmdef)
            goto cleanup;
7889 7890
    }

7891
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7892
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
7893 7894
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup CPU controller is not mounted"));
7895 7896 7897
            goto cleanup;
        }
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7898 7899 7900
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
7901 7902 7903 7904
            goto cleanup;
        }
    }

7905
    for (i = 0; i < nparams; i++) {
7906
        virTypedParameterPtr param = &params[i];
7907 7908
        value_ul = param->value.ul;
        value_l = param->value.l;
7909

7910
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
7911
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7912
                if ((rc = virCgroupSetCpuShares(group, value_ul))) {
7913 7914 7915 7916
                    virReportSystemError(-rc, "%s",
                                         _("unable to set cpu shares tunable"));
                    goto cleanup;
                }
7917
                vm->def->cputune.shares = value_ul;
7918
            }
7919

7920 7921 7922
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.shares = value_ul;

7923
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
7924 7925 7926
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

7927 7928
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
                if ((rc = qemuSetVcpusBWLive(vm, group, value_ul, 0)))
7929
                    goto cleanup;
7930

7931
                vm->def->cputune.period = value_ul;
7932 7933
            }

7934
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
7935
                vmdef->cputune.period = params[i].value.ul;
7936

7937
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
7938 7939 7940
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

7941 7942
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
                if ((rc = qemuSetVcpusBWLive(vm, group, 0, value_l)))
7943
                    goto cleanup;
7944

7945
                vm->def->cputune.quota = value_l;
7946 7947
            }

7948 7949 7950
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.quota = value_l;

7951
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD)) {
7952 7953 7954
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

7955 7956
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
                if ((rc = qemuSetEmulatorBandwidthLive(vm, group, value_ul, 0)))
7957 7958
                    goto cleanup;

7959
                vm->def->cputune.emulator_period = value_ul;
7960 7961
            }

7962 7963 7964
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_period = value_ul;

7965
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA)) {
7966 7967 7968
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

7969 7970
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
                if ((rc = qemuSetEmulatorBandwidthLive(vm, group, 0, value_l)))
7971 7972
                    goto cleanup;

7973
                vm->def->cputune.emulator_quota = value_l;
7974 7975
            }

7976 7977
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_quota = value_l;
7978 7979
        }
    }
7980

7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
        goto cleanup;


    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        rc = virDomainSaveConfig(driver->configDir, vmdef);
        if (rc < 0)
            goto cleanup;

        virDomainObjAssignDef(vm, vmdef, false);
        vmdef = NULL;
    }

7994 7995 7996
    ret = 0;

cleanup:
7997
    virDomainDefFree(vmdef);
7998 7999 8000
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
8001
    qemuDriverUnlock(driver);
8002 8003
    return ret;
}
8004
#undef SCHED_RANGE_CHECK
8005

8006 8007 8008 8009
static int
qemuSetSchedulerParameters(virDomainPtr dom,
                           virTypedParameterPtr params,
                           int nparams)
8010 8011 8012 8013
{
    return qemuSetSchedulerParametersFlags(dom,
                                           params,
                                           nparams,
8014
                                           VIR_DOMAIN_AFFECT_LIVE);
8015 8016
}

8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064 8065 8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078 8079 8080 8081
static int
qemuGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
                  long long *quota)
{
    int rc;

    rc = virCgroupGetCpuCfsPeriod(cgroup, period);
    if (rc < 0) {
        virReportSystemError(-rc, "%s",
                             _("unable to get cpu bandwidth period tunable"));
        return -1;
    }

    rc = virCgroupGetCpuCfsQuota(cgroup, quota);
    if (rc < 0) {
        virReportSystemError(-rc, "%s",
                             _("unable to get cpu bandwidth tunable"));
        return -1;
    }

    return 0;
}

static int
qemuGetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup,
                   unsigned long long *period, long long *quota)
{
    virCgroupPtr cgroup_vcpu = NULL;
    qemuDomainObjPrivatePtr priv = NULL;
    int rc;
    int ret = -1;

    priv = vm->privateData;
    if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) {
        /* We do not create sub dir for each vcpu */
        rc = qemuGetVcpuBWLive(cgroup, period, quota);
        if (rc < 0)
            goto cleanup;

        if (*quota > 0)
            *quota /= vm->def->vcpus;
        goto out;
    }

    /* get period and quota for vcpu0 */
    rc = virCgroupForVcpu(cgroup, 0, &cgroup_vcpu, 0);
    if (!cgroup_vcpu) {
        virReportSystemError(-rc,
                             _("Unable to find vcpu cgroup for %s(vcpu: 0)"),
                             vm->def->name);
        goto cleanup;
    }

    rc = qemuGetVcpuBWLive(cgroup_vcpu, period, quota);
    if (rc < 0)
        goto cleanup;

out:
    ret = 0;

cleanup:
    virCgroupFree(&cgroup_vcpu);
    return ret;
}

8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118
static int
qemuGetEmulatorBandwidthLive(virDomainObjPtr vm, virCgroupPtr cgroup,
                             unsigned long long *period, long long *quota)
{
    virCgroupPtr cgroup_emulator = NULL;
    qemuDomainObjPrivatePtr priv = NULL;
    int rc;
    int ret = -1;

    priv = vm->privateData;
    if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) {
        /* We don't create sub dir for each vcpu */
        *period = 0;
        *quota = 0;
        return 0;
    }

    /* get period and quota for emulator */
    rc = virCgroupForEmulator(cgroup, &cgroup_emulator, 0);
    if (!cgroup_emulator) {
        virReportSystemError(-rc,
                             _("Unable to find emulator cgroup for %s"),
                             vm->def->name);
        goto cleanup;
    }

    rc = qemuGetVcpuBWLive(cgroup_emulator, period, quota);
    if (rc < 0)
        goto cleanup;

    ret = 0;

cleanup:
    virCgroupFree(&cgroup_emulator);
    return ret;
}

8119 8120 8121 8122 8123
static int
qemuGetSchedulerParametersFlags(virDomainPtr dom,
                                virTypedParameterPtr params,
                                int *nparams,
                                unsigned int flags)
8124 8125 8126 8127
{
    struct qemud_driver *driver = dom->conn->privateData;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
8128 8129 8130
    unsigned long long shares;
    unsigned long long period;
    long long quota;
8131 8132
    unsigned long long emulator_period;
    long long emulator_quota;
8133 8134
    int ret = -1;
    int rc;
8135
    bool cpu_bw_status = false;
8136
    int saved_nparams = 0;
8137
    virDomainDefPtr persistentDef;
8138

8139
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
8140 8141
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
8142

8143 8144
    qemuDriverLock(driver);

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

8148 8149 8150 8151 8152 8153 8154
    if (*nparams > 1) {
        rc = qemuGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        cpu_bw_status = !!rc;
    }

8155 8156 8157
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
8158 8159
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
8160 8161 8162
        goto cleanup;
    }

8163 8164 8165
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;
8166

8167
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8168 8169 8170 8171
        shares = persistentDef->cputune.shares;
        if (*nparams > 1 && cpu_bw_status) {
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
8172 8173
            emulator_period = persistentDef->cputune.emulator_period;
            emulator_quota = persistentDef->cputune.emulator_quota;
8174
        }
8175
        goto out;
8176 8177
    }

8178
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
8179 8180
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
8181 8182 8183
        goto cleanup;
    }

8184
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
8185 8186
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find cgroup for domain %s"), vm->def->name);
8187 8188 8189
        goto cleanup;
    }

8190
    rc = virCgroupGetCpuShares(group, &shares);
8191
    if (rc != 0) {
8192
        virReportSystemError(-rc, "%s",
8193 8194 8195
                             _("unable to get cpu shares tunable"));
        goto cleanup;
    }
8196 8197 8198 8199 8200 8201

    if (*nparams > 1 && cpu_bw_status) {
        rc = qemuGetVcpusBWLive(vm, group, &period, &quota);
        if (rc != 0)
            goto cleanup;
    }
8202 8203 8204 8205 8206 8207 8208 8209

    if (*nparams > 3 && cpu_bw_status) {
        rc = qemuGetEmulatorBandwidthLive(vm, group, &emulator_period,
                                          &emulator_quota);
        if (rc != 0)
            goto cleanup;
    }

8210
out:
8211 8212
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
8213
        goto cleanup;
8214 8215 8216 8217
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
8218 8219 8220
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
8221 8222 8223 8224 8225
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
8226 8227 8228
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
8229 8230 8231
                goto cleanup;
            saved_nparams++;
        }
8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249

        if (*nparams > saved_nparams) {
            if (virTypedParameterAssign(&params[3],
                                        VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG,
                                        emulator_period) < 0)
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
            if (virTypedParameterAssign(&params[4],
                                        VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
                                        VIR_TYPED_PARAM_LLONG,
                                        emulator_quota) < 0)
                goto cleanup;
            saved_nparams++;
        }
8250 8251 8252 8253
    }

    *nparams = saved_nparams;

8254 8255 8256 8257 8258 8259
    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
8260
    qemuDriverUnlock(driver);
8261 8262 8263
    return ret;
}

8264 8265 8266 8267 8268 8269
static int
qemuGetSchedulerParameters(virDomainPtr dom,
                           virTypedParameterPtr params,
                           int *nparams)
{
    return qemuGetSchedulerParametersFlags(dom, params, nparams,
8270
                                           VIR_DOMAIN_AFFECT_CURRENT);
8271
}
8272

8273 8274 8275 8276 8277 8278 8279
/**
 * Resize a block device while a guest is running. Resize to a lower size
 * is supported, but should be used with extreme caution.  Note that it
 * only supports to resize image files, it can't resize block devices
 * like LVM volumes.
 */
static int
E
Eric Blake 已提交
8280 8281 8282 8283
qemuDomainBlockResize(virDomainPtr dom,
                      const char *path,
                      unsigned long long size,
                      unsigned int flags)
8284 8285 8286 8287 8288 8289 8290 8291
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1, i;
    char *device = NULL;
    virDomainDiskDefPtr disk = NULL;

E
Eric Blake 已提交
8292
    virCheckFlags(VIR_DOMAIN_BLOCK_RESIZE_BYTES, -1);
8293 8294

    if (path[0] == '\0') {
8295 8296
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("empty path"));
8297 8298 8299
        return -1;
    }

E
Eric Blake 已提交
8300 8301 8302
    /* We prefer operating on bytes.  */
    if ((flags & VIR_DOMAIN_BLOCK_RESIZE_BYTES) == 0) {
        if (size > ULLONG_MAX / 1024) {
8303 8304 8305
            virReportError(VIR_ERR_OVERFLOW,
                           _("size must be less than %llu"),
                           ULLONG_MAX / 1024);
E
Eric Blake 已提交
8306 8307 8308
            return -1;
        }
        size *= 1024;
8309 8310 8311 8312 8313 8314 8315 8316 8317
    }

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8318 8319
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain matching uuid '%s'"), uuidstr);
8320 8321 8322 8323 8324 8325 8326 8327 8328
        goto cleanup;
    }

    priv = vm->privateData;

    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
8329 8330
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8331 8332 8333 8334
        goto endjob;
    }

    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
8335 8336
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
8337
        goto endjob;
8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366
    }
    disk = vm->def->disks[i];

    if (virAsprintf(&device, "%s%s", QEMU_DRIVE_HOST_PREFIX,
                    disk->info.alias) < 0) {
        virReportOOMError();
        goto endjob;
    }

    qemuDomainObjEnterMonitor(driver, vm);
    if (qemuMonitorBlockResize(priv->mon, device, size) < 0) {
        qemuDomainObjExitMonitor(driver, vm);
        goto endjob;
    }
    qemuDomainObjExitMonitor(driver, vm);

    ret = 0;

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

cleanup:
    VIR_FREE(device);
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

8367 8368 8369 8370 8371
/* This uses the 'info blockstats' monitor command which was
 * integrated into both qemu & kvm in late 2007.  If the command is
 * not supported we detect this and return the appropriate error.
 */
static int
8372 8373 8374
qemuDomainBlockStats(virDomainPtr dom,
                     const char *path,
                     struct _virDomainBlockStats *stats)
8375
{
8376
    struct qemud_driver *driver = dom->conn->privateData;
8377
    int i, ret = -1;
8378
    virDomainObjPtr vm;
8379
    virDomainDiskDefPtr disk = NULL;
8380
    qemuDomainObjPrivatePtr priv;
8381

8382
    qemuDriverLock(driver);
8383
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8384
    qemuDriverUnlock(driver);
8385
    if (!vm) {
8386 8387
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8388 8389
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
8390
        goto cleanup;
8391
    }
8392

8393
    if (!virDomainObjIsActive(vm)) {
8394 8395
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8396 8397 8398
        goto cleanup;
    }

8399
    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
8400 8401
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
8402
        goto cleanup;
8403
    }
8404
    disk = vm->def->disks[i];
8405

8406
    if (!disk->info.alias) {
8407 8408
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing disk device alias name for %s"), disk->dst);
8409
        goto cleanup;
8410
    }
8411

8412
    priv = vm->privateData;
8413 8414
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;
8415

8416
    if (!virDomainObjIsActive(vm)) {
8417 8418
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8419 8420
        goto endjob;
    }
8421

8422
    qemuDomainObjEnterMonitor(driver, vm);
8423 8424 8425 8426
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
                                       disk->info.alias,
                                       &stats->rd_req,
                                       &stats->rd_bytes,
8427
                                       NULL,
8428 8429
                                       &stats->wr_req,
                                       &stats->wr_bytes,
8430 8431 8432
                                       NULL,
                                       NULL,
                                       NULL,
8433 8434
                                       &stats->errs);
    qemuDomainObjExitMonitor(driver, vm);
8435

8436
endjob:
8437 8438
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;
8439

8440
cleanup:
8441 8442
    if (vm)
        virDomainObjUnlock(vm);
8443
    return ret;
8444 8445
}

8446
static int
8447 8448 8449 8450 8451
qemuDomainBlockStatsFlags(virDomainPtr dom,
                          const char *path,
                          virTypedParameterPtr params,
                          int *nparams,
                          unsigned int flags)
8452 8453 8454 8455 8456 8457 8458 8459
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i, tmp, ret = -1;
    virDomainObjPtr vm;
    virDomainDiskDefPtr disk = NULL;
    qemuDomainObjPrivatePtr priv;
    long long rd_req, rd_bytes, wr_req, wr_bytes, rd_total_times;
    long long wr_total_times, flush_req, flush_total_times, errs;
8460
    virTypedParameterPtr param;
8461

8462 8463 8464 8465
    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

    /* We don't return strings, and thus trivially support this flag.  */
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;
8466 8467 8468 8469 8470 8471 8472

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8473 8474
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
8475 8476 8477 8478
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
8479 8480
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8481 8482 8483 8484
        goto cleanup;
    }

    if (*nparams != 0) {
8485
        if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
8486 8487
            virReportError(VIR_ERR_INVALID_ARG,
                           _("invalid path: %s"), path);
8488 8489
            goto cleanup;
        }
8490
        disk = vm->def->disks[i];
8491 8492

        if (!disk->info.alias) {
8493 8494 8495
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("missing disk device alias name for %s"),
                            disk->dst);
8496 8497 8498 8499 8500 8501 8502 8503 8504 8505
             goto cleanup;
        }
    }

    priv = vm->privateData;
    VIR_DEBUG("priv=%p, params=%p, flags=%x", priv, params, flags);

    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;

8506
    if (!virDomainObjIsActive(vm)) {
8507 8508
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8509 8510 8511
        goto endjob;
    }

8512 8513 8514 8515
    qemuDomainObjEnterMonitor(driver, vm);
    tmp = *nparams;
    ret = qemuMonitorGetBlockStatsParamsNumber(priv->mon, nparams);

8516
    if (tmp == 0 || ret < 0) {
8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537
        qemuDomainObjExitMonitor(driver, vm);
        goto endjob;
    }

    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
                                       disk->info.alias,
                                       &rd_req,
                                       &rd_bytes,
                                       &rd_total_times,
                                       &wr_req,
                                       &wr_bytes,
                                       &wr_total_times,
                                       &flush_req,
                                       &flush_total_times,
                                       &errs);

    qemuDomainObjExitMonitor(driver, vm);

    if (ret < 0)
        goto endjob;

8538 8539
    tmp = 0;
    ret = -1;
8540

8541 8542
    if (tmp < *nparams && wr_bytes != -1) {
        param = &params[tmp];
8543 8544
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES,
                                    VIR_TYPED_PARAM_LLONG, wr_bytes) < 0)
8545 8546 8547
            goto endjob;
        tmp++;
    }
8548

8549
    if (tmp < *nparams && wr_req != -1) {
8550
        param = &params[tmp];
8551 8552
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ,
                                    VIR_TYPED_PARAM_LLONG, wr_req) < 0)
8553 8554 8555
            goto endjob;
        tmp++;
    }
8556

8557
    if (tmp < *nparams && rd_bytes != -1) {
8558
        param = &params[tmp];
8559 8560
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_BYTES,
                                    VIR_TYPED_PARAM_LLONG, rd_bytes) < 0)
8561 8562 8563
            goto endjob;
        tmp++;
    }
8564

8565
    if (tmp < *nparams && rd_req != -1) {
8566
        param = &params[tmp];
8567 8568
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_REQ,
                                    VIR_TYPED_PARAM_LLONG, rd_req) < 0)
8569 8570 8571
            goto endjob;
        tmp++;
    }
8572

8573
    if (tmp < *nparams && flush_req != -1) {
8574
        param = &params[tmp];
8575 8576
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ,
                                    VIR_TYPED_PARAM_LLONG, flush_req) < 0)
8577 8578 8579
            goto endjob;
        tmp++;
    }
8580

8581
    if (tmp < *nparams && wr_total_times != -1) {
8582
        param = &params[tmp];
8583 8584 8585
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, wr_total_times) < 0)
8586 8587 8588
            goto endjob;
        tmp++;
    }
8589

8590
    if (tmp < *nparams && rd_total_times != -1) {
8591
        param = &params[tmp];
8592 8593 8594
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, rd_total_times) < 0)
8595 8596 8597
            goto endjob;
        tmp++;
    }
8598

8599
    if (tmp < *nparams && flush_total_times != -1) {
8600
        param = &params[tmp];
8601 8602 8603 8604
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_FLUSH_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG,
                                    flush_total_times) < 0)
8605 8606
            goto endjob;
        tmp++;
8607 8608
    }

8609 8610 8611 8612 8613
    /* Field 'errs' is meaningless for QEMU, won't set it. */

    ret = 0;
    *nparams = tmp;

8614 8615 8616 8617 8618 8619 8620 8621 8622 8623
endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

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

8624
#ifdef __linux__
8625 8626 8627 8628 8629
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path,
                           struct _virDomainInterfaceStats *stats)
{
8630 8631
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
8632
    int i;
8633
    int ret = -1;
8634

8635
    qemuDriverLock(driver);
8636
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
8637 8638
    qemuDriverUnlock(driver);

8639
    if (!vm) {
8640 8641
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
8642 8643
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
8644
        goto cleanup;
8645 8646
    }

D
Daniel P. Berrange 已提交
8647
    if (!virDomainObjIsActive(vm)) {
8648 8649
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8650
        goto cleanup;
8651 8652 8653
    }

    /* Check the path is one of the domain's network interfaces. */
8654 8655
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
8656 8657 8658 8659
            STREQ (vm->def->nets[i]->ifname, path)) {
            ret = 0;
            break;
        }
8660 8661
    }

8662
    if (ret == 0)
8663
        ret = linuxDomainInterfaceStats(path, stats);
8664
    else
8665 8666
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path, '%s' is not a known interface"), path);
8667

8668
cleanup:
8669 8670
    if (vm)
        virDomainObjUnlock(vm);
8671 8672
    return ret;
}
8673
#else
8674 8675 8676 8677
static int
qemudDomainInterfaceStats (virDomainPtr dom,
                           const char *path ATTRIBUTE_UNUSED,
                           struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
8678
{
8679 8680
    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("interface stats not implemented on this platform"));
8681 8682
    return -1;
}
8683
#endif
8684

8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698
static int
qemuDomainSetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    virDomainNetDefPtr net = NULL, persistentNet = NULL;
8699
    virNetDevBandwidthPtr bandwidth = NULL, newBandwidth = NULL;
8700 8701 8702

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
8703 8704 8705 8706 8707 8708 8709 8710 8711 8712 8713 8714 8715 8716 8717
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_BANDWIDTH_IN_AVERAGE,
                                       VIR_TYPED_PARAM_UINT,
                                       VIR_DOMAIN_BANDWIDTH_IN_PEAK,
                                       VIR_TYPED_PARAM_UINT,
                                       VIR_DOMAIN_BANDWIDTH_IN_BURST,
                                       VIR_TYPED_PARAM_UINT,
                                       VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE,
                                       VIR_TYPED_PARAM_UINT,
                                       VIR_DOMAIN_BANDWIDTH_OUT_PEAK,
                                       VIR_TYPED_PARAM_UINT,
                                       VIR_DOMAIN_BANDWIDTH_OUT_BURST,
                                       VIR_TYPED_PARAM_UINT,
                                       NULL) < 0)
        return -1;
8718

8719
    qemuDriverLock(driver);
8720 8721 8722
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
8723 8724
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
8725 8726 8727 8728 8729 8730 8731 8732 8733 8734
        goto cleanup;
    }

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

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        net = virDomainNetFind(vm->def, device);
        if (!net) {
8735 8736
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
8737 8738 8739 8740 8741 8742
            goto cleanup;
        }
    }
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        persistentNet = virDomainNetFind(persistentDef, device);
        if (!persistentNet) {
8743 8744
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
8745 8746 8747 8748
            goto cleanup;
        }
    }

8749 8750 8751
    if ((VIR_ALLOC(bandwidth) < 0) ||
        (VIR_ALLOC(bandwidth->in) < 0) ||
        (VIR_ALLOC(bandwidth->out) < 0)) {
8752 8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767 8768 8769 8770 8771 8772 8773
        virReportOOMError();
        goto cleanup;
    }

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

        if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_IN_AVERAGE)) {
            bandwidth->in->average = params[i].value.ui;
        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_IN_PEAK)) {
            bandwidth->in->peak = params[i].value.ui;
        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_IN_BURST)) {
            bandwidth->in->burst = params[i].value.ui;
        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE)) {
            bandwidth->out->average = params[i].value.ui;
        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_OUT_PEAK)) {
            bandwidth->out->peak = params[i].value.ui;
        } else if (STREQ(param->field, VIR_DOMAIN_BANDWIDTH_OUT_BURST)) {
            bandwidth->out->burst = params[i].value.ui;
        }
    }

8774
    /* average is mandatory, peak and burst are optional. So if no
8775
     * average is given, we free inbound/outbound here which causes
8776
     * inbound/outbound to not be set. */
8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 8788 8789 8790 8791
    if (!bandwidth->in->average) {
        VIR_FREE(bandwidth->in);
    }
    if (!bandwidth->out->average) {
        VIR_FREE(bandwidth->out);
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (VIR_ALLOC(newBandwidth) < 0) {
            virReportOOMError();
            goto cleanup;
        }

        /* virNetDevBandwidthSet() will clear any previous value of
         * bandwidth parameters, so merge with old bandwidth parameters
8792
         * here to prevent them from being lost. */
8793 8794
        if (bandwidth->in ||
            (net->bandwidth && net->bandwidth->in)) {
8795 8796 8797 8798
            if (VIR_ALLOC(newBandwidth->in) < 0) {
                virReportOOMError();
                goto cleanup;
            }
8799 8800 8801 8802 8803 8804 8805

            memcpy(newBandwidth->in,
                   bandwidth->in ? bandwidth->in : net->bandwidth->in,
                   sizeof(*newBandwidth->in));
        }
        if (bandwidth->out ||
            (net->bandwidth && net->bandwidth->out)) {
8806 8807 8808 8809
            if (VIR_ALLOC(newBandwidth->out) < 0) {
                virReportOOMError();
                goto cleanup;
            }
8810 8811 8812 8813

            memcpy(newBandwidth->out,
                   bandwidth->out ? bandwidth->out : net->bandwidth->out,
                   sizeof(*newBandwidth->out));
8814 8815 8816
        }

        if (virNetDevBandwidthSet(net->ifname, newBandwidth) < 0) {
8817 8818 8819
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot set bandwidth limits on %s"),
                           device);
8820 8821 8822 8823 8824
            goto cleanup;
        }

        virNetDevBandwidthFree(net->bandwidth);
        net->bandwidth = newBandwidth;
E
Eric Blake 已提交
8825
        newBandwidth = NULL;
8826 8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841 8842 8843 8844 8845 8846 8847 8848 8849 8850
    }
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (!persistentNet->bandwidth) {
            persistentNet->bandwidth = bandwidth;
            bandwidth = NULL;
        } else {
            if (bandwidth->in) {
                VIR_FREE(persistentNet->bandwidth->in);
                persistentNet->bandwidth->in = bandwidth->in;
                bandwidth->in = NULL;
            }
            if (bandwidth->out) {
                VIR_FREE(persistentNet->bandwidth->out);
                persistentNet->bandwidth->out = bandwidth->out;
                bandwidth->out = NULL;
            }
        }

        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            goto cleanup;
    }

    ret = 0;
cleanup:
    virNetDevBandwidthFree(bandwidth);
8851
    virNetDevBandwidthFree(newBandwidth);
8852 8853 8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867 8868 8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881 8882 8883 8884 8885
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainGetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int *nparams,
                                 unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainDefPtr persistentDef = NULL;
    virDomainNetDefPtr net = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    qemuDriverLock(driver);

    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
8886 8887
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900 8901 8902 8903 8904 8905 8906
        goto cleanup;
    }

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

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

    def = persistentDef;
    if (!def)
        def = vm->def;

    net = virDomainNetFind(def, device);
    if (!net) {
8907 8908
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Can't find device %s"), device);
8909 8910 8911 8912 8913 8914
        goto cleanup;
    }

    for (i = 0; i < *nparams && i < QEMU_NB_BANDWIDTH_PARAM; i++) {
        switch(i) {
        case 0: /* inbound.average */
8915 8916 8917
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8918 8919 8920 8921 8922
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->average;
            break;
        case 1: /* inbound.peak */
8923 8924 8925
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8926 8927 8928 8929 8930
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->peak;
            break;
        case 2: /* inbound.burst */
8931 8932 8933
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8934 8935 8936 8937 8938
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->burst;
            break;
        case 3: /* outbound.average */
8939 8940 8941
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8942 8943 8944 8945 8946
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->average;
            break;
        case 4: /* outbound.peak */
8947 8948 8949
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8950 8951 8952 8953 8954
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->peak;
            break;
        case 5: /* outbound.burst */
8955 8956 8957
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8958 8959 8960 8961 8962 8963 8964 8965 8966 8967 8968 8969 8970 8971 8972 8973 8974 8975 8976 8977 8978 8979 8980
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->burst;
            break;
        default:
            break;
            /* should not hit here */
        }
    }

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

cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

8981 8982 8983
static int
qemudDomainMemoryStats (virDomainPtr dom,
                        struct _virDomainMemoryStat *stats,
8984 8985
                        unsigned int nr_stats,
                        unsigned int flags)
8986 8987 8988
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
M
Martin Kletzander 已提交
8989
    int ret = -1;
8990

8991 8992
    virCheckFlags(0, -1);

8993 8994 8995 8996 8997 8998 8999
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9000 9001
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9002 9003 9004
        goto cleanup;
    }

9005
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
9006 9007
        goto cleanup;

M
Martin Kletzander 已提交
9008
    if (!virDomainObjIsActive(vm)) {
9009 9010
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
M
Martin Kletzander 已提交
9011
    } else {
9012
        qemuDomainObjPrivatePtr priv = vm->privateData;
9013
        qemuDomainObjEnterMonitor(driver, vm);
9014
        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
9015
        qemuDomainObjExitMonitor(driver, vm);
M
Martin Kletzander 已提交
9016 9017 9018 9019

        if (ret >= 0 && ret < nr_stats) {
            long rss;
            if (qemudGetProcessInfo(NULL, NULL, &rss, vm->pid, 0) < 0) {
9020 9021
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("cannot get RSS for domain"));
M
Martin Kletzander 已提交
9022 9023 9024 9025 9026 9027 9028
            } else {
                stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_RSS;
                stats[ret].val = rss;
                ret++;
            }

        }
9029 9030
    }

9031
    if (qemuDomainObjEndJob(driver, vm) == 0)
9032 9033
        vm = NULL;

9034 9035 9036 9037 9038 9039
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}

9040 9041 9042 9043 9044
static int
qemudDomainBlockPeek (virDomainPtr dom,
                      const char *path,
                      unsigned long long offset, size_t size,
                      void *buffer,
E
Eric Blake 已提交
9045
                      unsigned int flags)
9046
{
9047 9048
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
9049 9050
    int fd = -1, ret = -1;
    const char *actual;
9051

E
Eric Blake 已提交
9052 9053
    virCheckFlags(0, -1);

9054
    qemuDriverLock(driver);
9055
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
9056 9057
    qemuDriverUnlock(driver);

9058
    if (!vm) {
9059 9060
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9061 9062
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9063
        goto cleanup;
9064 9065 9066
    }

    if (!path || path[0] == '\0') {
9067 9068
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("NULL or empty path"));
9069
        goto cleanup;
9070 9071
    }

9072 9073
    /* Check the path belongs to this domain.  */
    if (!(actual = virDomainDiskPathByName(vm->def, path))) {
9074 9075
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path '%s'"), path);
9076
        goto cleanup;
9077
    }
9078
    path = actual;
9079

9080 9081 9082 9083 9084 9085 9086
    /* The path is correct, now try to open it and get its size. */
    fd = open(path, O_RDONLY);
    if (fd == -1) {
        virReportSystemError(errno,
                             _("%s: failed to open"), path);
        goto cleanup;
    }
9087

9088 9089 9090 9091 9092 9093 9094 9095 9096
    /* Seek and read. */
    /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
     * be 64 bits on all platforms.
     */
    if (lseek(fd, offset, SEEK_SET) == (off_t) -1 ||
        saferead(fd, buffer, size) == (ssize_t) -1) {
        virReportSystemError(errno,
                             _("%s: failed to seek or read"), path);
        goto cleanup;
9097 9098
    }

9099 9100
    ret = 0;

9101
cleanup:
9102
    VIR_FORCE_CLOSE(fd);
9103 9104
    if (vm)
        virDomainObjUnlock(vm);
9105 9106 9107
    return ret;
}

R
Richard W.M. Jones 已提交
9108 9109 9110 9111 9112 9113
static int
qemudDomainMemoryPeek (virDomainPtr dom,
                       unsigned long long offset, size_t size,
                       void *buffer,
                       unsigned int flags)
{
9114 9115
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
9116
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
9117
    int fd = -1, ret = -1;
9118
    qemuDomainObjPrivatePtr priv;
R
Richard W.M. Jones 已提交
9119

9120 9121
    virCheckFlags(VIR_MEMORY_VIRTUAL | VIR_MEMORY_PHYSICAL, -1);

9122
    qemuDriverLock(driver);
9123
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
9124
    qemuDriverUnlock(driver);
R
Richard W.M. Jones 已提交
9125 9126

    if (!vm) {
9127 9128
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9129 9130
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9131 9132 9133
        goto cleanup;
    }

9134
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
9135 9136
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
9137
        goto cleanup;
R
Richard W.M. Jones 已提交
9138 9139
    }

9140
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
9141 9142
        goto cleanup;

D
Daniel P. Berrange 已提交
9143
    if (!virDomainObjIsActive(vm)) {
9144 9145
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9146
        goto endjob;
R
Richard W.M. Jones 已提交
9147 9148
    }

9149
    if (virAsprintf(&tmp, "%s/qemu.mem.XXXXXX", driver->cacheDir) < 0) {
9150
        virReportOOMError();
9151
        goto endjob;
9152 9153
    }

R
Richard W.M. Jones 已提交
9154 9155
    /* Create a temporary filename. */
    if ((fd = mkstemp (tmp)) == -1) {
9156 9157
        virReportSystemError(errno,
                             _("mkstemp(\"%s\") failed"), tmp);
9158
        goto endjob;
R
Richard W.M. Jones 已提交
9159 9160
    }

9161
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
9162

9163
    priv = vm->privateData;
9164
    qemuDomainObjEnterMonitor(driver, vm);
9165
    if (flags == VIR_MEMORY_VIRTUAL) {
9166
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
9167
            qemuDomainObjExitMonitor(driver, vm);
9168
            goto endjob;
9169
        }
9170
    } else {
9171
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
9172
            qemuDomainObjExitMonitor(driver, vm);
9173
            goto endjob;
9174
        }
R
Richard W.M. Jones 已提交
9175
    }
9176
    qemuDomainObjExitMonitor(driver, vm);
R
Richard W.M. Jones 已提交
9177 9178

    /* Read the memory file into buffer. */
9179
    if (saferead(fd, buffer, size) == (ssize_t) -1) {
9180 9181 9182
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
9183
        goto endjob;
R
Richard W.M. Jones 已提交
9184 9185 9186
    }

    ret = 0;
9187

9188
endjob:
9189
    if (qemuDomainObjEndJob(driver, vm) == 0)
9190
        vm = NULL;
9191

9192
cleanup:
9193
    VIR_FORCE_CLOSE(fd);
9194 9195
    if (tmp)
        unlink(tmp);
W
Wen Congyang 已提交
9196
    VIR_FREE(tmp);
9197 9198
    if (vm)
        virDomainObjUnlock(vm);
R
Richard W.M. Jones 已提交
9199 9200 9201
    return ret;
}

9202

9203 9204 9205 9206 9207 9208 9209 9210 9211
static int qemuDomainGetBlockInfo(virDomainPtr dom,
                                  const char *path,
                                  virDomainBlockInfoPtr info,
                                  unsigned int flags) {
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    int fd = -1;
    off_t end;
9212
    virStorageFileMetadata *meta = NULL;
9213
    virDomainDiskDefPtr disk = NULL;
9214
    struct stat sb;
9215
    int i;
9216
    int format;
9217 9218 9219 9220 9221 9222 9223 9224 9225

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9226 9227
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9228 9229 9230 9231
        goto cleanup;
    }

    if (!path || path[0] == '\0') {
9232 9233
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("NULL or empty path"));
9234 9235 9236 9237
        goto cleanup;
    }

    /* Check the path belongs to this domain. */
9238
    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
9239 9240
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path %s not assigned to domain"), path);
9241 9242
        goto cleanup;
    }
9243 9244
    disk = vm->def->disks[i];
    if (!disk->src) {
9245 9246 9247
        virReportError(VIR_ERR_INVALID_ARG,
                       _("disk %s does not currently have a source assigned"),
                       path);
9248 9249 9250
        goto cleanup;
    }
    path = disk->src;
9251 9252

    /* The path is correct, now try to open it and get its size. */
9253
    fd = open(path, O_RDONLY);
9254 9255 9256 9257 9258 9259 9260
    if (fd == -1) {
        virReportSystemError(errno,
                             _("failed to open path '%s'"), path);
        goto cleanup;
    }

    /* Probe for magic formats */
9261 9262
    if (disk->driverType) {
        if ((format = virStorageFileFormatTypeFromString(disk->driverType)) < 0) {
9263 9264 9265
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown disk format %s for %s"),
                           disk->driverType, disk->src);
9266 9267 9268
            goto cleanup;
        }
    } else {
9269 9270 9271 9272
        if (driver->allowDiskFormatProbing) {
            if ((format = virStorageFileProbeFormat(disk->src)) < 0)
                goto cleanup;
        } else {
9273 9274 9275
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no disk format for %s and probing is disabled"),
                           disk->src);
9276
            goto cleanup;
9277
        }
9278 9279
    }

9280 9281 9282 9283 9284
    if (VIR_ALLOC(meta) < 0) {
        virReportOOMError();
        goto cleanup;
    }

9285 9286
    if (virStorageFileGetMetadataFromFD(path, fd,
                                        format,
9287
                                        meta) < 0)
9288 9289 9290 9291 9292 9293 9294 9295 9296 9297
        goto cleanup;

    /* Get info for normal formats */
    if (fstat(fd, &sb) < 0) {
        virReportSystemError(errno,
                             _("cannot stat file '%s'"), path);
        goto cleanup;
    }

    if (S_ISREG(sb.st_mode)) {
9298
#ifndef WIN32
9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311
        info->physical = (unsigned long long)sb.st_blocks *
            (unsigned long long)DEV_BSIZE;
#else
        info->physical = sb.st_size;
#endif
        /* Regular files may be sparse, so logical size (capacity) is not same
         * as actual physical above
         */
        info->capacity = sb.st_size;
    } else {
        /* NB. Because we configure with AC_SYS_LARGEFILE, off_t should
         * be 64 bits on all platforms.
         */
9312
        end = lseek(fd, 0, SEEK_END);
9313 9314 9315 9316 9317 9318 9319 9320 9321 9322 9323
        if (end == (off_t)-1) {
            virReportSystemError(errno,
                                 _("failed to seek to end of %s"), path);
            goto cleanup;
        }
        info->physical = end;
        info->capacity = end;
    }

    /* If the file we probed has a capacity set, then override
     * what we calculated from file/block extents */
9324 9325
    if (meta->capacity)
        info->capacity = meta->capacity;
9326

9327
    /* Set default value .. */
9328 9329
    info->allocation = info->physical;

9330 9331 9332
    /* ..but if guest is running & not using raw
       disk format and on a block device, then query
       highest allocated extent from QEMU */
9333
    if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
9334
        format != VIR_STORAGE_FILE_RAW &&
9335 9336
        S_ISBLK(sb.st_mode) &&
        virDomainObjIsActive(vm)) {
9337
        qemuDomainObjPrivatePtr priv = vm->privateData;
9338

9339 9340
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
            goto cleanup;
9341

9342
        if (virDomainObjIsActive(vm)) {
9343
            qemuDomainObjEnterMonitor(driver, vm);
9344 9345 9346 9347
            ret = qemuMonitorGetBlockExtent(priv->mon,
                                            disk->info.alias,
                                            &info->allocation);
            qemuDomainObjExitMonitor(driver, vm);
9348
        } else {
9349
            ret = 0;
9350
        }
9351 9352 9353

        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
9354 9355 9356
    } else {
        ret = 0;
    }
9357 9358

cleanup:
9359
    virStorageFileFreeMetadata(meta);
9360
    VIR_FORCE_CLOSE(fd);
9361 9362 9363 9364 9365 9366
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
}


9367
static int
9368 9369 9370 9371
qemuDomainEventRegister(virConnectPtr conn,
                        virConnectDomainEventCallback callback,
                        void *opaque,
                        virFreeCallback freecb)
9372
{
9373 9374 9375
    struct qemud_driver *driver = conn->privateData;
    int ret;

9376
    qemuDriverLock(driver);
9377 9378 9379
    ret = virDomainEventStateRegister(conn,
                                      driver->domainEventState,
                                      callback, opaque, freecb);
9380
    qemuDriverUnlock(driver);
9381

9382
    return ret;
9383 9384
}

9385

9386
static int
9387 9388
qemuDomainEventDeregister(virConnectPtr conn,
                          virConnectDomainEventCallback callback)
9389
{
9390 9391 9392
    struct qemud_driver *driver = conn->privateData;
    int ret;

9393
    qemuDriverLock(driver);
9394 9395 9396
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
9397
    qemuDriverUnlock(driver);
9398

9399
    return ret;
9400 9401
}

9402 9403 9404 9405 9406 9407 9408 9409 9410 9411 9412 9413 9414

static int
qemuDomainEventRegisterAny(virConnectPtr conn,
                           virDomainPtr dom,
                           int eventID,
                           virConnectDomainEventGenericCallback callback,
                           void *opaque,
                           virFreeCallback freecb)
{
    struct qemud_driver *driver = conn->privateData;
    int ret;

    qemuDriverLock(driver);
9415 9416 9417 9418
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
9419
        ret = -1;
9420 9421 9422 9423 9424 9425 9426 9427 9428 9429 9430 9431 9432 9433
    qemuDriverUnlock(driver);

    return ret;
}


static int
qemuDomainEventDeregisterAny(virConnectPtr conn,
                             int callbackID)
{
    struct qemud_driver *driver = conn->privateData;
    int ret;

    qemuDriverLock(driver);
9434 9435 9436
    ret = virDomainEventStateDeregisterID(conn,
                                          driver->domainEventState,
                                          callbackID);
9437 9438 9439 9440 9441 9442
    qemuDriverUnlock(driver);

    return ret;
}


9443 9444 9445
/*******************************************************************
 * Migration Protocol Version 2
 *******************************************************************/
D
Daniel Veillard 已提交
9446

C
Chris Lalancette 已提交
9447 9448 9449 9450 9451 9452 9453 9454 9455 9456 9457 9458 9459 9460 9461
/* Prepare is the first step, and it runs on the destination host.
 *
 * This version starts an empty VM listening on a localhost TCP port, and
 * sets up the corresponding virStream to handle the incoming data.
 */
static int
qemudDomainMigratePrepareTunnel(virConnectPtr dconn,
                                virStreamPtr st,
                                unsigned long flags,
                                const char *dname,
                                unsigned long resource ATTRIBUTE_UNUSED,
                                const char *dom_xml)
{
    struct qemud_driver *driver = dconn->privateData;
    int ret = -1;
9462

9463
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9464

9465 9466
    qemuDriverLock(driver);

C
Chris Lalancette 已提交
9467
    if (!dom_xml) {
9468 9469
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
C
Chris Lalancette 已提交
9470 9471 9472
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
9473 9474
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
C
Chris Lalancette 已提交
9475 9476 9477
        goto cleanup;
    }
    if (st == NULL) {
9478 9479
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("tunnelled migration requested but NULL stream passed"));
C
Chris Lalancette 已提交
9480 9481 9482
        goto cleanup;
    }

9483
    if (virLockManagerPluginUsesState(driver->lockManager)) {
9484 9485 9486
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
9487 9488 9489
        goto cleanup;
    }

9490 9491 9492
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     NULL, 0, NULL, NULL, /* No cookies in v2 */
                                     st, dname, dom_xml);
9493

C
Chris Lalancette 已提交
9494
cleanup:
9495
    qemuDriverUnlock(driver);
C
Chris Lalancette 已提交
9496 9497 9498
    return ret;
}

D
Daniel Veillard 已提交
9499 9500 9501 9502
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
9503
static int ATTRIBUTE_NONNULL (5)
D
Daniel Veillard 已提交
9504
qemudDomainMigratePrepare2 (virConnectPtr dconn,
9505 9506
                            char **cookie ATTRIBUTE_UNUSED,
                            int *cookielen ATTRIBUTE_UNUSED,
D
Daniel Veillard 已提交
9507 9508
                            const char *uri_in,
                            char **uri_out,
C
Chris Lalancette 已提交
9509
                            unsigned long flags,
D
Daniel Veillard 已提交
9510 9511 9512 9513
                            const char *dname,
                            unsigned long resource ATTRIBUTE_UNUSED,
                            const char *dom_xml)
{
9514
    struct qemud_driver *driver = dconn->privateData;
9515
    int ret = -1;
9516

9517
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
9518

9519
    *uri_out = NULL;
D
Daniel Veillard 已提交
9520

9521
    qemuDriverLock(driver);
9522 9523

    if (virLockManagerPluginUsesState(driver->lockManager)) {
9524 9525 9526
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
9527 9528 9529
        goto cleanup;
    }

C
Chris Lalancette 已提交
9530 9531 9532 9533
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
9534 9535
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Tunnelled migration requested but invalid RPC method called"));
C
Chris Lalancette 已提交
9536 9537 9538
        goto cleanup;
    }

D
Daniel Veillard 已提交
9539
    if (!dom_xml) {
9540 9541
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
9542
        goto cleanup;
D
Daniel Veillard 已提交
9543 9544
    }

9545 9546 9547 9548
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
9549
    ret = qemuMigrationPrepareDirect(driver, dconn,
9550
                                     NULL, 0, NULL, NULL, /* No cookies */
9551 9552
                                     uri_in, uri_out,
                                     dname, dom_xml);
D
Daniel Veillard 已提交
9553

9554 9555 9556 9557
cleanup:
    qemuDriverUnlock(driver);
    return ret;
}
C
Chris Lalancette 已提交
9558

D
Daniel Veillard 已提交
9559

9560 9561 9562
/* Perform is the second step, and it runs on the source host. */
static int
qemudDomainMigratePerform (virDomainPtr dom,
9563 9564
                           const char *cookie,
                           int cookielen,
9565 9566 9567 9568 9569 9570 9571 9572
                           const char *uri,
                           unsigned long flags,
                           const char *dname,
                           unsigned long resource)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
9573
    const char *dconnuri = NULL;
9574

9575
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
9576

9577
    qemuDriverLock(driver);
9578
    if (virLockManagerPluginUsesState(driver->lockManager)) {
9579 9580 9581
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
9582 9583 9584
        goto cleanup;
    }

9585
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
9586
    if (!vm) {
9587 9588
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9589 9590
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9591
        goto cleanup;
D
Daniel Veillard 已提交
9592 9593
    }

9594 9595 9596 9597 9598
    if (flags & VIR_MIGRATE_PEER2PEER) {
        dconnuri = uri;
        uri = NULL;
    }

9599 9600 9601 9602 9603 9604
    /* Do not output cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd.
     *
     * Consume any cookie we were able to decode though
     */
9605
    ret = qemuMigrationPerform(driver, dom->conn, vm,
9606
                               NULL, dconnuri, uri, cookie, cookielen,
9607
                               NULL, NULL, /* No output cookies in v2 */
9608
                               flags, dname, resource, false);
9609

9610
cleanup:
9611
    qemuDriverUnlock(driver);
9612
    return ret;
D
Daniel Veillard 已提交
9613 9614
}

9615

D
Daniel Veillard 已提交
9616 9617 9618 9619 9620 9621 9622
/* Finish is the third and final step, and it runs on the destination host. */
static virDomainPtr
qemudDomainMigrateFinish2 (virConnectPtr dconn,
                           const char *dname,
                           const char *cookie ATTRIBUTE_UNUSED,
                           int cookielen ATTRIBUTE_UNUSED,
                           const char *uri ATTRIBUTE_UNUSED,
C
Chris Lalancette 已提交
9623
                           unsigned long flags,
D
Daniel Veillard 已提交
9624 9625
                           int retcode)
{
9626 9627 9628
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
9629

9630
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
C
Chris Lalancette 已提交
9631

9632
    qemuDriverLock(driver);
9633
    vm = virDomainFindByName(&driver->domains, dname);
D
Daniel Veillard 已提交
9634
    if (!vm) {
9635 9636
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), dname);
9637
        goto cleanup;
D
Daniel Veillard 已提交
9638 9639
    }

9640 9641 9642 9643
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
9644
    dom = qemuMigrationFinish(driver, dconn, vm,
9645
                              NULL, 0, NULL, NULL, /* No cookies */
9646
                              flags, retcode, false);
9647

9648
cleanup:
9649
    qemuDriverUnlock(driver);
9650
    return dom;
D
Daniel Veillard 已提交
9651 9652
}

9653

9654 9655 9656 9657 9658 9659
/*******************************************************************
 * Migration Protocol Version 3
 *******************************************************************/

static char *
qemuDomainMigrateBegin3(virDomainPtr domain,
9660
                        const char *xmlin,
9661 9662 9663
                        char **cookieout,
                        int *cookieoutlen,
                        unsigned long flags,
9664
                        const char *dname,
9665 9666 9667 9668 9669
                        unsigned long resource ATTRIBUTE_UNUSED)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    char *xml = NULL;
9670
    enum qemuDomainAsyncJob asyncJob;
9671

9672
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
9673 9674 9675 9676 9677 9678

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
9679 9680
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9681 9682 9683
        goto cleanup;
    }

9684 9685 9686
    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
            goto cleanup;
9687
        asyncJob = QEMU_ASYNC_JOB_MIGRATION_OUT;
9688
    } else {
W
Wen Congyang 已提交
9689
        if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
9690
            goto cleanup;
9691
        asyncJob = QEMU_ASYNC_JOB_NONE;
9692 9693 9694
    }

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

9700 9701 9702 9703
    /* Check if there is any ejected media.
     * We don't want to require them on the destination.
     */

9704
    if (qemuDomainCheckEjectableMedia(driver, vm, asyncJob) < 0)
9705 9706
        goto endjob;

9707
    if (!(xml = qemuMigrationBegin(driver, vm, xmlin, dname,
9708 9709
                                   cookieout, cookieoutlen,
                                   flags)))
9710 9711 9712 9713 9714 9715 9716
        goto endjob;

    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        /* We keep the job active across API calls until the confirm() call.
         * This prevents any other APIs being invoked while migration is taking
         * place.
         */
9717 9718 9719
        if (qemuDriverCloseCallbackSet(driver, vm, domain->conn,
                                       qemuMigrationCleanup) < 0)
            goto endjob;
9720 9721
        if (qemuMigrationJobContinue(vm) == 0) {
            vm = NULL;
9722 9723
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("domain disappeared"));
9724 9725 9726 9727 9728 9729 9730
            VIR_FREE(xml);
            if (cookieout)
                VIR_FREE(*cookieout);
        }
    } else {
        goto endjob;
    }
9731 9732

cleanup:
9733 9734
    if (vm)
        virDomainObjUnlock(vm);
9735 9736
    qemuDriverUnlock(driver);
    return xml;
9737 9738 9739 9740 9741 9742 9743 9744 9745 9746

endjob:
    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobFinish(driver, vm) == 0)
            vm = NULL;
    } else {
        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
    }
    goto cleanup;
9747 9748 9749 9750 9751 9752 9753 9754 9755 9756 9757 9758 9759 9760 9761 9762 9763 9764
}

static int
qemuDomainMigratePrepare3(virConnectPtr dconn,
                          const char *cookiein,
                          int cookieinlen,
                          char **cookieout,
                          int *cookieoutlen,
                          const char *uri_in,
                          char **uri_out,
                          unsigned long flags,
                          const char *dname,
                          unsigned long resource ATTRIBUTE_UNUSED,
                          const char *dom_xml)
{
    struct qemud_driver *driver = dconn->privateData;
    int ret = -1;

9765
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9766 9767 9768 9769 9770 9771 9772 9773

    *uri_out = NULL;

    qemuDriverLock(driver);
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
9774 9775
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Tunnelled migration requested but invalid RPC method called"));
9776 9777 9778 9779
        goto cleanup;
    }

    if (!dom_xml) {
9780 9781
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
9782 9783 9784 9785 9786 9787 9788 9789 9790 9791 9792 9793 9794 9795 9796 9797 9798 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811
        goto cleanup;
    }

    ret = qemuMigrationPrepareDirect(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
                                     uri_in, uri_out,
                                     dname, dom_xml);

cleanup:
    qemuDriverUnlock(driver);
    return ret;
}


static int
qemuDomainMigratePrepareTunnel3(virConnectPtr dconn,
                                virStreamPtr st,
                                const char *cookiein,
                                int cookieinlen,
                                char **cookieout,
                                int *cookieoutlen,
                                unsigned long flags,
                                const char *dname,
                                unsigned long resource ATTRIBUTE_UNUSED,
                                const char *dom_xml)
{
    struct qemud_driver *driver = dconn->privateData;
    int ret = -1;

9812
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9813 9814

    if (!dom_xml) {
9815 9816
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
9817 9818 9819
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
9820 9821
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
9822 9823 9824
        goto cleanup;
    }
    if (st == NULL) {
9825 9826
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("tunnelled migration requested but NULL stream passed"));
9827 9828 9829 9830 9831 9832 9833 9834 9835 9836 9837 9838 9839 9840 9841 9842 9843
        goto cleanup;
    }

    qemuDriverLock(driver);
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
                                     st, dname, dom_xml);
    qemuDriverUnlock(driver);

cleanup:
    return ret;
}


static int
qemuDomainMigratePerform3(virDomainPtr dom,
9844
                          const char *xmlin,
9845 9846 9847 9848
                          const char *cookiein,
                          int cookieinlen,
                          char **cookieout,
                          int *cookieoutlen,
9849
                          const char *dconnuri,
9850 9851 9852 9853 9854 9855 9856 9857 9858
                          const char *uri,
                          unsigned long flags,
                          const char *dname,
                          unsigned long resource)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;

9859
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9860 9861 9862 9863 9864 9865

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9866 9867
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9868 9869 9870
        goto cleanup;
    }

9871
    ret = qemuMigrationPerform(driver, dom->conn, vm, xmlin,
9872
                               dconnuri, uri, cookiein, cookieinlen,
9873
                               cookieout, cookieoutlen,
9874
                               flags, dname, resource, true);
9875 9876 9877 9878 9879 9880 9881

cleanup:
    qemuDriverUnlock(driver);
    return ret;
}


9882
static virDomainPtr
9883 9884 9885 9886 9887 9888
qemuDomainMigrateFinish3(virConnectPtr dconn,
                         const char *dname,
                         const char *cookiein,
                         int cookieinlen,
                         char **cookieout,
                         int *cookieoutlen,
9889
                         const char *dconnuri ATTRIBUTE_UNUSED,
9890 9891
                         const char *uri ATTRIBUTE_UNUSED,
                         unsigned long flags,
9892
                         int cancelled)
9893 9894 9895
{
    struct qemud_driver *driver = dconn->privateData;
    virDomainObjPtr vm;
9896
    virDomainPtr dom = NULL;
9897

9898
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
9899 9900 9901 9902

    qemuDriverLock(driver);
    vm = virDomainFindByName(&driver->domains, dname);
    if (!vm) {
9903 9904
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), dname);
9905 9906 9907
        goto cleanup;
    }

9908 9909 9910 9911
    dom = qemuMigrationFinish(driver, dconn, vm,
                              cookiein, cookieinlen,
                              cookieout, cookieoutlen,
                              flags, cancelled, true);
9912 9913 9914

cleanup:
    qemuDriverUnlock(driver);
9915
    return dom;
9916 9917 9918 9919 9920 9921 9922 9923 9924 9925 9926 9927
}

static int
qemuDomainMigrateConfirm3(virDomainPtr domain,
                          const char *cookiein,
                          int cookieinlen,
                          unsigned long flags,
                          int cancelled)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
9928
    enum qemuMigrationJobPhase phase;
9929

9930
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9931 9932 9933 9934 9935 9936

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
9937 9938
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9939 9940 9941
        goto cleanup;
    }

9942
    if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_OUT))
9943 9944
        goto cleanup;

9945 9946 9947 9948 9949 9950
    if (cancelled)
        phase = QEMU_MIGRATION_PHASE_CONFIRM3_CANCELLED;
    else
        phase = QEMU_MIGRATION_PHASE_CONFIRM3;

    qemuMigrationJobStartPhase(driver, vm, phase);
9951
    qemuDriverCloseCallbackUnset(driver, vm, qemuMigrationCleanup);
9952

9953 9954
    ret = qemuMigrationConfirm(driver, domain->conn, vm,
                               cookiein, cookieinlen,
9955 9956
                               flags, cancelled);

9957
    if (qemuMigrationJobFinish(driver, vm) == 0) {
9958 9959 9960 9961 9962
        vm = NULL;
    } else if (!virDomainObjIsActive(vm) &&
               (!vm->persistent || (flags & VIR_MIGRATE_UNDEFINE_SOURCE))) {
        if (flags & VIR_MIGRATE_UNDEFINE_SOURCE)
            virDomainDeleteConfig(driver->configDir, driver->autostartDir, vm);
9963
        qemuDomainRemoveInactive(driver, vm);
9964 9965 9966
        vm = NULL;
    }

9967
cleanup:
9968 9969
    if (vm)
        virDomainObjUnlock(vm);
9970 9971 9972 9973 9974
    qemuDriverUnlock(driver);
    return ret;
}


9975 9976 9977 9978 9979 9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990
static int
qemudNodeDeviceGetPciInfo (virNodeDevicePtr dev,
                           unsigned *domain,
                           unsigned *bus,
                           unsigned *slot,
                           unsigned *function)
{
    virNodeDeviceDefPtr def = NULL;
    virNodeDevCapsDefPtr cap;
    char *xml = NULL;
    int ret = -1;

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

9991
    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
9992 9993 9994 9995 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008
    if (!def)
        goto out;

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

        cap = cap->next;
    }

    if (!cap) {
10009 10010
        virReportError(VIR_ERR_INVALID_ARG,
                       _("device %s is not a PCI device"), dev->name);
10011 10012 10013 10014 10015 10016 10017 10018 10019 10020 10021 10022 10023
        goto out;
    }

    ret = 0;
out:
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
qemudNodeDeviceDettach (virNodeDevicePtr dev)
{
10024
    struct qemud_driver *driver = dev->conn->privateData;
10025 10026 10027
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;
10028
    bool in_inactive_list = false;
10029 10030 10031 10032

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

10033
    pci = pciGetDevice(domain, bus, slot, function);
10034 10035 10036
    if (!pci)
        return -1;

10037
    qemuDriverLock(driver);
10038 10039 10040 10041
    in_inactive_list = pciDeviceListFind(driver->inactivePciHostdevs, pci);

    if (pciDettachDevice(pci, driver->activePciHostdevs,
                         driver->inactivePciHostdevs) < 0)
10042 10043 10044 10045
        goto out;

    ret = 0;
out:
10046
    qemuDriverUnlock(driver);
10047 10048
    if (in_inactive_list)
        pciFreeDevice(pci);
10049 10050 10051 10052 10053 10054
    return ret;
}

static int
qemudNodeDeviceReAttach (virNodeDevicePtr dev)
{
10055
    struct qemud_driver *driver = dev->conn->privateData;
10056
    pciDevice *pci;
10057
    pciDevice *other;
10058 10059 10060 10061 10062 10063
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

10064
    pci = pciGetDevice(domain, bus, slot, function);
10065 10066 10067
    if (!pci)
        return -1;

10068 10069 10070 10071 10072
    other = pciDeviceListFind(driver->activePciHostdevs, pci);
    if (other) {
        const char *other_name = pciDeviceGetUsedBy(other);

        if (other_name)
10073 10074 10075
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is still in use by domain %s"),
                           pciDeviceGetName(pci), other_name);
10076
        else
10077 10078 10079
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is still in use"),
                           pciDeviceGetName(pci));
10080 10081
    }

10082 10083
    pciDeviceReAttachInit(pci);

10084
    qemuDriverLock(driver);
10085 10086
    if (pciReAttachDevice(pci, driver->activePciHostdevs,
                          driver->inactivePciHostdevs) < 0)
10087 10088 10089 10090
        goto out;

    ret = 0;
out:
10091
    qemuDriverUnlock(driver);
10092
    pciFreeDevice(pci);
10093 10094 10095 10096 10097 10098
    return ret;
}

static int
qemudNodeDeviceReset (virNodeDevicePtr dev)
{
10099
    struct qemud_driver *driver = dev->conn->privateData;
10100 10101 10102 10103 10104 10105 10106
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

    if (qemudNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
        return -1;

10107
    pci = pciGetDevice(domain, bus, slot, function);
10108 10109 10110
    if (!pci)
        return -1;

10111 10112
    qemuDriverLock(driver);

10113 10114
    if (pciResetDevice(pci, driver->activePciHostdevs,
                       driver->inactivePciHostdevs) < 0)
10115 10116 10117 10118
        goto out;

    ret = 0;
out:
10119
    qemuDriverUnlock(driver);
10120
    pciFreeDevice(pci);
10121 10122 10123
    return ret;
}

10124 10125 10126
static int
qemuCPUCompare(virConnectPtr conn,
               const char *xmlDesc,
E
Eric Blake 已提交
10127
               unsigned int flags)
10128 10129 10130 10131
{
    struct qemud_driver *driver = conn->privateData;
    int ret = VIR_CPU_COMPARE_ERROR;

E
Eric Blake 已提交
10132 10133
    virCheckFlags(0, VIR_CPU_COMPARE_ERROR);

10134 10135
    qemuDriverLock(driver);

10136
    if (!driver->caps) {
10137 10138
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot get host capabilities"));
10139 10140 10141
    } else if (!driver->caps->host.cpu) {
        VIR_WARN("cannot get host CPU capabilities");
        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
E
Eric Blake 已提交
10142
    } else {
10143
        ret = cpuCompareXML(driver->caps->host.cpu, xmlDesc);
E
Eric Blake 已提交
10144
    }
10145 10146 10147 10148 10149 10150

    qemuDriverUnlock(driver);

    return ret;
}

10151

10152 10153 10154 10155
static char *
qemuCPUBaseline(virConnectPtr conn ATTRIBUTE_UNUSED,
                const char **xmlCPUs,
                unsigned int ncpus,
E
Eric Blake 已提交
10156
                unsigned int flags)
10157 10158 10159
{
    char *cpu;

E
Eric Blake 已提交
10160 10161
    virCheckFlags(0, NULL);

10162 10163 10164 10165 10166
    cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0);

    return cpu;
}

10167 10168 10169 10170 10171 10172 10173 10174 10175 10176 10177 10178 10179 10180

static int qemuDomainGetJobInfo(virDomainPtr dom,
                                virDomainJobInfoPtr info) {
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
10181 10182
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
10183 10184 10185 10186 10187 10188
        goto cleanup;
    }

    priv = vm->privateData;

    if (virDomainObjIsActive(vm)) {
10189
        if (priv->job.asyncJob && !priv->job.dump_memory_only) {
10190
            memcpy(info, &priv->job.info, sizeof(*info));
10191 10192 10193 10194 10195 10196

            /* Refresh elapsed time again just to ensure it
             * is fully updated. This is primarily for benefit
             * of incoming migration which we don't currently
             * monitor actively in the background thread
             */
10197
            if (virTimeMillisNow(&info->timeElapsed) < 0)
10198
                goto cleanup;
10199
            info->timeElapsed -= priv->job.start;
10200 10201 10202 10203 10204
        } else {
            memset(info, 0, sizeof(*info));
            info->type = VIR_DOMAIN_JOB_NONE;
        }
    } else {
10205 10206
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10207 10208 10209 10210 10211 10212 10213 10214 10215 10216 10217 10218
        goto cleanup;
    }

    ret = 0;

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


10219 10220 10221 10222 10223 10224 10225 10226 10227 10228 10229 10230
static int qemuDomainAbortJob(virDomainPtr dom) {
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
10231 10232
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
10233 10234 10235
        goto cleanup;
    }

10236 10237
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_ABORT) < 0)
        goto cleanup;
10238

10239
    if (!virDomainObjIsActive(vm)) {
10240 10241
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10242
        goto endjob;
10243 10244
    }

10245 10246
    priv = vm->privateData;

10247
    if (!priv->job.asyncJob || priv->job.dump_memory_only) {
10248 10249
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("no job is active on the domain"));
10250 10251
        goto endjob;
    } else if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) {
10252 10253 10254
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot abort incoming migration;"
                         " use virDomainDestroy instead"));
10255 10256 10257 10258
        goto endjob;
    }

    VIR_DEBUG("Cancelling job at client request");
10259
    qemuDomainObjEnterMonitor(driver, vm);
10260 10261 10262 10263 10264 10265
    ret = qemuMonitorMigrateCancel(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;
10266 10267 10268 10269 10270 10271 10272 10273

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


10274 10275 10276 10277 10278 10279 10280 10281 10282 10283
static int
qemuDomainMigrateSetMaxDowntime(virDomainPtr dom,
                                unsigned long long downtime,
                                unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

10284
    virCheckFlags(0, -1);
10285 10286 10287

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
10288
    qemuDriverUnlock(driver);
10289 10290 10291 10292

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
10293 10294
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
10295
        return -1;
10296 10297
    }

10298 10299 10300
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
        goto cleanup;

10301
    if (!virDomainObjIsActive(vm)) {
10302 10303
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10304
        goto endjob;
10305 10306 10307 10308
    }

    priv = vm->privateData;

10309
    if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
10310 10311
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not being migrated"));
10312
        goto endjob;
10313 10314
    }

10315
    VIR_DEBUG("Setting migration downtime to %llums", downtime);
10316
    qemuDomainObjEnterMonitor(driver, vm);
10317 10318 10319 10320 10321 10322
    ret = qemuMonitorSetMigrationDowntime(priv->mon, downtime);
    qemuDomainObjExitMonitor(driver, vm);

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;
10323 10324 10325 10326 10327 10328 10329

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

10330 10331 10332 10333 10334 10335 10336 10337 10338 10339 10340 10341 10342 10343
static int
qemuDomainMigrateSetMaxSpeed(virDomainPtr dom,
                             unsigned long bandwidth,
                             unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
10344
    qemuDriverUnlock(driver);
10345 10346 10347 10348

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
10349 10350
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
10351
        return -1;
10352 10353 10354
    }

    priv = vm->privateData;
10355 10356 10357
    if (virDomainObjIsActive(vm)) {
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
            goto cleanup;
10358

10359
        if (!virDomainObjIsActive(vm)) {
10360 10361
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("domain is not running"));
10362 10363 10364
            goto endjob;
        }

10365 10366 10367 10368
        VIR_DEBUG("Setting migration bandwidth to %luMbs", bandwidth);
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSetMigrationSpeed(priv->mon, bandwidth);
        qemuDomainObjExitMonitor(driver, vm);
10369

10370 10371
        if (ret == 0)
            priv->migMaxBandwidth = bandwidth;
10372

10373
endjob:
10374 10375 10376 10377 10378 10379
        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
    } else {
        priv->migMaxBandwidth = bandwidth;
        ret = 0;
    }
10380 10381 10382 10383 10384 10385 10386

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

10387 10388 10389 10390 10391 10392 10393
static int
qemuDomainMigrateGetMaxSpeed(virDomainPtr dom,
                             unsigned long *bandwidth,
                             unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
10394
    qemuDomainObjPrivatePtr priv;
10395 10396 10397 10398 10399 10400 10401 10402 10403 10404 10405
    int ret = -1;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
10406 10407
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
10408 10409 10410
        goto cleanup;
    }

J
Jim Fehlig 已提交
10411 10412
    priv = vm->privateData;
    *bandwidth = priv->migMaxBandwidth;
10413 10414 10415 10416 10417 10418 10419 10420
    ret = 0;

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

10421 10422
static bool
qemuDomainSnapshotIsAllowed(virDomainObjPtr vm)
C
Chris Lalancette 已提交
10423 10424 10425 10426 10427 10428 10429 10430
{
    int i;

    /* FIXME: we need to figure out what else here might succeed; in
     * particular, if it's a raw device but on LVM, we could probably make
     * that succeed as well
     */
    for (i = 0; i < vm->def->ndisks; i++) {
10431 10432 10433 10434 10435 10436 10437 10438 10439
        virDomainDiskDefPtr disk = vm->def->disks[i];
        if (disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
            (disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG ||
             disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD))
            continue;

        if ((disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) ||
            (disk->device == VIR_DOMAIN_DISK_DEVICE_DISK &&
             STRNEQ_NULLABLE(disk->driverType, "qcow2"))) {
10440 10441 10442
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("Disk '%s' does not support snapshotting"),
                           disk->src);
10443
            return false;
C
Chris Lalancette 已提交
10444 10445 10446
        }
    }

10447
    return true;
C
Chris Lalancette 已提交
10448 10449
}

10450 10451 10452 10453 10454 10455 10456
static int
qemuDomainSnapshotFSFreeze(struct qemud_driver *driver,
                           virDomainObjPtr vm) {
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int freezed;

    if (priv->agentError) {
10457
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
10458 10459
                       _("QEMU guest agent is not "
                         "available due to an error"));
10460 10461 10462
        return -1;
    }
    if (!priv->agent) {
10463 10464
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("QEMU guest agent is not configured"));
10465 10466 10467 10468 10469 10470 10471 10472 10473 10474 10475 10476
        return -1;
    }

    qemuDomainObjEnterAgent(driver, vm);
    freezed = qemuAgentFSFreeze(priv->agent);
    qemuDomainObjExitAgent(driver, vm);

    return freezed;
}

static int
qemuDomainSnapshotFSThaw(struct qemud_driver *driver,
E
Eric Blake 已提交
10477 10478
                         virDomainObjPtr vm, bool report)
{
10479 10480
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int thawed;
E
Eric Blake 已提交
10481
    virErrorPtr err = NULL;
10482 10483

    if (priv->agentError) {
E
Eric Blake 已提交
10484
        if (report)
10485
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
10486 10487
                           _("QEMU guest agent is not "
                             "available due to an error"));
10488 10489 10490
        return -1;
    }
    if (!priv->agent) {
E
Eric Blake 已提交
10491
        if (report)
10492 10493
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
10494 10495 10496 10497
        return -1;
    }

    qemuDomainObjEnterAgent(driver, vm);
E
Eric Blake 已提交
10498
    if (!report)
10499
        err = virSaveLastError();
10500
    thawed = qemuAgentFSThaw(priv->agent);
10501 10502
    if (!report)
        virSetError(err);
10503 10504
    qemuDomainObjExitAgent(driver, vm);

10505
    virFreeError(err);
10506 10507 10508
    return thawed;
}

10509 10510
/* The domain is expected to be locked and inactive. */
static int
E
Eric Blake 已提交
10511 10512
qemuDomainSnapshotCreateInactive(struct qemud_driver *driver,
                                 virDomainObjPtr vm,
10513 10514
                                 virDomainSnapshotObjPtr snap)
{
E
Eric Blake 已提交
10515
    return qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-c", false);
10516 10517
}

10518 10519
/* The domain is expected to be locked and active. */
static int
10520 10521
qemuDomainSnapshotCreateActive(virConnectPtr conn,
                               struct qemud_driver *driver,
10522
                               virDomainObjPtr *vmptr,
10523 10524
                               virDomainSnapshotObjPtr snap,
                               unsigned int flags)
10525 10526 10527
{
    virDomainObjPtr vm = *vmptr;
    qemuDomainObjPrivatePtr priv = vm->privateData;
10528 10529
    bool resume = false;
    int ret = -1;
10530

10531
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
10532 10533
        return -1;

10534
    if (!virDomainObjIsActive(vm)) {
10535 10536
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10537 10538 10539
        goto endjob;
    }

J
Jiri Denemark 已提交
10540
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
10541 10542 10543 10544
        /* savevm monitor command pauses the domain emitting an event which
         * confuses libvirt since it's not notified when qemu resumes the
         * domain. Thus we stop and start CPUs ourselves.
         */
10545 10546
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_NONE) < 0)
10547 10548 10549 10550
            goto cleanup;

        resume = true;
        if (!virDomainObjIsActive(vm)) {
10551 10552
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
10553 10554 10555 10556
            goto cleanup;
        }
    }

10557
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
10558 10559
    ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
10560 10561 10562 10563 10564 10565 10566 10567
    if (ret < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
        virDomainEventPtr event;

        event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
10568
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
10569 10570 10571 10572 10573 10574 10575 10576 10577
        virDomainAuditStop(vm, "from-snapshot");
        /* We already filtered the _HALT flag for persistent domains
         * only, so this end job never drops the last reference.  */
        ignore_value(qemuDomainObjEndJob(driver, vm));
        resume = false;
        vm = NULL;
        if (event)
            qemuDomainEventQueue(driver, event);
    }
10578

10579 10580
cleanup:
    if (resume && virDomainObjIsActive(vm) &&
J
Jiri Denemark 已提交
10581
        qemuProcessStartCPUs(driver, vm, conn,
10582 10583
                             VIR_DOMAIN_RUNNING_UNPAUSED,
                             QEMU_ASYNC_JOB_NONE) < 0 &&
10584
        virGetLastError() == NULL) {
10585 10586
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("resuming after snapshot failed"));
10587 10588
    }

10589
endjob:
10590
    if (vm && qemuDomainObjEndJob(driver, vm) == 0) {
10591 10592
        /* Only possible if a transient vm quit while our locks were down,
         * in which case we don't want to save snapshot metadata.  */
10593
        *vmptr = NULL;
10594 10595
        ret = -1;
    }
10596 10597 10598 10599

    return ret;
}

10600
static int
10601
qemuDomainSnapshotDiskPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def,
10602
                              unsigned int *flags)
10603 10604 10605 10606 10607 10608
{
    int ret = -1;
    int i;
    bool found = false;
    bool active = virDomainObjIsActive(vm);
    struct stat st;
10609 10610 10611 10612
    bool allow_reuse = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
    bool atomic = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC) != 0;
    int external = 0;
    qemuDomainObjPrivatePtr priv = vm->privateData;
10613

10614
    if (allow_reuse && !qemuCapsGet(priv->caps, QEMU_CAPS_TRANSACTION)) {
10615 10616
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("reuse is not supported with this QEMU binary"));
10617 10618 10619
        goto cleanup;
    }

10620 10621 10622 10623
    for (i = 0; i < def->ndisks; i++) {
        virDomainSnapshotDiskDefPtr disk = &def->disks[i];

        switch (disk->snapshot) {
E
Eric Blake 已提交
10624
        case VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL:
10625
            if (active) {
10626 10627 10628 10629
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("active qemu domains require external disk "
                                 "snapshots; disk %s requested internal"),
                               disk->name);
10630 10631 10632 10633
                goto cleanup;
            }
            if (!vm->def->disks[i]->driverType ||
                STRNEQ(vm->def->disks[i]->driverType, "qcow2")) {
10634 10635 10636 10637 10638
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("internal snapshot for disk %s unsupported "
                                 "for storage type %s"),
                               disk->name,
                               NULLSTR(vm->def->disks[i]->driverType));
10639 10640 10641 10642 10643
                goto cleanup;
            }
            found = true;
            break;

E
Eric Blake 已提交
10644
        case VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL:
10645 10646 10647 10648 10649
            if (!disk->driverType) {
                if (!(disk->driverType = strdup("qcow2"))) {
                    virReportOOMError();
                    goto cleanup;
                }
10650 10651
            } else if (STRNEQ(disk->driverType, "qcow2") &&
                       STRNEQ(disk->driverType, "qed")) {
10652 10653 10654 10655
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("external snapshot format for disk %s "
                                 "is unsupported: %s"),
                               disk->name, disk->driverType);
10656 10657 10658 10659 10660 10661 10662 10663 10664
                goto cleanup;
            }
            if (stat(disk->file, &st) < 0) {
                if (errno != ENOENT) {
                    virReportSystemError(errno,
                                         _("unable to stat for disk %s: %s"),
                                         disk->name, disk->file);
                    goto cleanup;
                }
10665
            } else if (!(S_ISBLK(st.st_mode) || !st.st_size || allow_reuse)) {
10666 10667 10668 10669
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("external snapshot file for disk %s already "
                                 "exists and is not a block device: %s"),
                               disk->name, disk->file);
10670 10671 10672
                goto cleanup;
            }
            found = true;
10673
            external++;
10674 10675
            break;

E
Eric Blake 已提交
10676
        case VIR_DOMAIN_SNAPSHOT_LOCATION_NONE:
10677 10678
            break;

E
Eric Blake 已提交
10679
        case VIR_DOMAIN_SNAPSHOT_LOCATION_DEFAULT:
10680
        default:
10681 10682
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("unexpected code path"));
10683 10684 10685 10686 10687
            goto cleanup;
        }
    }

    if (!found) {
10688 10689 10690
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("disk snapshots require at least one disk to be "
                         "selected for snapshot"));
10691 10692
        goto cleanup;
    }
10693 10694
    if (active) {
        if (external == 1 ||
10695
            qemuCapsGet(priv->caps, QEMU_CAPS_TRANSACTION)) {
10696 10697
            *flags |= VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC;
        } else if (atomic && external > 1) {
10698 10699 10700
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("atomic live snapshot of multiple disks "
                             "is unsupported"));
10701 10702 10703
            goto cleanup;
        }
    }
10704 10705 10706 10707 10708 10709 10710 10711 10712

    ret = 0;

cleanup:
    return ret;
}

/* The domain is expected to hold monitor lock.  */
static int
10713 10714
qemuDomainSnapshotCreateSingleDiskActive(struct qemud_driver *driver,
                                         virDomainObjPtr vm,
10715
                                         virCgroupPtr cgroup,
10716
                                         virDomainSnapshotDiskDefPtr snap,
10717
                                         virDomainDiskDefPtr disk,
10718
                                         virDomainDiskDefPtr persistDisk,
10719 10720
                                         virJSONValuePtr actions,
                                         bool reuse)
10721 10722 10723 10724 10725
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *device = NULL;
    char *source = NULL;
    char *driverType = NULL;
10726 10727
    char *persistSource = NULL;
    char *persistDriverType = NULL;
10728
    int ret = -1;
10729 10730 10731 10732
    int fd = -1;
    char *origsrc = NULL;
    char *origdriver = NULL;
    bool need_unlink = false;
10733

E
Eric Blake 已提交
10734
    if (snap->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
10735 10736
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected code path"));
10737 10738 10739 10740 10741
        return -1;
    }

    if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0 ||
        !(source = strdup(snap->file)) ||
10742 10743
        (STRNEQ_NULLABLE(disk->driverType, snap->driverType) &&
         !(driverType = strdup(snap->driverType))) ||
10744 10745
        (persistDisk &&
         (!(persistSource = strdup(source)) ||
10746 10747
          (STRNEQ_NULLABLE(persistDisk->driverType, snap->driverType) &&
           !(persistDriverType = strdup(snap->driverType)))))) {
10748 10749 10750 10751
        virReportOOMError();
        goto cleanup;
    }

10752 10753
    /* create the stub file and set selinux labels; manipulate disk in
     * place, in a way that can be reverted on failure. */
10754 10755 10756 10757 10758 10759 10760
    if (!reuse) {
        fd = qemuOpenFile(driver, source, O_WRONLY | O_TRUNC | O_CREAT,
                          &need_unlink, NULL);
        if (fd < 0)
            goto cleanup;
        VIR_FORCE_CLOSE(fd);
    }
10761 10762 10763 10764

    origsrc = disk->src;
    disk->src = source;
    origdriver = disk->driverType;
10765
    disk->driverType = (char *) "raw"; /* Don't want to probe backing files */
10766 10767 10768

    if (virDomainLockDiskAttach(driver->lockManager, vm, disk) < 0)
        goto cleanup;
10769 10770 10771 10772 10773
    if (cgroup && qemuSetupDiskCgroup(driver, vm, cgroup, disk) < 0) {
        if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
            VIR_WARN("Unable to release lock on %s", source);
        goto cleanup;
    }
10774
    if (virSecurityManagerSetImageLabel(driver->securityManager, vm->def,
10775
                                        disk) < 0) {
10776 10777
        if (cgroup && qemuTeardownDiskCgroup(driver, vm, cgroup, disk) < 0)
            VIR_WARN("Failed to teardown cgroup for disk path %s", source);
10778 10779 10780 10781 10782 10783 10784 10785 10786 10787 10788
        if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
            VIR_WARN("Unable to release lock on %s", source);
        goto cleanup;
    }

    disk->src = origsrc;
    origsrc = NULL;
    disk->driverType = origdriver;
    origdriver = NULL;

    /* create the actual snapshot */
10789
    ret = qemuMonitorDiskSnapshot(priv->mon, actions, device, source,
10790
                                  snap->driverType, reuse);
10791 10792 10793 10794 10795
    virDomainAuditDisk(vm, disk->src, source, "snapshot", ret >= 0);
    if (ret < 0)
        goto cleanup;

    /* Update vm in place to match changes.  */
10796
    need_unlink = false;
10797 10798 10799 10800 10801 10802 10803 10804
    VIR_FREE(disk->src);
    disk->src = source;
    source = NULL;
    if (driverType) {
        VIR_FREE(disk->driverType);
        disk->driverType = driverType;
        driverType = NULL;
    }
10805 10806 10807 10808 10809 10810 10811 10812 10813 10814
    if (persistDisk) {
        VIR_FREE(persistDisk->src);
        persistDisk->src = persistSource;
        persistSource = NULL;
        if (persistDriverType) {
            VIR_FREE(persistDisk->driverType);
            persistDisk->driverType = persistDriverType;
            persistDriverType = NULL;
        }
    }
10815 10816

cleanup:
10817 10818 10819 10820 10821 10822
    if (origsrc) {
        disk->src = origsrc;
        disk->driverType = origdriver;
    }
    if (need_unlink && unlink(source))
        VIR_WARN("unable to unlink just-created %s", source);
10823 10824 10825
    VIR_FREE(device);
    VIR_FREE(source);
    VIR_FREE(driverType);
10826 10827
    VIR_FREE(persistSource);
    VIR_FREE(persistDriverType);
10828 10829 10830
    return ret;
}

10831 10832 10833 10834 10835 10836
/* The domain is expected to hold monitor lock.  This is the
 * counterpart to qemuDomainSnapshotCreateSingleDiskActive, called
 * only on a failed transaction. */
static void
qemuDomainSnapshotUndoSingleDiskActive(struct qemud_driver *driver,
                                       virDomainObjPtr vm,
10837
                                       virCgroupPtr cgroup,
10838 10839 10840 10841 10842 10843 10844 10845 10846 10847 10848 10849 10850 10851 10852 10853 10854 10855 10856 10857 10858 10859 10860 10861
                                       virDomainDiskDefPtr origdisk,
                                       virDomainDiskDefPtr disk,
                                       virDomainDiskDefPtr persistDisk,
                                       bool need_unlink)
{
    char *source = NULL;
    char *driverType = NULL;
    char *persistSource = NULL;
    char *persistDriverType = NULL;
    struct stat st;

    if (!(source = strdup(origdisk->src)) ||
        (origdisk->driverType &&
         !(driverType = strdup(origdisk->driverType))) ||
        (persistDisk &&
         (!(persistSource = strdup(source)) ||
          (driverType && !(persistDriverType = strdup(driverType)))))) {
        virReportOOMError();
        goto cleanup;
    }

    if (virSecurityManagerRestoreImageLabel(driver->securityManager,
                                            vm->def, disk) < 0)
        VIR_WARN("Unable to restore security label on %s", disk->src);
10862 10863
    if (cgroup && qemuTeardownDiskCgroup(driver, vm, cgroup, disk) < 0)
        VIR_WARN("Failed to teardown cgroup for disk path %s", disk->src);
10864 10865 10866
    if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
        VIR_WARN("Unable to release lock on %s", disk->src);
    if (need_unlink && stat(disk->src, &st) == 0 &&
10867
        S_ISREG(st.st_mode) && unlink(disk->src) < 0)
10868 10869 10870 10871 10872 10873 10874 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 10885 10886 10887 10888 10889 10890 10891 10892 10893 10894 10895 10896
        VIR_WARN("Unable to remove just-created %s", disk->src);

    /* Update vm in place to match changes.  */
    VIR_FREE(disk->src);
    disk->src = source;
    source = NULL;
    VIR_FREE(disk->driverType);
    if (driverType) {
        disk->driverType = driverType;
        driverType = NULL;
    }
    if (persistDisk) {
        VIR_FREE(persistDisk->src);
        persistDisk->src = persistSource;
        persistSource = NULL;
        VIR_FREE(persistDisk->driverType);
        if (persistDriverType) {
            persistDisk->driverType = persistDriverType;
            persistDriverType = NULL;
        }
    }

cleanup:
    VIR_FREE(source);
    VIR_FREE(driverType);
    VIR_FREE(persistSource);
    VIR_FREE(persistDriverType);
}

10897 10898 10899 10900 10901 10902 10903 10904 10905
/* The domain is expected to be locked and active. */
static int
qemuDomainSnapshotCreateDiskActive(virConnectPtr conn,
                                   struct qemud_driver *driver,
                                   virDomainObjPtr *vmptr,
                                   virDomainSnapshotObjPtr snap,
                                   unsigned int flags)
{
    virDomainObjPtr vm = *vmptr;
10906 10907
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virJSONValuePtr actions = NULL;
10908 10909 10910
    bool resume = false;
    int ret = -1;
    int i;
10911
    bool persist = false;
E
Eric Blake 已提交
10912
    int thaw = 0; /* 1 if freeze succeeded, -1 if freeze failed */
10913
    bool atomic = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC) != 0;
10914
    bool reuse = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
10915
    virCgroupPtr cgroup = NULL;
10916 10917 10918 10919

    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
        return -1;

10920
    if (!virDomainObjIsActive(vm)) {
10921 10922
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10923 10924 10925
        goto endjob;
    }

10926 10927
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0)) {
10928 10929 10930
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to find cgroup for %s"),
                       vm->def->name);
10931 10932 10933 10934
        goto endjob;
    }
    /* 'cgroup' is still NULL if cgroups are disabled.  */

E
Eric Blake 已提交
10935 10936 10937 10938 10939 10940
    /* If quiesce was requested, then issue a freeze command, and a
     * counterpart thaw command, no matter what.  The command will
     * fail if the guest is paused or the guest agent is not
     * running.  */
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) {
        if (qemuDomainSnapshotFSFreeze(driver, vm) < 0) {
10941
            /* helper reported the error */
E
Eric Blake 已提交
10942
            thaw = -1;
10943
            goto endjob;
E
Eric Blake 已提交
10944 10945
        } else {
            thaw = 1;
10946
        }
E
Eric Blake 已提交
10947
    }
10948

10949 10950 10951 10952 10953 10954 10955 10956
    /* For multiple disks, libvirt must pause externally to get all
     * snapshots to be at the same point in time, unless qemu supports
     * transactions.  For a single disk, snapshot is atomic without
     * requiring a pause.  Thanks to qemuDomainSnapshotDiskPrepare, if
     * we got to this point, the atomic flag now says whether we need
     * to pause, and a capability bit says whether to use transaction.
     */
    if (!atomic && virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
10957 10958 10959 10960 10961 10962
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_NONE) < 0)
            goto cleanup;

        resume = true;
        if (!virDomainObjIsActive(vm)) {
10963 10964
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
10965 10966 10967
            goto cleanup;
        }
    }
10968
    if (qemuCapsGet(priv->caps, QEMU_CAPS_TRANSACTION)) {
10969 10970 10971 10972 10973 10974
        actions = virJSONValueNewArray();
        if (!actions) {
            virReportOOMError();
            goto cleanup;
        }
    }
10975 10976

    /* No way to roll back if first disk succeeds but later disks
10977 10978
     * fail, unless we have transaction support.
     * Based on earlier qemuDomainSnapshotDiskPrepare, all
10979 10980 10981 10982
     * disks in this list are now either SNAPSHOT_NO, or
     * SNAPSHOT_EXTERNAL with a valid file name and qcow2 format.  */
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    for (i = 0; i < snap->def->ndisks; i++) {
10983 10984
        virDomainDiskDefPtr persistDisk = NULL;

E
Eric Blake 已提交
10985
        if (snap->def->disks[i].snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
10986
            continue;
10987 10988 10989 10990 10991 10992 10993 10994 10995
        if (vm->newDef) {
            int indx = virDomainDiskIndexByName(vm->newDef,
                                                vm->def->disks[i]->dst,
                                                false);
            if (indx >= 0) {
                persistDisk = vm->newDef->disks[indx];
                persist = true;
            }
        }
10996

10997
        ret = qemuDomainSnapshotCreateSingleDiskActive(driver, vm, cgroup,
10998
                                                       &snap->def->disks[i],
10999
                                                       vm->def->disks[i],
11000 11001
                                                       persistDisk, actions,
                                                       reuse);
11002 11003 11004
        if (ret < 0)
            break;
    }
11005 11006 11007
    if (actions) {
        if (ret == 0)
            ret = qemuMonitorTransaction(priv->mon, actions);
E
Eric Blake 已提交
11008
        virJSONValueFree(actions);
11009 11010 11011 11012 11013 11014
        if (ret < 0) {
            /* Transaction failed; undo the changes to vm.  */
            bool need_unlink = !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT);
            while (--i >= 0) {
                virDomainDiskDefPtr persistDisk = NULL;

E
Eric Blake 已提交
11015 11016
                if (snap->def->disks[i].snapshot ==
                    VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
11017 11018 11019 11020 11021 11022 11023 11024 11025
                    continue;
                if (vm->newDef) {
                    int indx = virDomainDiskIndexByName(vm->newDef,
                                                        vm->def->disks[i]->dst,
                                                        false);
                    if (indx >= 0)
                        persistDisk = vm->newDef->disks[indx];
                }

11026
                qemuDomainSnapshotUndoSingleDiskActive(driver, vm, cgroup,
11027 11028 11029 11030 11031 11032 11033
                                                       snap->def->dom->disks[i],
                                                       vm->def->disks[i],
                                                       persistDisk,
                                                       need_unlink);
            }
        }
    }
11034 11035 11036 11037 11038 11039 11040 11041 11042
    qemuDomainObjExitMonitorWithDriver(driver, vm);
    if (ret < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
        virDomainEventPtr event;

        event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
11043
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
11044 11045 11046 11047 11048
        virDomainAuditStop(vm, "from-snapshot");
        /* We already filtered the _HALT flag for persistent domains
         * only, so this end job never drops the last reference.  */
        ignore_value(qemuDomainObjEndJob(driver, vm));
        resume = false;
E
Eric Blake 已提交
11049
        thaw = 0;
11050 11051 11052 11053 11054 11055
        vm = NULL;
        if (event)
            qemuDomainEventQueue(driver, event);
    }

cleanup:
11056 11057 11058 11059 11060
    if (resume && virDomainObjIsActive(vm)) {
        if (qemuProcessStartCPUs(driver, vm, conn,
                                 VIR_DOMAIN_RUNNING_UNPAUSED,
                                 QEMU_ASYNC_JOB_NONE) < 0 &&
            virGetLastError() == NULL) {
11061 11062
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("resuming after snapshot failed"));
11063 11064
            goto endjob;
        }
11065 11066
    }

11067
    if (vm && (ret == 0 ||
11068
               !qemuCapsGet(priv->caps, QEMU_CAPS_TRANSACTION))) {
11069 11070 11071
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0 ||
            (persist &&
             virDomainSaveConfig(driver->configDir, vm->newDef) < 0))
11072
            ret = -1;
11073 11074 11075
    }

endjob:
11076 11077
    if (cgroup)
        virCgroupFree(&cgroup);
E
Eric Blake 已提交
11078 11079 11080 11081 11082 11083
    if (vm && thaw != 0 &&
        qemuDomainSnapshotFSThaw(driver, vm, thaw > 0) < 0) {
        /* helper reported the error, if it was needed */
        if (thaw > 0)
            ret = -1;
    }
11084
    if (vm && (qemuDomainObjEndJob(driver, vm) == 0)) {
11085 11086 11087 11088
        /* Only possible if a transient vm quit while our locks were down,
         * in which case we don't want to save snapshot metadata.  */
        *vmptr = NULL;
        ret = -1;
11089 11090 11091 11092 11093
    }

    return ret;
}

11094 11095 11096 11097
static virDomainSnapshotPtr
qemuDomainSnapshotCreateXML(virDomainPtr domain,
                            const char *xmlDesc,
                            unsigned int flags)
C
Chris Lalancette 已提交
11098 11099 11100
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
11101
    char *xml = NULL;
C
Chris Lalancette 已提交
11102 11103 11104
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
11105
    virDomainSnapshotDefPtr def = NULL;
11106 11107
    bool update_current = true;
    unsigned int parse_flags = 0;
11108
    virDomainSnapshotObjPtr other = NULL;
C
Chris Lalancette 已提交
11109

11110 11111
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
11112
                  VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
11113
                  VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
11114
                  VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
11115
                  VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT |
11116 11117
                  VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC, NULL);
11118 11119 11120

    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) &&
        !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)) {
11121 11122
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("quiesce requires disk-only"));
11123 11124
        return NULL;
    }
11125 11126 11127 11128 11129 11130 11131

    if (((flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) &&
         !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) ||
        (flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA))
        update_current = false;
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)
        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE;
11132 11133
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)
        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
11134

C
Chris Lalancette 已提交
11135 11136 11137 11138
    qemuDriverLock(driver);
    virUUIDFormat(domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
11139 11140
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
C
Chris Lalancette 已提交
11141 11142 11143
        goto cleanup;
    }

11144
    if (qemuProcessAutoDestroyActive(driver, vm)) {
11145 11146
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is marked for auto destroy"));
11147 11148
        goto cleanup;
    }
11149
    if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
11150 11151
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot halt after transient domain snapshot"));
11152 11153
        goto cleanup;
    }
11154

11155 11156 11157
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, driver->caps,
                                                QEMU_EXPECTED_VIRT_TYPES,
                                                parse_flags)))
C
Chris Lalancette 已提交
11158 11159
        goto cleanup;

11160 11161 11162 11163
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
        /* Prevent circular chains */
        if (def->parent) {
            if (STREQ(def->name, def->parent)) {
11164 11165 11166
                virReportError(VIR_ERR_INVALID_ARG,
                               _("cannot set snapshot %s as its own parent"),
                               def->name);
11167 11168
                goto cleanup;
            }
11169
            other = virDomainSnapshotFindByName(vm->snapshots, def->parent);
11170
            if (!other) {
11171 11172 11173
                virReportError(VIR_ERR_INVALID_ARG,
                               _("parent %s for snapshot %s not found"),
                               def->parent, def->name);
11174 11175 11176 11177
                goto cleanup;
            }
            while (other->def->parent) {
                if (STREQ(other->def->parent, def->name)) {
11178 11179 11180
                    virReportError(VIR_ERR_INVALID_ARG,
                                   _("parent %s would create cycle to %s"),
                                   other->def->name, def->name);
11181 11182
                    goto cleanup;
                }
11183
                other = virDomainSnapshotFindByName(vm->snapshots,
11184 11185 11186 11187 11188 11189 11190 11191 11192 11193
                                                    other->def->parent);
                if (!other) {
                    VIR_WARN("snapshots are inconsistent for %s",
                             vm->def->name);
                    break;
                }
            }
        }

        /* Check that any replacement is compatible */
11194 11195
        if (def->dom &&
            memcmp(def->dom->uuid, domain->uuid, VIR_UUID_BUFLEN)) {
11196 11197 11198
            virReportError(VIR_ERR_INVALID_ARG,
                           _("definition for snapshot %s must use uuid %s"),
                           def->name, uuidstr);
11199 11200
            goto cleanup;
        }
11201
        other = virDomainSnapshotFindByName(vm->snapshots, def->name);
11202 11203 11204 11205 11206
        if (other) {
            if ((other->def->state == VIR_DOMAIN_RUNNING ||
                 other->def->state == VIR_DOMAIN_PAUSED) !=
                (def->state == VIR_DOMAIN_RUNNING ||
                 def->state == VIR_DOMAIN_PAUSED)) {
11207 11208 11209 11210
                virReportError(VIR_ERR_INVALID_ARG,
                               _("cannot change between online and offline "
                                 "snapshot state in snapshot %s"),
                               def->name);
11211 11212
                goto cleanup;
            }
11213 11214
            if ((other->def->state == VIR_DOMAIN_DISK_SNAPSHOT) !=
                (def->state == VIR_DOMAIN_DISK_SNAPSHOT)) {
11215 11216 11217 11218
                virReportError(VIR_ERR_INVALID_ARG,
                               _("cannot change between disk snapshot and "
                                 "system checkpoint in snapshot %s"),
                               def->name);
11219 11220
                goto cleanup;
            }
11221 11222 11223 11224 11225 11226 11227 11228 11229 11230 11231
            if (other->def->dom) {
                if (def->dom) {
                    if (!virDomainDefCheckABIStability(other->def->dom,
                                                       def->dom))
                        goto cleanup;
                } else {
                    /* Transfer the domain def */
                    def->dom = other->def->dom;
                    other->def->dom = NULL;
                }
            }
11232 11233 11234 11235
            if (other == vm->current_snapshot) {
                update_current = true;
                vm->current_snapshot = NULL;
            }
11236 11237
            /* Drop and rebuild the parent relationship, but keep all
             * child relations by reusing snap.  */
11238
            virDomainSnapshotDropParent(other);
11239 11240 11241
            virDomainSnapshotDefFree(other->def);
            other->def = NULL;
            snap = other;
11242
        }
11243 11244
        if (def->state == VIR_DOMAIN_DISK_SNAPSHOT && def->dom) {
            if (virDomainSnapshotAlignDisks(def,
E
Eric Blake 已提交
11245
                                            VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL,
11246 11247 11248
                                            false) < 0)
                goto cleanup;
        }
11249 11250 11251
    } else {
        /* Easiest way to clone inactive portion of vm->def is via
         * conversion in and back out of xml.  */
11252
        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, false)) ||
11253 11254 11255 11256 11257
            !(def->dom = virDomainDefParseString(driver->caps, xml,
                                                 QEMU_EXPECTED_VIRT_TYPES,
                                                 VIR_DOMAIN_XML_INACTIVE)))
            goto cleanup;

11258
        if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
11259
            if (!virDomainObjIsActive(vm)) {
11260 11261 11262
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("disk snapshots of inactive domains not "
                                 "implemented yet"));
11263 11264
                goto cleanup;
            }
11265
            if (virDomainSnapshotAlignDisks(def,
E
Eric Blake 已提交
11266
                                            VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL,
11267 11268
                                            false) < 0)
                goto cleanup;
11269
            if (qemuDomainSnapshotDiskPrepare(vm, def, &flags) < 0)
11270 11271 11272 11273 11274 11275 11276 11277 11278 11279 11280 11281 11282 11283 11284 11285
                goto cleanup;
            def->state = VIR_DOMAIN_DISK_SNAPSHOT;
        } else {
            /* In a perfect world, we would allow qemu to tell us this.
             * The problem is that qemu only does this check
             * device-by-device; so if you had a domain that booted from a
             * large qcow2 device, but had a secondary raw device
             * attached, you wouldn't find out that you can't snapshot
             * your guest until *after* it had spent the time to snapshot
             * the boot device.  This is probably a bug in qemu, but we'll
             * work around it here for now.
             */
            if (!qemuDomainSnapshotIsAllowed(vm))
                goto cleanup;
            def->state = virDomainObjGetState(vm, NULL);
        }
11286 11287
    }

11288 11289
    if (snap)
        snap->def = def;
11290
    else if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
C
Chris Lalancette 已提交
11291
        goto cleanup;
11292
    def = NULL;
C
Chris Lalancette 已提交
11293

11294 11295
    if (update_current)
        snap->def->current = true;
11296
    if (vm->current_snapshot) {
11297 11298 11299 11300 11301 11302
        if (!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)) {
            snap->def->parent = strdup(vm->current_snapshot->def->name);
            if (snap->def->parent == NULL) {
                virReportOOMError();
                goto cleanup;
            }
11303
        }
11304
        if (update_current) {
11305 11306 11307 11308 11309 11310
            vm->current_snapshot->def->current = false;
            if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
                                                driver->snapshotDir) < 0)
                goto cleanup;
            vm->current_snapshot = NULL;
        }
11311
    }
11312

C
Chris Lalancette 已提交
11313
    /* actually do the snapshot */
11314 11315
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
        /* XXX Should we validate that the redefined snapshot even
11316 11317
         * makes sense, such as checking that qemu-img recognizes the
         * snapshot name in at least one of the domain's disks?  */
11318 11319 11320 11321
    } else if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
        if (qemuDomainSnapshotCreateDiskActive(domain->conn, driver,
                                               &vm, snap, flags) < 0)
            goto cleanup;
11322
    } else if (!virDomainObjIsActive(vm)) {
E
Eric Blake 已提交
11323
        if (qemuDomainSnapshotCreateInactive(driver, vm, snap) < 0)
C
Chris Lalancette 已提交
11324
            goto cleanup;
E
Eric Blake 已提交
11325
    } else {
11326
        if (qemuDomainSnapshotCreateActive(domain->conn, driver,
11327
                                           &vm, snap, flags) < 0)
11328
            goto cleanup;
C
Chris Lalancette 已提交
11329 11330
    }

11331
    /* If we fail after this point, there's not a whole lot we can
C
Chris Lalancette 已提交
11332 11333 11334 11335 11336 11337
     * do; we've successfully taken the snapshot, and we are now running
     * on it, so we have to go forward the best we can
     */
    snapshot = virGetDomainSnapshot(domain, snap->def->name);

cleanup:
11338
    if (vm) {
11339
        if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
11340
            if (qemuDomainSnapshotWriteMetadata(vm, snap,
11341
                                                driver->snapshotDir) < 0) {
11342 11343
                VIR_WARN("unable to save metadata for snapshot %s",
                         snap->def->name);
11344 11345 11346
            } else {
                if (update_current)
                    vm->current_snapshot = snap;
11347
                other = virDomainSnapshotFindByName(vm->snapshots,
11348 11349 11350 11351 11352
                                                    snap->def->parent);
                snap->parent = other;
                other->nchildren++;
                snap->sibling = other->first_child;
                other->first_child = snap;
11353
            }
11354
        } else if (snap) {
11355
            virDomainSnapshotObjListRemove(vm->snapshots, snap);
11356
        }
C
Chris Lalancette 已提交
11357
        virDomainObjUnlock(vm);
11358 11359
    }
    virDomainSnapshotDefFree(def);
11360
    VIR_FREE(xml);
C
Chris Lalancette 已提交
11361 11362 11363 11364 11365 11366
    qemuDriverUnlock(driver);
    return snapshot;
}

static int qemuDomainSnapshotListNames(virDomainPtr domain, char **names,
                                       int nameslen,
11367
                                       unsigned int flags)
C
Chris Lalancette 已提交
11368 11369 11370 11371
{
    virDomainObjPtr vm = NULL;
    int n = -1;

11372
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
11373
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11374

11375
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11376 11377
        goto cleanup;

11378
    n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen,
11379
                                         flags);
C
Chris Lalancette 已提交
11380 11381 11382 11383 11384 11385 11386 11387

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return n;
}

static int qemuDomainSnapshotNum(virDomainPtr domain,
11388
                                 unsigned int flags)
C
Chris Lalancette 已提交
11389 11390 11391 11392
{
    virDomainObjPtr vm = NULL;
    int n = -1;

11393
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
11394
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11395

11396
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11397 11398
        goto cleanup;

11399
    n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags);
C
Chris Lalancette 已提交
11400 11401 11402 11403 11404 11405 11406

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return n;
}

11407 11408 11409 11410 11411 11412 11413 11414 11415 11416
static int
qemuDomainListAllSnapshots(virDomainPtr domain, virDomainSnapshotPtr **snaps,
                           unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int n = -1;

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);

11417
    if (!(vm = qemuDomObjFromDomain(domain)))
11418 11419
        goto cleanup;

11420
    n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags);
11421 11422 11423 11424 11425 11426 11427

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return n;
}

11428 11429 11430 11431 11432 11433 11434 11435 11436 11437 11438
static int
qemuDomainSnapshotListChildrenNames(virDomainSnapshotPtr snapshot,
                                    char **names,
                                    int nameslen,
                                    unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    int n = -1;

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
11439
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11440

11441
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11442 11443
        goto cleanup;

11444
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11445 11446
        goto cleanup;

11447
    n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen,
11448
                                         flags);
11449 11450 11451 11452 11453 11454 11455 11456 11457 11458 11459 11460 11461 11462 11463 11464

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return n;
}

static int
qemuDomainSnapshotNumChildren(virDomainSnapshotPtr snapshot,
                              unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    int n = -1;

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
11465
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11466

11467
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11468 11469
        goto cleanup;

11470
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11471 11472
        goto cleanup;

11473
    n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags);
11474 11475 11476 11477 11478 11479 11480

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return n;
}

11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491 11492
static int
qemuDomainSnapshotListAllChildren(virDomainSnapshotPtr snapshot,
                                  virDomainSnapshotPtr **snaps,
                                  unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    int n = -1;

    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_DESCENDANTS |
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);

11493
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11494 11495
        goto cleanup;

11496
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11497 11498
        goto cleanup;

11499
    n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps,
11500 11501 11502 11503 11504 11505 11506 11507
                               flags);

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return n;
}

C
Chris Lalancette 已提交
11508 11509
static virDomainSnapshotPtr qemuDomainSnapshotLookupByName(virDomainPtr domain,
                                                           const char *name,
11510
                                                           unsigned int flags)
C
Chris Lalancette 已提交
11511 11512 11513 11514 11515
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

11516 11517
    virCheckFlags(0, NULL);

11518
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11519 11520
        goto cleanup;

11521
    if (!(snap = qemuSnapObjFromName(vm, name)))
C
Chris Lalancette 已提交
11522 11523 11524 11525 11526 11527 11528 11529 11530 11531 11532
        goto cleanup;

    snapshot = virGetDomainSnapshot(domain, snap->def->name);

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return snapshot;
}

static int qemuDomainHasCurrentSnapshot(virDomainPtr domain,
11533
                                        unsigned int flags)
C
Chris Lalancette 已提交
11534 11535 11536 11537
{
    virDomainObjPtr vm;
    int ret = -1;

11538 11539
    virCheckFlags(0, -1);

11540
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11541 11542 11543 11544 11545 11546 11547 11548 11549 11550
        goto cleanup;

    ret = (vm->current_snapshot != NULL);

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

11551 11552 11553 11554 11555 11556 11557 11558 11559 11560
static virDomainSnapshotPtr
qemuDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr parent = NULL;

    virCheckFlags(0, NULL);

11561
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11562 11563
        goto cleanup;

11564
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11565 11566 11567
        goto cleanup;

    if (!snap->def->parent) {
11568 11569 11570
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snap->def->name);
11571 11572 11573 11574 11575 11576 11577 11578 11579 11580 11581
        goto cleanup;
    }

    parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return parent;
}

C
Chris Lalancette 已提交
11582
static virDomainSnapshotPtr qemuDomainSnapshotCurrent(virDomainPtr domain,
11583
                                                      unsigned int flags)
C
Chris Lalancette 已提交
11584 11585 11586 11587
{
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

11588 11589
    virCheckFlags(0, NULL);

11590
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11591 11592 11593
        goto cleanup;

    if (!vm->current_snapshot) {
11594 11595
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
                       _("the domain does not have a current snapshot"));
C
Chris Lalancette 已提交
11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606
        goto cleanup;
    }

    snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return snapshot;
}

11607 11608
static char *qemuDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                                          unsigned int flags)
C
Chris Lalancette 已提交
11609 11610 11611 11612 11613 11614
{
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

11615
    virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
11616

11617
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
C
Chris Lalancette 已提交
11618 11619
        goto cleanup;

11620
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
11621
        goto cleanup;
11622 11623

    virUUIDFormat(snapshot->domain->uuid, uuidstr);
C
Chris Lalancette 已提交
11624

11625
    xml = virDomainSnapshotDefFormat(uuidstr, snap->def, flags, 0);
C
Chris Lalancette 已提交
11626 11627 11628 11629 11630 11631 11632

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return xml;
}

11633 11634 11635 11636 11637 11638 11639 11640 11641 11642
static int
qemuDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

11643
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11644 11645
        goto cleanup;

11646
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11647 11648 11649 11650 11651 11652 11653 11654 11655 11656 11657 11658 11659 11660 11661 11662 11663 11664 11665 11666 11667 11668
        goto cleanup;

    ret = (vm->current_snapshot &&
           STREQ(snapshot->name, vm->current_snapshot->def->name));

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


static int
qemuDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
                              unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

11669
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11670 11671
        goto cleanup;

11672
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11673 11674 11675 11676 11677 11678 11679 11680 11681 11682 11683 11684 11685
        goto cleanup;

    /* XXX Someday, we should recognize internal snapshots in qcow2
     * images that are not tied to a libvirt snapshot; if we ever do
     * that, then we would have a reason to return 0 here.  */
    ret = 1;

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

11686 11687
/* The domain is expected to be locked and inactive. */
static int
E
Eric Blake 已提交
11688 11689
qemuDomainSnapshotRevertInactive(struct qemud_driver *driver,
                                 virDomainObjPtr vm,
11690 11691 11692
                                 virDomainSnapshotObjPtr snap)
{
    /* Try all disks, but report failure if we skipped any.  */
E
Eric Blake 已提交
11693
    int ret = qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-a", true);
11694 11695 11696
    return ret > 0 ? -1 : ret;
}

C
Chris Lalancette 已提交
11697
static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
11698
                                      unsigned int flags)
C
Chris Lalancette 已提交
11699 11700 11701 11702 11703 11704 11705
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virDomainEventPtr event = NULL;
11706
    virDomainEventPtr event2 = NULL;
11707
    int detail;
C
Chris Lalancette 已提交
11708 11709
    qemuDomainObjPrivatePtr priv;
    int rc;
11710
    virDomainDefPtr config = NULL;
C
Chris Lalancette 已提交
11711

11712
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
11713 11714
                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
                  VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
11715

11716 11717 11718 11719 11720 11721 11722 11723 11724 11725
    /* We have the following transitions, which create the following events:
     * 1. inactive -> inactive: none
     * 2. inactive -> running:  EVENT_STARTED
     * 3. inactive -> paused:   EVENT_STARTED, EVENT_PAUSED
     * 4. running  -> inactive: EVENT_STOPPED
     * 5. running  -> running:  none
     * 6. running  -> paused:   EVENT_PAUSED
     * 7. paused   -> inactive: EVENT_STOPPED
     * 8. paused   -> running:  EVENT_RESUMED
     * 9. paused   -> paused:   none
11726 11727
     * Also, several transitions occur even if we fail partway through,
     * and use of FORCE can cause multiple transitions.
11728 11729
     */

C
Chris Lalancette 已提交
11730 11731 11732 11733
    qemuDriverLock(driver);
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, snapshot->domain->uuid);
    if (!vm) {
11734 11735
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
C
Chris Lalancette 已提交
11736 11737 11738
        goto cleanup;
    }

11739
    snap = virDomainSnapshotFindByName(vm->snapshots, snapshot->name);
C
Chris Lalancette 已提交
11740
    if (!snap) {
11741 11742 11743
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("no domain snapshot with matching name '%s'"),
                       snapshot->name);
C
Chris Lalancette 已提交
11744 11745 11746
        goto cleanup;
    }

11747 11748 11749 11750 11751
    if (!vm->persistent &&
        snap->def->state != VIR_DOMAIN_RUNNING &&
        snap->def->state != VIR_DOMAIN_PAUSED &&
        (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) == 0) {
11752 11753 11754
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("transient domain needs to request run or pause "
                         "to revert to inactive snapshot"));
11755 11756
        goto cleanup;
    }
11757
    if (snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT) {
11758 11759 11760
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("revert to external disk snapshot not supported "
                         "yet"));
11761 11762
        goto cleanup;
    }
11763 11764
    if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
        if (!snap->def->dom) {
11765 11766 11767
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
                           _("snapshot '%s' lacks domain '%s' rollback info"),
                           snap->def->name, vm->def->name);
11768 11769 11770 11771 11772 11773 11774
            goto cleanup;
        }
        if (virDomainObjIsActive(vm) &&
            !(snap->def->state == VIR_DOMAIN_RUNNING
              || snap->def->state == VIR_DOMAIN_PAUSED) &&
            (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
                      VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
11775 11776
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                           _("must respawn qemu to start inactive snapshot"));
11777 11778 11779 11780
            goto cleanup;
        }
    }

11781

11782 11783 11784 11785 11786 11787 11788 11789 11790 11791
    if (vm->current_snapshot) {
        vm->current_snapshot->def->current = false;
        if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
                                            driver->snapshotDir) < 0)
            goto cleanup;
        vm->current_snapshot = NULL;
        /* XXX Should we restore vm->current_snapshot after this point
         * in the failure cases where we know there was no change?  */
    }

11792 11793 11794 11795 11796
    /* Prepare to copy the snapshot inactive xml as the config of this
     * domain.  Easiest way is by a round trip through xml.
     *
     * XXX Should domain snapshots track live xml rather
     * than inactive xml?  */
11797
    snap->def->current = true;
11798 11799
    if (snap->def->dom) {
        char *xml;
11800 11801 11802
        if (!(xml = qemuDomainDefFormatXML(driver,
                                           snap->def->dom,
                                           VIR_DOMAIN_XML_INACTIVE |
11803 11804
                                           VIR_DOMAIN_XML_SECURE,
                                           false)))
11805 11806 11807 11808 11809 11810 11811 11812
            goto cleanup;
        config = virDomainDefParseString(driver->caps, xml,
                                         QEMU_EXPECTED_VIRT_TYPES,
                                         VIR_DOMAIN_XML_INACTIVE);
        VIR_FREE(xml);
        if (!config)
            goto cleanup;
    }
C
Chris Lalancette 已提交
11813

11814
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
C
Chris Lalancette 已提交
11815 11816 11817 11818
        goto cleanup;

    if (snap->def->state == VIR_DOMAIN_RUNNING
        || snap->def->state == VIR_DOMAIN_PAUSED) {
11819 11820 11821 11822 11823 11824 11825 11826 11827
        /* Transitions 2, 3, 5, 6, 8, 9 */
        bool was_running = false;
        bool was_stopped = false;

        /* When using the loadvm monitor command, qemu does not know
         * whether to pause or run the reverted domain, and just stays
         * in the same state as before the monitor command, whether
         * that is paused or running.  We always pause before loadvm,
         * to have finer control.  */
C
Chris Lalancette 已提交
11828
        if (virDomainObjIsActive(vm)) {
11829
            /* Transitions 5, 6, 8, 9 */
11830 11831
            /* Check for ABI compatibility.  */
            if (config && !virDomainDefCheckABIStability(vm->def, config)) {
11832 11833 11834 11835 11836
                virErrorPtr err = virGetLastError();

                if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
                    /* Re-spawn error using correct category. */
                    if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
11837 11838
                        virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                                       err->str2);
11839 11840 11841
                    goto endjob;
                }
                virResetError(err);
11842 11843
                qemuProcessStop(driver, vm,
                                VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
11844 11845 11846 11847 11848 11849 11850 11851
                virDomainAuditStop(vm, "from-snapshot");
                detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
                event = virDomainEventNewFromObj(vm,
                                                 VIR_DOMAIN_EVENT_STOPPED,
                                                 detail);
                if (event)
                    qemuDomainEventQueue(driver, event);
                goto load;
11852 11853
            }

C
Chris Lalancette 已提交
11854
            priv = vm->privateData;
11855 11856 11857 11858 11859 11860 11861 11862 11863 11864 11865 11866 11867 11868 11869
            if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
                /* Transitions 5, 6 */
                was_running = true;
                if (qemuProcessStopCPUs(driver, vm,
                                        VIR_DOMAIN_PAUSED_FROM_SNAPSHOT,
                                        QEMU_ASYNC_JOB_NONE) < 0)
                    goto endjob;
                /* Create an event now in case the restore fails, so
                 * that user will be alerted that they are now paused.
                 * If restore later succeeds, we might replace this. */
                detail = VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT;
                event = virDomainEventNewFromObj(vm,
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 detail);
                if (!virDomainObjIsActive(vm)) {
11870 11871
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("guest unexpectedly quit"));
11872 11873 11874
                    goto endjob;
                }
            }
11875
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
11876 11877
            rc = qemuMonitorLoadSnapshot(priv->mon, snap->def->name);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
11878 11879 11880
            if (rc < 0) {
                /* XXX resume domain if it was running before the
                 * failed loadvm attempt? */
11881
                goto endjob;
11882
            }
11883 11884
            if (config)
                virDomainObjAssignDef(vm, config, false);
E
Eric Blake 已提交
11885
        } else {
11886
            /* Transitions 2, 3 */
11887
        load:
11888
            was_stopped = true;
11889 11890 11891
            if (config)
                virDomainObjAssignDef(vm, config, false);

11892 11893 11894 11895
            rc = qemuProcessStart(snapshot->domain->conn,
                                  driver, vm, NULL, -1, NULL, snap,
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  VIR_QEMU_PROCESS_START_PAUSED);
11896
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
11897 11898 11899 11900
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
C
Chris Lalancette 已提交
11901
            if (rc < 0)
11902
                goto endjob;
C
Chris Lalancette 已提交
11903 11904
        }

11905
        /* Touch up domain state.  */
11906 11907 11908
        if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
            (snap->def->state == VIR_DOMAIN_PAUSED ||
             (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
11909 11910 11911 11912 11913 11914 11915 11916 11917 11918 11919 11920 11921
            /* Transitions 3, 6, 9 */
            virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
                                 VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
            if (was_stopped) {
                /* Transition 3, use event as-is and add event2 */
                detail = VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT;
                event2 = virDomainEventNewFromObj(vm,
                                                  VIR_DOMAIN_EVENT_SUSPENDED,
                                                  detail);
            } /* else transition 6 and 9 use event as-is */
        } else {
            /* Transitions 2, 5, 8 */
            if (!virDomainObjIsActive(vm)) {
11922 11923
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("guest unexpectedly quit"));
11924 11925 11926 11927 11928
                goto endjob;
            }
            rc = qemuProcessStartCPUs(driver, vm, snapshot->domain->conn,
                                      VIR_DOMAIN_RUNNING_FROM_SNAPSHOT,
                                      QEMU_ASYNC_JOB_NONE);
H
Hu Tao 已提交
11929
            if (rc < 0)
11930
                goto endjob;
11931 11932 11933 11934 11935 11936 11937 11938 11939 11940 11941 11942 11943 11944 11945
            virDomainEventFree(event);
            event = NULL;
            if (was_stopped) {
                /* Transition 2 */
                detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
                event = virDomainEventNewFromObj(vm,
                                                 VIR_DOMAIN_EVENT_STARTED,
                                                 detail);
            } else if (was_running) {
                /* Transition 8 */
                detail = VIR_DOMAIN_EVENT_RESUMED;
                event = virDomainEventNewFromObj(vm,
                                                 VIR_DOMAIN_EVENT_RESUMED,
                                                 detail);
            }
C
Chris Lalancette 已提交
11946
        }
E
Eric Blake 已提交
11947
    } else {
11948
        /* Transitions 1, 4, 7 */
11949 11950 11951
        /* Newer qemu -loadvm refuses to revert to the state of a snapshot
         * created by qemu-img snapshot -c.  If the domain is running, we
         * must take it offline; then do the revert using qemu-img.
C
Chris Lalancette 已提交
11952 11953 11954
         */

        if (virDomainObjIsActive(vm)) {
11955
            /* Transitions 4, 7 */
11956
            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
11957
            virDomainAuditStop(vm, "from-snapshot");
11958
            detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
C
Chris Lalancette 已提交
11959 11960
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STOPPED,
11961
                                             detail);
11962 11963
        }

E
Eric Blake 已提交
11964
        if (qemuDomainSnapshotRevertInactive(driver, vm, snap) < 0) {
11965
            if (!vm->persistent) {
11966
                if (qemuDomainObjEndJob(driver, vm) > 0)
11967
                    qemuDomainRemoveInactive(driver, vm);
11968
                vm = NULL;
11969
                goto cleanup;
11970
            }
11971
            goto endjob;
C
Chris Lalancette 已提交
11972
        }
11973 11974
        if (config)
            virDomainObjAssignDef(vm, config, false);
11975

11976 11977 11978 11979
        if (flags & (VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
                     VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED)) {
            /* Flush first event, now do transition 2 or 3 */
            bool paused = (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED) != 0;
11980 11981 11982
            unsigned int start_flags = 0;

            start_flags |= paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
11983 11984 11985

            if (event)
                qemuDomainEventQueue(driver, event);
11986 11987 11988 11989
            rc = qemuProcessStart(snapshot->domain->conn,
                                  driver, vm, NULL, -1, NULL, NULL,
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  start_flags);
11990 11991 11992 11993
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
            if (rc < 0) {
                if (!vm->persistent) {
                    if (qemuDomainObjEndJob(driver, vm) > 0)
11994
                        qemuDomainRemoveInactive(driver, vm);
11995 11996 11997 11998 11999 12000 12001 12002 12003 12004 12005 12006 12007 12008 12009 12010
                    vm = NULL;
                    goto cleanup;
                }
                goto endjob;
            }
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
            if (paused) {
                detail = VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT;
                event2 = virDomainEventNewFromObj(vm,
                                                  VIR_DOMAIN_EVENT_SUSPENDED,
                                                  detail);
            }
        }
C
Chris Lalancette 已提交
12011 12012 12013 12014
    }

    ret = 0;

12015
endjob:
12016
    if (vm && qemuDomainObjEndJob(driver, vm) == 0)
C
Chris Lalancette 已提交
12017 12018
        vm = NULL;

12019
cleanup:
12020 12021 12022 12023 12024 12025 12026 12027 12028
    if (vm && ret == 0) {
        if (qemuDomainSnapshotWriteMetadata(vm, snap,
                                            driver->snapshotDir) < 0)
            ret = -1;
        else
            vm->current_snapshot = snap;
    } else if (snap) {
        snap->def->current = false;
    }
12029
    if (event) {
C
Chris Lalancette 已提交
12030
        qemuDomainEventQueue(driver, event);
12031 12032 12033
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
C
Chris Lalancette 已提交
12034 12035 12036 12037 12038 12039 12040
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);

    return ret;
}

12041 12042
struct snap_reparent {
    struct qemud_driver *driver;
12043
    virDomainSnapshotObjPtr parent;
12044 12045
    virDomainObjPtr vm;
    int err;
12046
    virDomainSnapshotObjPtr last;
12047 12048 12049 12050
};

static void
qemuDomainSnapshotReparentChildren(void *payload,
12051
                                   const void *name ATTRIBUTE_UNUSED,
12052 12053 12054 12055 12056 12057 12058 12059 12060
                                   void *data)
{
    virDomainSnapshotObjPtr snap = payload;
    struct snap_reparent *rep = data;

    if (rep->err < 0) {
        return;
    }

12061
    VIR_FREE(snap->def->parent);
12062
    snap->parent = rep->parent;
12063

12064
    if (rep->parent->def) {
12065
        snap->def->parent = strdup(rep->parent->def->name);
12066

12067 12068 12069 12070
        if (snap->def->parent == NULL) {
            virReportOOMError();
            rep->err = -1;
            return;
12071 12072
        }
    }
12073

12074 12075 12076
    if (!snap->sibling)
        rep->last = snap;

12077 12078
    rep->err = qemuDomainSnapshotWriteMetadata(rep->vm, snap,
                                               rep->driver->snapshotDir);
12079 12080
}

C
Chris Lalancette 已提交
12081 12082 12083 12084 12085 12086 12087 12088
static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                                    unsigned int flags)
{
    struct qemud_driver *driver = snapshot->domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
12089
    struct qemu_snap_remove rem;
12090
    struct snap_reparent rep;
12091
    bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);
12092
    int external = 0;
C
Chris Lalancette 已提交
12093

12094
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
12095 12096
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY |
                  VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
12097

C
Chris Lalancette 已提交
12098 12099 12100 12101
    qemuDriverLock(driver);
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, snapshot->domain->uuid);
    if (!vm) {
12102 12103
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
C
Chris Lalancette 已提交
12104 12105 12106
        goto cleanup;
    }

12107
    snap = virDomainSnapshotFindByName(vm->snapshots, snapshot->name);
C
Chris Lalancette 已提交
12108
    if (!snap) {
12109 12110 12111
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("no domain snapshot with matching name '%s'"),
                       snapshot->name);
C
Chris Lalancette 已提交
12112 12113 12114
        goto cleanup;
    }

12115 12116 12117 12118 12119
    if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY)) {
        if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) &&
            snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT)
            external++;
        if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
E
Eric Blake 已提交
12120
            virDomainSnapshotForEachDescendant(snap,
12121 12122 12123
                                               qemuDomainSnapshotCountExternal,
                                               &external);
        if (external) {
12124 12125 12126
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("deletion of %d external disk snapshots not "
                             "supported yet"), external);
12127 12128 12129 12130
            goto cleanup;
        }
    }

12131
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
12132 12133
        goto cleanup;

12134 12135
    if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                 VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
C
Chris Lalancette 已提交
12136 12137
        rem.driver = driver;
        rem.vm = vm;
12138
        rem.metadata_only = metadata_only;
C
Chris Lalancette 已提交
12139
        rem.err = 0;
12140
        rem.current = false;
E
Eric Blake 已提交
12141
        virDomainSnapshotForEachDescendant(snap,
E
Eric Blake 已提交
12142
                                           qemuDomainSnapshotDiscardAll,
12143
                                           &rem);
C
Chris Lalancette 已提交
12144
        if (rem.err < 0)
12145
            goto endjob;
12146 12147 12148 12149 12150
        if (rem.current) {
            if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
                snap->def->current = true;
                if (qemuDomainSnapshotWriteMetadata(vm, snap,
                                                    driver->snapshotDir) < 0) {
12151 12152 12153
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("failed to set snapshot '%s' as current"),
                                   snap->def->name);
12154 12155 12156 12157
                    snap->def->current = false;
                    goto endjob;
                }
            }
12158
            vm->current_snapshot = snap;
12159
        }
12160
    } else if (snap->nchildren) {
12161
        rep.driver = driver;
12162
        rep.parent = snap->parent;
12163 12164
        rep.vm = vm;
        rep.err = 0;
12165
        rep.last = NULL;
E
Eric Blake 已提交
12166
        virDomainSnapshotForEachChild(snap,
12167 12168
                                      qemuDomainSnapshotReparentChildren,
                                      &rep);
12169 12170
        if (rep.err < 0)
            goto endjob;
12171
        /* Can't modify siblings during ForEachChild, so do it now.  */
12172 12173 12174
        snap->parent->nchildren += snap->nchildren;
        rep.last->sibling = snap->parent->first_child;
        snap->parent->first_child = snap->first_child;
C
Chris Lalancette 已提交
12175 12176
    }

12177 12178 12179
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
        snap->nchildren = 0;
        snap->first_child = NULL;
12180
        ret = 0;
12181
    } else {
12182
        virDomainSnapshotDropParent(snap);
12183
        ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only);
12184
    }
C
Chris Lalancette 已提交
12185

12186
endjob:
12187
    if (qemuDomainObjEndJob(driver, vm) == 0)
12188 12189
        vm = NULL;

C
Chris Lalancette 已提交
12190 12191 12192 12193 12194 12195
cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
12196

12197 12198 12199 12200 12201 12202 12203
static int qemuDomainMonitorCommand(virDomainPtr domain, const char *cmd,
                                    char **result, unsigned int flags)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
12204
    bool hmp;
12205

12206
    virCheckFlags(VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP, -1);
12207 12208 12209 12210 12211 12212

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
12213 12214
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
12215 12216 12217 12218
        goto cleanup;
    }

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

12224 12225 12226 12227
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

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

12233 12234
    priv = vm->privateData;

12235
    qemuDomainObjTaint(driver, vm, VIR_DOMAIN_TAINT_CUSTOM_MONITOR, -1);
12236

12237 12238
    hmp = !!(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP);

12239
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
12240
    ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result, hmp);
12241
    qemuDomainObjExitMonitorWithDriver(driver, vm);
12242 12243

endjob:
12244
    if (qemuDomainObjEndJob(driver, vm) == 0) {
12245 12246 12247 12248 12249 12250 12251 12252 12253 12254
        vm = NULL;
    }

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

12255

12256
static virDomainPtr qemuDomainAttach(virConnectPtr conn,
12257
                                     unsigned int pid_value,
12258 12259 12260 12261 12262 12263 12264 12265
                                     unsigned int flags)
{
    struct qemud_driver *driver = conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainPtr dom = NULL;
    virDomainChrSourceDefPtr monConfig = NULL;
    bool monJSON = false;
12266
    pid_t pid = pid_value;
12267
    char *pidfile = NULL;
12268 12269 12270 12271 12272 12273 12274 12275 12276 12277

    virCheckFlags(0, NULL);

    qemuDriverLock(driver);

    if (!(def = qemuParseCommandLinePid(driver->caps, pid,
                                        &pidfile, &monConfig, &monJSON)))
        goto cleanup;

    if (!monConfig) {
12278 12279
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("No monitor connection for pid %u"), pid_value);
12280 12281 12282
        goto cleanup;
    }
    if (monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
12283 12284 12285 12286 12287
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Cannot connect to monitor connection of type '%s' "
                         "for pid %u"),
                       virDomainChrTypeToString(monConfig->type),
                       pid_value);
12288 12289 12290 12291
        goto cleanup;
    }

    if (!(def->name) &&
12292
        virAsprintf(&def->name, "attach-pid-%u", pid_value) < 0) {
12293 12294 12295 12296 12297 12298 12299 12300 12301 12302
        virReportOOMError();
        goto cleanup;
    }

    if (virDomainObjIsDuplicate(&driver->domains, def, 1) < 0)
        goto cleanup;

    if (qemudCanonicalizeMachine(driver, def) < 0)
        goto cleanup;

12303
    if (qemuDomainAssignAddresses(def, NULL, NULL) < 0)
12304 12305 12306 12307 12308 12309 12310 12311 12312
        goto cleanup;

    if (!(vm = virDomainAssignDef(driver->caps,
                                  &driver->domains,
                                  def, false)))
        goto cleanup;

    def = NULL;

12313
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
12314 12315 12316 12317 12318 12319 12320 12321 12322 12323 12324 12325 12326 12327
        goto cleanup;

    if (qemuProcessAttach(conn, driver, vm, pid,
                          pidfile, monConfig, monJSON) < 0) {
        monConfig = NULL;
        goto endjob;
    }

    monConfig = NULL;

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

endjob:
12328
    if (qemuDomainObjEndJob(driver, vm) == 0) {
12329 12330 12331 12332 12333 12334 12335 12336 12337 12338 12339 12340 12341 12342 12343
        vm = NULL;
        goto cleanup;
    }

cleanup:
    virDomainDefFree(def);
    virDomainChrSourceDefFree(monConfig);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    VIR_FREE(pidfile);
    return dom;
}


12344 12345
static int
qemuDomainOpenConsole(virDomainPtr dom,
12346
                      const char *dev_name,
12347 12348 12349 12350 12351 12352 12353
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    int i;
    virDomainChrDefPtr chr = NULL;
12354
    qemuDomainObjPrivatePtr priv;
12355

12356 12357
    virCheckFlags(VIR_DOMAIN_CONSOLE_SAFE |
                  VIR_DOMAIN_CONSOLE_FORCE, -1);
12358

12359
    if (!(vm = qemuDomObjFromDomain(dom)))
12360 12361 12362
        goto cleanup;

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

12368 12369
    priv = vm->privateData;

12370
    if (dev_name) {
12371 12372 12373 12374 12375
        for (i = 0 ; !chr && i < vm->def->nconsoles ; i++) {
            if (vm->def->consoles[i]->info.alias &&
                STREQ(dev_name, vm->def->consoles[i]->info.alias))
                chr = vm->def->consoles[i];
        }
12376
        for (i = 0 ; !chr && i < vm->def->nserials ; i++) {
12377
            if (STREQ(dev_name, vm->def->serials[i]->info.alias))
12378 12379 12380
                chr = vm->def->serials[i];
        }
        for (i = 0 ; !chr && i < vm->def->nparallels ; i++) {
12381
            if (STREQ(dev_name, vm->def->parallels[i]->info.alias))
12382 12383 12384
                chr = vm->def->parallels[i];
        }
    } else {
12385 12386
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
12387 12388 12389 12390 12391
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
12392 12393 12394
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find character device %s"),
                       NULLSTR(dev_name));
12395 12396 12397
        goto cleanup;
    }

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

12405 12406 12407 12408 12409 12410 12411
    /* handle mutually exclusive access to console devices */
    ret = virConsoleOpen(priv->cons,
                         chr->source.data.file.path,
                         st,
                         (flags & VIR_DOMAIN_CONSOLE_FORCE) != 0);

    if (ret == 1) {
12412 12413
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Active console session exists for this domain"));
12414 12415
        ret = -1;
    }
12416 12417 12418 12419 12420 12421 12422

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

E
Eric Blake 已提交
12423
static char *
E
Eric Blake 已提交
12424
qemuDiskPathToAlias(virDomainObjPtr vm, const char *path, int *idx)
E
Eric Blake 已提交
12425
{
12426 12427
    int i;
    char *ret = NULL;
12428
    virDomainDiskDefPtr disk;
12429

12430 12431 12432
    i = virDomainDiskIndexByName(vm->def, path, true);
    if (i < 0)
        goto cleanup;
12433

12434
    disk = vm->def->disks[i];
E
Eric Blake 已提交
12435 12436
    if (idx)
        *idx = i;
12437

12438 12439 12440 12441 12442 12443 12444 12445
    if (disk->type != VIR_DOMAIN_DISK_TYPE_BLOCK &&
        disk->type != VIR_DOMAIN_DISK_TYPE_FILE)
        goto cleanup;

    if (disk->src) {
        if (virAsprintf(&ret, "drive-%s", disk->info.alias) < 0) {
            virReportOOMError();
            return NULL;
12446 12447 12448
        }
    }

12449
cleanup:
12450
    if (!ret) {
12451 12452
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("No device found for specified path"));
12453 12454 12455 12456 12457
    }
    return ret;
}

static int
12458
qemuDomainBlockJobImpl(virDomainPtr dom, const char *path, const char *base,
12459
                       unsigned long bandwidth, virDomainBlockJobInfoPtr info,
12460
                       int mode, unsigned int flags)
12461 12462 12463 12464 12465
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
E
Eric Blake 已提交
12466
    char *device = NULL;
12467
    int ret = -1;
12468
    bool async = false;
12469 12470 12471
    virDomainEventPtr event = NULL;
    int idx;
    virDomainDiskDefPtr disk;
12472 12473 12474 12475 12476

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
12477 12478
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
12479 12480
        goto cleanup;
    }
12481
    if (!virDomainObjIsActive(vm)) {
12482 12483
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
12484 12485 12486
        goto cleanup;
    }

12487
    priv = vm->privateData;
12488
    if (qemuCapsGet(priv->caps, QEMU_CAPS_BLOCKJOB_ASYNC)) {
12489
        async = true;
12490
    } else if (!qemuCapsGet(priv->caps, QEMU_CAPS_BLOCKJOB_SYNC)) {
12491 12492
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block jobs not supported with this QEMU binary"));
12493 12494
        goto cleanup;
    } else if (base) {
12495 12496 12497
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("partial block pull not supported with this "
                         "QEMU binary"));
12498
        goto cleanup;
12499
    } else if (mode == BLOCK_JOB_PULL && bandwidth) {
12500 12501 12502
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("setting bandwidth at start of block pull not "
                         "supported with this QEMU binary"));
12503
        goto cleanup;
12504
    }
12505

12506 12507
    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device)
12508
        goto cleanup;
12509
    disk = vm->def->disks[idx];
12510 12511 12512

    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;
12513 12514

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

12520
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
12521
    /* XXX - libvirt should really be tracking the backing file chain
12522 12523
     * itself, and validating that base is on the chain, rather than
     * relying on qemu to do this.  */
12524 12525
    ret = qemuMonitorBlockJob(priv->mon, device, base, bandwidth, info, mode,
                              async);
12526
    qemuDomainObjExitMonitorWithDriver(driver, vm);
12527 12528 12529 12530 12531 12532 12533 12534 12535 12536 12537 12538 12539 12540 12541 12542 12543 12544 12545 12546 12547 12548 12549 12550 12551 12552 12553 12554 12555 12556 12557 12558 12559 12560 12561 12562 12563 12564 12565
    if (ret < 0)
        goto endjob;

    /* With synchronous block cancel, we must synthesize an event, and
     * we silently ignore the ABORT_ASYNC flag.  With asynchronous
     * block cancel, the event will come from qemu, but without the
     * ABORT_ASYNC flag, we must block to guarantee synchronous
     * operation.  We do the waiting while still holding the VM job,
     * to prevent newly scheduled block jobs from confusing us.  */
    if (mode == BLOCK_JOB_ABORT) {
        if (!async) {
            int type = VIR_DOMAIN_BLOCK_JOB_TYPE_PULL;
            int status = VIR_DOMAIN_BLOCK_JOB_CANCELED;
            event = virDomainEventBlockJobNewFromObj(vm, disk->src, type,
                                                     status);
        } else if (!(flags & VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC)) {
            while (1) {
                /* Poll every 50ms */
                static struct timespec ts = { .tv_sec = 0,
                                              .tv_nsec = 50 * 1000 * 1000ull };
                virDomainBlockJobInfo dummy;

                qemuDomainObjEnterMonitorWithDriver(driver, vm);
                ret = qemuMonitorBlockJob(priv->mon, device, NULL, 0, &dummy,
                                          BLOCK_JOB_INFO, async);
                qemuDomainObjExitMonitorWithDriver(driver, vm);

                if (ret <= 0)
                    break;

                virDomainObjUnlock(vm);
                qemuDriverUnlock(driver);

                nanosleep(&ts, NULL);

                qemuDriverLock(driver);
                virDomainObjLock(vm);

                if (!virDomainObjIsActive(vm)) {
12566 12567
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("domain is not running"));
12568 12569 12570 12571 12572 12573
                    ret = -1;
                    break;
                }
            }
        }
    }
12574 12575

endjob:
12576 12577 12578 12579 12580 12581 12582 12583 12584
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

cleanup:
    VIR_FREE(device);
    if (vm)
        virDomainObjUnlock(vm);
12585 12586
    if (event)
        qemuDomainEventQueue(driver, event);
12587 12588 12589 12590 12591 12592 12593
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainBlockJobAbort(virDomainPtr dom, const char *path, unsigned int flags)
{
12594 12595 12596
    virCheckFlags(VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC, -1);
    return qemuDomainBlockJobImpl(dom, path, NULL, 0, NULL, BLOCK_JOB_ABORT,
                                  flags);
12597 12598 12599 12600 12601 12602 12603
}

static int
qemuDomainGetBlockJobInfo(virDomainPtr dom, const char *path,
                           virDomainBlockJobInfoPtr info, unsigned int flags)
{
    virCheckFlags(0, -1);
12604 12605
    return qemuDomainBlockJobImpl(dom, path, NULL, 0, info, BLOCK_JOB_INFO,
                                  flags);
12606 12607 12608 12609 12610 12611 12612
}

static int
qemuDomainBlockJobSetSpeed(virDomainPtr dom, const char *path,
                           unsigned long bandwidth, unsigned int flags)
{
    virCheckFlags(0, -1);
12613
    return qemuDomainBlockJobImpl(dom, path, NULL, bandwidth, NULL,
12614
                                  BLOCK_JOB_SPEED, flags);
12615 12616 12617
}

static int
12618 12619
qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base,
                      unsigned long bandwidth, unsigned int flags)
12620 12621
{
    virCheckFlags(0, -1);
12622 12623
    return qemuDomainBlockJobImpl(dom, path, base, bandwidth, NULL,
                                  BLOCK_JOB_PULL, flags);
12624
}
12625

12626 12627 12628 12629 12630 12631 12632
static int
qemuDomainBlockPull(virDomainPtr dom, const char *path, unsigned long bandwidth,
                    unsigned int flags)
{
    return qemuDomainBlockRebase(dom, path, NULL, bandwidth, flags);
}

12633 12634 12635 12636 12637 12638 12639 12640 12641 12642 12643 12644 12645 12646 12647 12648 12649 12650 12651
static int
qemuDomainOpenGraphics(virDomainPtr dom,
                       unsigned int idx,
                       int fd,
                       unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
    const char *protocol;

    virCheckFlags(VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH, -1);

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
12652 12653
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
12654 12655 12656 12657
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
12658 12659
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
12660 12661 12662 12663 12664 12665
        goto cleanup;
    }

    priv = vm->privateData;

    if (idx >= vm->def->ngraphics) {
12666 12667
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No graphics backend with index %d"), idx);
12668 12669 12670 12671 12672 12673 12674 12675 12676 12677
        goto cleanup;
    }
    switch (vm->def->graphics[idx]->type) {
    case VIR_DOMAIN_GRAPHICS_TYPE_VNC:
        protocol = "vnc";
        break;
    case VIR_DOMAIN_GRAPHICS_TYPE_SPICE:
        protocol = "spice";
        break;
    default:
12678 12679 12680
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Can only open VNC or SPICE graphics backends, not %s"),
                       virDomainGraphicsTypeToString(vm->def->graphics[idx]->type));
12681 12682 12683 12684 12685 12686 12687 12688 12689 12690 12691 12692 12693 12694 12695 12696 12697 12698 12699 12700 12701
        goto cleanup;
    }

    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    ret = qemuMonitorOpenGraphics(priv->mon, protocol, fd, "graphicsfd",
                                  (flags & VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH) != 0);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

12702 12703 12704 12705 12706 12707 12708 12709 12710 12711 12712 12713
static int
qemuDomainSetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int nparams,
                         unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virDomainDefPtr persistentDef = NULL;
    virDomainBlockIoTuneInfo info;
E
Eric Blake 已提交
12714
    virDomainBlockIoTuneInfo *oldinfo;
12715 12716 12717 12718 12719
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    const char *device = NULL;
    int ret = -1;
    int i;
    int idx = -1;
E
Eric Blake 已提交
12720 12721
    bool set_bytes = false;
    bool set_iops = false;
12722 12723 12724

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
12725 12726 12727 12728 12729 12730 12731 12732 12733 12734 12735 12736 12737 12738 12739
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC,
                                       VIR_TYPED_PARAM_ULLONG,
                                       NULL) < 0)
        return -1;
12740 12741 12742 12743 12744 12745 12746

    memset(&info, 0, sizeof(info));

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
12747 12748
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
12749 12750
        goto cleanup;
    }
12751
    priv = vm->privateData;
12752
    if (!qemuCapsGet(priv->caps, QEMU_CAPS_DRIVE_IOTUNE)) {
12753 12754 12755
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block I/O throttling not supported with this "
                         "QEMU binary"));
12756 12757
        goto cleanup;
    }
12758

E
Eric Blake 已提交
12759
    device = qemuDiskPathToAlias(vm, disk, &idx);
12760 12761 12762 12763 12764 12765 12766
    if (!device) {
        goto cleanup;
    }

    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

12767 12768
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
12769 12770 12771 12772 12773 12774 12775
        goto endjob;

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

        if (STREQ(param->field, VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC)) {
            info.total_bytes_sec = param->value.ul;
E
Eric Blake 已提交
12776
            set_bytes = true;
12777 12778 12779
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC)) {
            info.read_bytes_sec = param->value.ul;
E
Eric Blake 已提交
12780
            set_bytes = true;
12781 12782 12783
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC)) {
            info.write_bytes_sec = param->value.ul;
E
Eric Blake 已提交
12784
            set_bytes = true;
12785 12786 12787
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC)) {
            info.total_iops_sec = param->value.ul;
E
Eric Blake 已提交
12788
            set_iops = true;
12789 12790 12791
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC)) {
            info.read_iops_sec = param->value.ul;
E
Eric Blake 已提交
12792
            set_iops = true;
12793 12794 12795
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC)) {
            info.write_iops_sec = param->value.ul;
E
Eric Blake 已提交
12796
            set_iops = true;
12797 12798 12799 12800 12801
        }
    }

    if ((info.total_bytes_sec && info.read_bytes_sec) ||
        (info.total_bytes_sec && info.write_bytes_sec)) {
12802 12803
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("total and read/write of bytes_sec cannot be set at the same time"));
12804 12805 12806 12807 12808
        goto endjob;
    }

    if ((info.total_iops_sec && info.read_iops_sec) ||
        (info.total_iops_sec && info.write_iops_sec)) {
12809 12810
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("total and read/write of iops_sec cannot be set at the same time"));
12811 12812 12813 12814
        goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
E
Eric Blake 已提交
12815 12816 12817 12818 12819 12820 12821 12822 12823 12824 12825 12826 12827 12828
        /* If the user didn't specify bytes limits, inherit previous
         * values; likewise if the user didn't specify iops
         * limits.  */
        oldinfo = &vm->def->disks[idx]->blkdeviotune;
        if (!set_bytes) {
            info.total_bytes_sec = oldinfo->total_bytes_sec;
            info.read_bytes_sec = oldinfo->read_bytes_sec;
            info.write_bytes_sec = oldinfo->write_bytes_sec;
        }
        if (!set_iops) {
            info.total_iops_sec = oldinfo->total_iops_sec;
            info.read_iops_sec = oldinfo->read_iops_sec;
            info.write_iops_sec = oldinfo->write_iops_sec;
        }
12829 12830 12831
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
        ret = qemuMonitorSetBlockIoThrottle(priv->mon, device, &info);
        qemuDomainObjExitMonitorWithDriver(driver, vm);
L
Lei Li 已提交
12832 12833
        if (ret < 0)
            goto endjob;
12834
        vm->def->disks[idx]->blkdeviotune = info;
12835 12836 12837
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
12838 12839 12840 12841
        sa_assert(persistentDef);
        idx = virDomainDiskIndexByName(persistentDef, disk, true);
        if (idx < 0)
            goto endjob;
E
Eric Blake 已提交
12842 12843 12844 12845 12846 12847 12848 12849 12850 12851 12852
        oldinfo = &persistentDef->disks[idx]->blkdeviotune;
        if (!set_bytes) {
            info.total_bytes_sec = oldinfo->total_bytes_sec;
            info.read_bytes_sec = oldinfo->read_bytes_sec;
            info.write_bytes_sec = oldinfo->write_bytes_sec;
        }
        if (!set_iops) {
            info.total_iops_sec = oldinfo->total_iops_sec;
            info.read_iops_sec = oldinfo->read_iops_sec;
            info.write_iops_sec = oldinfo->write_iops_sec;
        }
12853 12854 12855
        persistentDef->disks[idx]->blkdeviotune = info;
        ret = virDomainSaveConfig(driver->configDir, persistentDef);
        if (ret < 0) {
12856
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
12857 12858 12859 12860 12861 12862 12863 12864 12865 12866 12867 12868 12869 12870 12871 12872 12873 12874 12875 12876 12877 12878 12879 12880 12881 12882 12883 12884 12885 12886 12887 12888 12889 12890 12891 12892 12893 12894 12895 12896 12897 12898 12899 12900 12901
                           _("Write to config file failed"));
            goto endjob;
        }
    }

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

cleanup:
    VIR_FREE(device);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainGetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int *nparams,
                         unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virDomainDefPtr persistentDef = NULL;
    virDomainBlockIoTuneInfo reply;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    const char *device = NULL;
    int ret = -1;
    int i;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

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

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
12902 12903
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
12904 12905 12906 12907 12908 12909 12910 12911 12912 12913
        goto cleanup;
    }

    if ((*nparams) == 0) {
        /* Current number of parameters supported by QEMU Block I/O Throttling */
        *nparams = QEMU_NB_BLOCK_IO_TUNE_PARAM;
        ret = 0;
        goto cleanup;
    }

E
Eric Blake 已提交
12914
    device = qemuDiskPathToAlias(vm, disk, NULL);
12915 12916 12917 12918 12919 12920 12921 12922

    if (!device) {
        goto cleanup;
    }

    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

12923 12924
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
12925 12926 12927 12928 12929 12930 12931 12932 12933 12934 12935 12936 12937 12938 12939 12940 12941 12942 12943 12944 12945 12946 12947
        goto endjob;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        priv = vm->privateData;
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
        ret = qemuMonitorGetBlockIoThrottle(priv->mon, device, &reply);
        qemuDomainObjExitMonitorWithDriver(driver, vm);
        if (ret < 0)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        int idx = virDomainDiskIndexByName(vm->def, disk, true);
        if (idx < 0)
            goto endjob;
        reply = persistentDef->disks[idx]->blkdeviotune;
    }

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

        switch(i) {
        case 0:
12948 12949 12950 12951
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_bytes_sec) < 0)
12952 12953 12954
                goto endjob;
            break;
        case 1:
12955 12956 12957 12958
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_bytes_sec) < 0)
12959 12960 12961
                goto endjob;
            break;
        case 2:
12962 12963 12964 12965
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_bytes_sec) < 0)
12966 12967 12968
                goto endjob;
            break;
        case 3:
12969 12970 12971 12972
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_iops_sec) < 0)
12973 12974 12975
                goto endjob;
            break;
        case 4:
12976 12977 12978 12979
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_iops_sec) < 0)
12980 12981 12982
                goto endjob;
            break;
        case 5:
12983 12984 12985 12986
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_iops_sec) < 0)
12987 12988 12989 12990 12991 12992 12993 12994 12995 12996 12997 12998 12999 13000 13001 13002 13003 13004 13005 13006 13007 13008
                goto endjob;
            break;
        default:
            break;
        }
    }

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

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

cleanup:
    VIR_FREE(device);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}
13009

13010 13011 13012 13013 13014 13015 13016 13017 13018 13019 13020 13021 13022 13023 13024 13025 13026 13027 13028 13029 13030 13031 13032
static int
qemuDomainGetDiskErrors(virDomainPtr dom,
                        virDomainDiskErrorPtr errors,
                        unsigned int nerrors,
                        unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virHashTablePtr table = NULL;
    int ret = -1;
    int i;
    int n = 0;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
13033 13034
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
13035 13036 13037 13038 13039 13040 13041 13042 13043
        goto cleanup;
    }

    priv = vm->privateData;

    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
13044 13045
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
13046 13047 13048 13049 13050 13051 13052 13053 13054 13055 13056 13057 13058 13059 13060 13061 13062 13063 13064 13065 13066 13067 13068 13069 13070 13071 13072 13073 13074 13075 13076 13077 13078 13079 13080 13081 13082 13083 13084 13085 13086 13087 13088 13089 13090 13091 13092 13093 13094
        goto endjob;
    }

    if (!errors) {
        ret = vm->def->ndisks;
        goto endjob;
    }

    qemuDomainObjEnterMonitor(driver, vm);
    table = qemuMonitorGetBlockInfo(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);
    if (!table)
        goto endjob;

    for (i = n = 0; i < vm->def->ndisks; i++) {
        struct qemuDomainDiskInfo *info;
        virDomainDiskDefPtr disk = vm->def->disks[i];

        if ((info = virHashLookup(table, disk->info.alias)) &&
            info->io_status != VIR_DOMAIN_DISK_ERROR_NONE) {
            if (n == nerrors)
                break;

            if (!(errors[n].disk = strdup(disk->dst))) {
                virReportOOMError();
                goto endjob;
            }
            errors[n].error = info->io_status;
            n++;
        }
    }

    ret = n;

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    virHashFree(table);
    if (ret < 0) {
        for (i = 0; i < n; i++)
            VIR_FREE(errors[i].disk);
    }
    return ret;
}

13095 13096 13097 13098 13099 13100 13101 13102 13103 13104 13105 13106 13107 13108 13109 13110 13111 13112 13113 13114 13115 13116 13117
static int
qemuDomainSetMetadata(virDomainPtr dom,
                      int type,
                      const char *metadata,
                      const char *key ATTRIBUTE_UNUSED,
                      const char *uri ATTRIBUTE_UNUSED,
                      unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDefPtr persistentDef;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
13118 13119
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
13120 13121 13122 13123 13124 13125 13126 13127 13128 13129 13130 13131 13132 13133 13134 13135 13136 13137 13138 13139 13140 13141
        goto cleanup;
    }

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

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        switch ((virDomainMetadataType) type) {
        case VIR_DOMAIN_METADATA_DESCRIPTION:
            VIR_FREE(vm->def->description);
            if (metadata &&
                !(vm->def->description = strdup(metadata)))
                goto no_memory;
            break;
        case VIR_DOMAIN_METADATA_TITLE:
            VIR_FREE(vm->def->title);
            if (metadata &&
                !(vm->def->title = strdup(metadata)))
                goto no_memory;
            break;
        case VIR_DOMAIN_METADATA_ELEMENT:
13142
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
13143
                           _("QEmu driver does not support modifying "
13144
                             "<metadata> element"));
13145 13146 13147
            goto cleanup;
            break;
        default:
13148 13149
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("unknown metadata type"));
13150 13151 13152 13153 13154 13155 13156 13157 13158 13159 13160 13161 13162 13163 13164 13165 13166 13167 13168 13169
            goto cleanup;
            break;
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        switch ((virDomainMetadataType) type) {
        case VIR_DOMAIN_METADATA_DESCRIPTION:
            VIR_FREE(persistentDef->description);
            if (metadata &&
                !(persistentDef->description = strdup(metadata)))
                goto no_memory;
            break;
        case VIR_DOMAIN_METADATA_TITLE:
            VIR_FREE(persistentDef->title);
            if (metadata &&
                !(persistentDef->title = strdup(metadata)))
                goto no_memory;
            break;
        case VIR_DOMAIN_METADATA_ELEMENT:
13170
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
13171
                           _("QEMU driver does not support "
13172
                             "<metadata> element"));
13173 13174
            goto cleanup;
         default:
13175 13176
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("unknown metadata type"));
13177 13178 13179 13180 13181 13182 13183 13184 13185 13186 13187 13188 13189 13190 13191 13192 13193 13194 13195 13196 13197 13198 13199 13200 13201 13202 13203 13204 13205 13206 13207 13208 13209 13210 13211 13212 13213 13214 13215 13216 13217
            goto cleanup;
            break;
        }

        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            goto cleanup;
    }

    ret = 0;

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return ret;
no_memory:
    virReportOOMError();
    goto cleanup;
}

static char *
qemuDomainGetMetadata(virDomainPtr dom,
                      int type,
                      const char *uri ATTRIBUTE_UNUSED,
                      unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    virDomainDefPtr def;
    char *ret = NULL;
    char *field = NULL;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, NULL);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
13218 13219
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
13220 13221 13222 13223 13224 13225 13226 13227 13228 13229 13230 13231 13232 13233 13234 13235 13236 13237
        goto cleanup;
    }

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

    /* use correct domain definition according to flags */
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
        def = vm->def;

    switch ((virDomainMetadataType) type) {
    case VIR_DOMAIN_METADATA_DESCRIPTION:
        field = def->description;
        break;
    case VIR_DOMAIN_METADATA_TITLE:
        field = def->title;
        break;
    case VIR_DOMAIN_METADATA_ELEMENT:
13238
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
13239
                       _("QEMU driver does not support "
13240
                         "<metadata> element"));
13241 13242 13243
        goto cleanup;
        break;
    default:
13244 13245
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("unknown metadata type"));
13246 13247 13248 13249 13250
        goto cleanup;
        break;
    }

    if (!field) {
13251 13252
        virReportError(VIR_ERR_NO_DOMAIN_METADATA, "%s",
                       _("Requested metadata element is not present"));
13253 13254 13255 13256 13257 13258 13259 13260 13261 13262 13263 13264 13265 13266
        goto cleanup;
    }

    if (!(ret = strdup(field))) {
        virReportOOMError();
        goto cleanup;
    }

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

13267 13268 13269 13270 13271 13272 13273 13274 13275 13276
/* qemuDomainGetCPUStats() with start_cpu == -1 */
static int
qemuDomainGetTotalcpuStats(virCgroupPtr group,
                           virTypedParameterPtr params,
                           int nparams)
{
    unsigned long long cpu_time;
    int ret;

    if (nparams == 0) /* return supported number of params */
E
Eric Blake 已提交
13277
        return QEMU_NB_TOTAL_CPU_STAT_PARAM;
13278 13279 13280 13281 13282 13283 13284
    /* entry 0 is cputime */
    ret = virCgroupGetCpuacctUsage(group, &cpu_time);
    if (ret < 0) {
        virReportSystemError(-ret, "%s", _("unable to get cpu account"));
        return -1;
    }

E
Eric Blake 已提交
13285 13286 13287 13288 13289 13290 13291 13292 13293 13294 13295 13296 13297 13298 13299 13300 13301 13302 13303 13304 13305 13306 13307 13308 13309 13310 13311 13312 13313
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_CPU_STATS_CPUTIME,
                                VIR_TYPED_PARAM_ULLONG, cpu_time) < 0)
        return -1;

    if (nparams > 1) {
        unsigned long long user;
        unsigned long long sys;

        ret = virCgroupGetCpuacctStat(group, &user, &sys);
        if (ret < 0) {
            virReportSystemError(-ret, "%s", _("unable to get cpu account"));
            return -1;
        }

        if (virTypedParameterAssign(&params[1],
                                    VIR_DOMAIN_CPU_STATS_USERTIME,
                                    VIR_TYPED_PARAM_ULLONG, user) < 0)
            return -1;
        if (nparams > 2 &&
            virTypedParameterAssign(&params[2],
                                    VIR_DOMAIN_CPU_STATS_SYSTEMTIME,
                                    VIR_TYPED_PARAM_ULLONG, sys) < 0)
            return -1;

        if (nparams > QEMU_NB_TOTAL_CPU_STAT_PARAM)
            nparams = QEMU_NB_TOTAL_CPU_STAT_PARAM;
    }

    return nparams;
13314 13315
}

13316 13317 13318 13319 13320 13321 13322 13323 13324 13325 13326 13327 13328 13329 13330 13331 13332 13333 13334 13335 13336 13337 13338 13339 13340 13341 13342 13343 13344 13345 13346
/* This function gets the sums of cpu time consumed by all vcpus.
 * For example, if there are 4 physical cpus, and 2 vcpus in a domain,
 * then for each vcpu, the cpuacct.usage_percpu looks like this:
 *   t0 t1 t2 t3
 * and we have 2 groups of such data:
 *   v\p   0   1   2   3
 *   0   t00 t01 t02 t03
 *   1   t10 t11 t12 t13
 * for each pcpu, the sum is cpu time consumed by all vcpus.
 *   s0 = t00 + t10
 *   s1 = t01 + t11
 *   s2 = t02 + t12
 *   s3 = t03 + t13
 */
static int
getSumVcpuPercpuStats(virCgroupPtr group,
                      unsigned int nvcpu,
                      unsigned long long *sum_cpu_time,
                      unsigned int num)
{
    int ret = -1;
    int i;
    char *buf = NULL;
    virCgroupPtr group_vcpu = NULL;

    for (i = 0; i < nvcpu; i++) {
        char *pos;
        unsigned long long tmp;
        int j;

        if (virCgroupForVcpu(group, i, &group_vcpu, 0) < 0) {
13347 13348
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("error accessing cgroup cpuacct for vcpu"));
13349 13350 13351
            goto cleanup;
        }

13352
        if (virCgroupGetCpuacctPercpuUsage(group_vcpu, &buf) < 0)
13353 13354 13355 13356 13357
            goto cleanup;

        pos = buf;
        for (j = 0; j < num; j++) {
            if (virStrToLong_ull(pos, &pos, 10, &tmp) < 0) {
13358 13359
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("cpuacct parse error"));
13360 13361 13362 13363 13364 13365 13366 13367 13368 13369 13370 13371 13372 13373 13374 13375
                goto cleanup;
            }
            sum_cpu_time[j] += tmp;
        }

        virCgroupFree(&group_vcpu);
        VIR_FREE(buf);
    }

    ret = 0;
cleanup:
    virCgroupFree(&group_vcpu);
    VIR_FREE(buf);
    return ret;
}

13376 13377
static int
qemuDomainGetPercpuStats(virDomainPtr domain,
13378
                         virDomainObjPtr vm,
13379 13380 13381 13382 13383 13384
                         virCgroupPtr group,
                         virTypedParameterPtr params,
                         unsigned int nparams,
                         int start_cpu,
                         unsigned int ncpus)
{
H
Hu Tao 已提交
13385 13386
    virBitmapPtr map = NULL;
    virBitmapPtr map2 = NULL;
13387
    int rv = -1;
13388
    int i, id, max_id;
13389 13390
    char *pos;
    char *buf = NULL;
13391 13392 13393 13394
    unsigned long long *sum_cpu_time = NULL;
    unsigned long long *sum_cpu_pos;
    unsigned int n = 0;
    qemuDomainObjPrivatePtr priv = vm->privateData;
13395 13396
    virTypedParameterPtr ent;
    int param_idx;
13397
    unsigned long long cpu_time;
H
Hu Tao 已提交
13398
    bool result;
13399 13400 13401

    /* return the number of supported params */
    if (nparams == 0 && ncpus != 0)
13402
        return QEMU_NB_PER_CPU_STAT_PARAM;
13403

13404
    /* To parse account file, we need "present" cpu map.  */
13405 13406 13407 13408 13409 13410 13411 13412 13413 13414
    map = nodeGetCPUmap(domain->conn, &max_id, "present");
    if (!map)
        return rv;

    if (ncpus == 0) { /* returns max cpu ID */
        rv = max_id + 1;
        goto cleanup;
    }

    if (start_cpu > max_id) {
13415 13416 13417
        virReportError(VIR_ERR_INVALID_ARG,
                       _("start_cpu %d larger than maximum of %d"),
                       start_cpu, max_id);
13418 13419 13420 13421 13422 13423 13424
        goto cleanup;
    }

    /* we get percpu cputime accounting info. */
    if (virCgroupGetCpuacctPercpuUsage(group, &buf))
        goto cleanup;
    pos = buf;
13425
    memset(params, 0, nparams * ncpus);
13426

13427 13428 13429
    /* return percpu cputime in index 0 */
    param_idx = 0;

13430 13431 13432
    /* number of cpus to compute */
    id = max_id;

13433
    if (max_id - start_cpu > ncpus - 1)
13434
        id = start_cpu + ncpus - 1;
13435

13436
    for (i = 0; i <= id; i++) {
H
Hu Tao 已提交
13437 13438 13439
        if (virBitmapGetBit(map, i, &result) < 0)
            goto cleanup;
        if (!result) {
13440 13441
            cpu_time = 0;
        } else if (virStrToLong_ull(pos, &pos, 10, &cpu_time) < 0) {
13442
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
13443
                           _("cpuacct parse error"));
13444
            goto cleanup;
13445 13446
        } else {
            n++;
13447 13448 13449
        }
        if (i < start_cpu)
            continue;
13450
        ent = &params[(i - start_cpu) * nparams + param_idx];
E
Eric Blake 已提交
13451 13452 13453
        if (virTypedParameterAssign(ent, VIR_DOMAIN_CPU_STATS_CPUTIME,
                                    VIR_TYPED_PARAM_ULLONG, cpu_time) < 0)
            goto cleanup;
13454
    }
13455 13456 13457 13458 13459 13460 13461 13462 13463 13464 13465 13466 13467 13468 13469 13470

    /* return percpu vcputime in index 1 */
    if (++param_idx >= nparams) {
        rv = nparams;
        goto cleanup;
    }

    if (VIR_ALLOC_N(sum_cpu_time, n) < 0) {
        virReportOOMError();
        goto cleanup;
    }
    if (getSumVcpuPercpuStats(group, priv->nvcpupids, sum_cpu_time, n) < 0)
        goto cleanup;

    /* Check that the mapping of online cpus didn't change mid-parse.  */
    map2 = nodeGetCPUmap(domain->conn, &max_id, "present");
H
Hu Tao 已提交
13471
    if (!map2 || !virBitmapEqual(map, map2)) {
13472 13473
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("the set of online cpus changed while reading"));
13474 13475 13476 13477
        goto cleanup;
    }

    sum_cpu_pos = sum_cpu_time;
13478
    for (i = 0; i <= id; i++) {
H
Hu Tao 已提交
13479 13480 13481
        if (virBitmapGetBit(map, i, &result) < 0)
            goto cleanup;
        if (!result)
13482 13483 13484 13485 13486 13487 13488 13489 13490 13491 13492 13493 13494
            cpu_time = 0;
        else
            cpu_time = *(sum_cpu_pos++);
        if (i < start_cpu)
            continue;
        if (virTypedParameterAssign(&params[(i - start_cpu) * nparams +
                                            param_idx],
                                    VIR_DOMAIN_CPU_STATS_VCPUTIME,
                                    VIR_TYPED_PARAM_ULLONG,
                                    cpu_time) < 0)
            goto cleanup;
    }

13495 13496
    rv = param_idx + 1;
cleanup:
13497
    VIR_FREE(sum_cpu_time);
13498
    VIR_FREE(buf);
H
Hu Tao 已提交
13499 13500
    virBitmapFree(map);
    virBitmapFree(map2);
13501 13502 13503 13504 13505 13506 13507 13508 13509 13510 13511 13512 13513 13514 13515 13516 13517 13518 13519 13520 13521 13522 13523 13524
    return rv;
}


static int
qemuDomainGetCPUStats(virDomainPtr domain,
                virTypedParameterPtr params,
                unsigned int nparams,
                int start_cpu,
                unsigned int ncpus,
                unsigned int flags)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
    bool isActive;

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

    qemuDriverLock(driver);

    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (vm == NULL) {
13525 13526
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), domain->uuid);
13527 13528 13529 13530 13531
        goto cleanup;
    }

    isActive = virDomainObjIsActive(vm);
    if (!isActive) {
13532 13533
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
13534 13535 13536 13537
        goto cleanup;
    }

    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUACCT)) {
13538 13539
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPUACCT controller is not mounted"));
13540 13541 13542 13543
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
13544 13545
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find cgroup for domain %s"), vm->def->name);
13546 13547 13548 13549 13550 13551
        goto cleanup;
    }

    if (start_cpu == -1)
        ret = qemuDomainGetTotalcpuStats(group, params, nparams);
    else
13552
        ret = qemuDomainGetPercpuStats(domain, vm, group, params, nparams,
13553 13554 13555 13556 13557 13558 13559 13560 13561
                                       start_cpu, ncpus);
cleanup:
    virCgroupFree(&group);
    if (vm)
        virDomainObjUnlock(vm);
    qemuDriverUnlock(driver);
    return ret;
}

13562 13563 13564 13565 13566 13567 13568 13569 13570 13571 13572 13573 13574 13575
static int
qemuDomainPMSuspendForDuration(virDomainPtr dom,
                               unsigned int target,
                               unsigned long long duration,
                               unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

    if (duration) {
13576 13577
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Duration not supported. Use 0 for now"));
13578 13579 13580 13581 13582 13583
        return -1;
    }

    if (!(target == VIR_NODE_SUSPEND_TARGET_MEM ||
          target == VIR_NODE_SUSPEND_TARGET_DISK ||
          target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
13584 13585 13586
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unknown suspend target: %u"),
                       target);
13587 13588 13589 13590 13591 13592 13593 13594 13595 13596
        return -1;
    }

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
13597 13598
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
13599 13600 13601 13602 13603
        goto cleanup;
    }

    priv = vm->privateData;

13604
    if (!virDomainObjIsActive(vm)) {
13605 13606
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
13607 13608 13609
        goto cleanup;
    }

13610
    if (!qemuCapsGet(priv->caps, QEMU_CAPS_WAKEUP) &&
13611 13612
        (target == VIR_NODE_SUSPEND_TARGET_MEM ||
         target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
13613 13614 13615
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Unable to suspend domain due to "
                         "missing system_wakeup monitor command"));
O
Osier Yang 已提交
13616
        goto cleanup;
13617 13618
    }

13619 13620 13621 13622 13623 13624 13625 13626 13627 13628 13629 13630 13631 13632 13633 13634 13635
    if (vm->def->pm.s3 || vm->def->pm.s4) {
        if (vm->def->pm.s3 == VIR_DOMAIN_PM_STATE_DISABLED &&
            (target == VIR_NODE_SUSPEND_TARGET_MEM ||
             target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("S3 state is disabled for this domain"));
            goto cleanup;
        }

        if (vm->def->pm.s4 == VIR_DOMAIN_PM_STATE_DISABLED &&
            target == VIR_NODE_SUSPEND_TARGET_DISK) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("S4 state is disabled for this domain"));
            goto cleanup;
        }
    }

13636
    if (priv->agentError) {
13637 13638 13639
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                       _("QEMU guest agent is not "
                         "available due to an error"));
13640 13641 13642 13643
        goto cleanup;
    }

    if (!priv->agent) {
13644 13645
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("QEMU guest agent is not configured"));
13646 13647 13648 13649 13650 13651 13652
        goto cleanup;
    }

    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
13653 13654
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
13655 13656 13657 13658 13659 13660 13661 13662 13663 13664 13665 13666 13667 13668 13669 13670 13671
        goto endjob;
    }

    qemuDomainObjEnterAgent(driver, vm);
    ret = qemuAgentSuspend(priv->agent, target);
    qemuDomainObjExitAgent(driver, vm);

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

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

13672 13673 13674 13675 13676 13677 13678 13679 13680 13681 13682 13683 13684 13685 13686 13687 13688 13689
static int
qemuDomainPMWakeup(virDomainPtr dom,
                   unsigned int flags)
{
    struct qemud_driver *driver = dom->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
13690 13691
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
13692 13693 13694 13695 13696 13697 13698
        goto cleanup;
    }

    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
13699 13700
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
13701 13702 13703 13704 13705
        goto endjob;
    }

    priv = vm->privateData;

13706
    if (!qemuCapsGet(priv->caps, QEMU_CAPS_WAKEUP)) {
13707 13708 13709
       virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                      _("Unable to wake up domain due to "
                        "missing system_wakeup monitor command"));
13710 13711 13712 13713 13714 13715 13716 13717 13718 13719 13720 13721 13722 13723 13724 13725 13726
       goto endjob;
    }

    qemuDomainObjEnterMonitor(driver, vm);
    ret = qemuMonitorSystemWakeup(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

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

13727 13728 13729 13730 13731 13732 13733 13734
static int
qemuListAllDomains(virConnectPtr conn,
                   virDomainPtr **domains,
                   unsigned int flags)
{
    struct qemud_driver *driver = conn->privateData;
    int ret = -1;

O
Osier Yang 已提交
13735
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
13736 13737 13738 13739 13740 13741 13742 13743

    qemuDriverLock(driver);
    ret = virDomainList(conn, driver->domains.objs, domains, flags);
    qemuDriverUnlock(driver);

    return ret;
}

M
MATSUDA Daiki 已提交
13744
static char *
13745
qemuDomainAgentCommand(virDomainPtr domain,
M
MATSUDA Daiki 已提交
13746 13747 13748 13749 13750 13751 13752 13753 13754 13755 13756 13757 13758 13759 13760 13761 13762 13763 13764 13765 13766 13767 13768 13769 13770 13771 13772 13773 13774 13775 13776 13777 13778
                       const char *cmd,
                       int timeout,
                       unsigned int flags)
{
    struct qemud_driver *driver = domain->conn->privateData;
    virDomainObjPtr vm;
    int ret = -1;
    char *result = NULL;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, NULL);

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    qemuDriverUnlock(driver);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
        virReportError(VIR_ERR_NO_DOMAIN,
                        _("no domain with matching uuid '%s'"), uuidstr);
        goto cleanup;
    }

    priv = vm->privateData;

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

    if (priv->agentError) {
13779 13780 13781
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                       _("QEMU guest agent is not "
                         "available due to an error"));
M
MATSUDA Daiki 已提交
13782 13783 13784 13785 13786 13787 13788 13789 13790 13791 13792 13793 13794 13795 13796 13797 13798 13799 13800 13801 13802 13803 13804 13805 13806 13807 13808 13809 13810 13811 13812 13813 13814 13815 13816 13817 13818 13819
        goto cleanup;
    }

    if (!priv->agent) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("QEMU guest agent is not configured"));
        goto cleanup;
    }

    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

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

    qemuDomainObjEnterAgent(driver, vm);
    ret = qemuAgentArbitraryCommand(priv->agent, cmd, &result, timeout);
    qemuDomainObjExitAgent(driver, vm);
    if (ret < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to execute agent command"));
        goto endjob;
    }

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        vm = NULL;
    }

cleanup:
    if (vm)
        virDomainObjUnlock(vm);
    return result;
}

13820
static virDriver qemuDriver = {
13821
    .no = VIR_DRV_QEMU,
13822
    .name = QEMU_DRIVER_NAME,
13823 13824 13825 13826 13827 13828 13829 13830 13831 13832 13833 13834
    .open = qemudOpen, /* 0.2.0 */
    .close = qemudClose, /* 0.2.0 */
    .supports_feature = qemudSupportsFeature, /* 0.5.0 */
    .type = qemudGetType, /* 0.2.0 */
    .version = qemudGetVersion, /* 0.2.0 */
    .getHostname = virGetHostname, /* 0.3.3 */
    .getSysinfo = qemuGetSysinfo, /* 0.8.8 */
    .getMaxVcpus = qemudGetMaxVCPUs, /* 0.2.1 */
    .nodeGetInfo = nodeGetInfo, /* 0.2.0 */
    .getCapabilities = qemudGetCapabilities, /* 0.2.1 */
    .listDomains = qemudListDomains, /* 0.2.0 */
    .numOfDomains = qemudNumDomains, /* 0.2.0 */
13835
    .listAllDomains = qemuListAllDomains, /* 0.9.13 */
13836 13837 13838 13839 13840 13841
    .domainCreateXML = qemudDomainCreate, /* 0.2.0 */
    .domainLookupByID = qemudDomainLookupByID, /* 0.2.0 */
    .domainLookupByUUID = qemudDomainLookupByUUID, /* 0.2.0 */
    .domainLookupByName = qemudDomainLookupByName, /* 0.2.0 */
    .domainSuspend = qemudDomainSuspend, /* 0.2.0 */
    .domainResume = qemudDomainResume, /* 0.2.0 */
13842
    .domainShutdown = qemuDomainShutdown, /* 0.2.0 */
13843
    .domainShutdownFlags = qemuDomainShutdownFlags, /* 0.9.10 */
13844
    .domainReboot = qemuDomainReboot, /* 0.9.3 */
13845
    .domainReset = qemuDomainReset, /* 0.9.7 */
13846 13847
    .domainDestroy = qemuDomainDestroy, /* 0.2.0 */
    .domainDestroyFlags = qemuDomainDestroyFlags, /* 0.9.4 */
13848
    .domainGetOSType = qemudDomainGetOSType, /* 0.2.2 */
13849
    .domainGetMaxMemory = qemuDomainGetMaxMemory, /* 0.4.2 */
13850 13851 13852 13853 13854 13855 13856 13857 13858
    .domainSetMaxMemory = qemudDomainSetMaxMemory, /* 0.4.2 */
    .domainSetMemory = qemudDomainSetMemory, /* 0.4.2 */
    .domainSetMemoryFlags = qemudDomainSetMemoryFlags, /* 0.9.0 */
    .domainSetMemoryParameters = qemuDomainSetMemoryParameters, /* 0.8.5 */
    .domainGetMemoryParameters = qemuDomainGetMemoryParameters, /* 0.8.5 */
    .domainSetBlkioParameters = qemuDomainSetBlkioParameters, /* 0.9.0 */
    .domainGetBlkioParameters = qemuDomainGetBlkioParameters, /* 0.9.0 */
    .domainGetInfo = qemudDomainGetInfo, /* 0.2.0 */
    .domainGetState = qemuDomainGetState, /* 0.9.2 */
13859
    .domainGetControlInfo = qemuDomainGetControlInfo, /* 0.9.3 */
13860 13861
    .domainSave = qemuDomainSave, /* 0.2.0 */
    .domainSaveFlags = qemuDomainSaveFlags, /* 0.9.4 */
13862
    .domainRestore = qemuDomainRestore, /* 0.2.0 */
13863
    .domainRestoreFlags = qemuDomainRestoreFlags, /* 0.9.4 */
13864 13865
    .domainSaveImageGetXMLDesc = qemuDomainSaveImageGetXMLDesc, /* 0.9.4 */
    .domainSaveImageDefineXML = qemuDomainSaveImageDefineXML, /* 0.9.4 */
13866 13867
    .domainCoreDump = qemudDomainCoreDump, /* 0.7.0 */
    .domainScreenshot = qemuDomainScreenshot, /* 0.9.2 */
13868 13869
    .domainSetVcpus = qemuDomainSetVcpus, /* 0.4.4 */
    .domainSetVcpusFlags = qemuDomainSetVcpusFlags, /* 0.8.5 */
13870 13871
    .domainGetVcpusFlags = qemudDomainGetVcpusFlags, /* 0.8.5 */
    .domainPinVcpu = qemudDomainPinVcpu, /* 0.4.4 */
13872
    .domainPinVcpuFlags = qemudDomainPinVcpuFlags, /* 0.9.3 */
E
Eric Blake 已提交
13873
    .domainGetVcpuPinInfo = qemudDomainGetVcpuPinInfo, /* 0.9.3 */
H
Hu Tao 已提交
13874 13875
    .domainPinEmulator = qemudDomainPinEmulator, /* 0.10.0 */
    .domainGetEmulatorPinInfo = qemudDomainGetEmulatorPinInfo, /* 0.10.0 */
13876 13877 13878
    .domainGetVcpus = qemudDomainGetVcpus, /* 0.4.4 */
    .domainGetMaxVcpus = qemudDomainGetMaxVcpus, /* 0.4.4 */
    .domainGetSecurityLabel = qemudDomainGetSecurityLabel, /* 0.6.1 */
M
Marcelo Cerri 已提交
13879
    .domainGetSecurityLabelList = qemuDomainGetSecurityLabelList, /* 0.10.0 */
13880 13881 13882 13883 13884 13885
    .nodeGetSecurityModel = qemudNodeGetSecurityModel, /* 0.6.1 */
    .domainGetXMLDesc = qemuDomainGetXMLDesc, /* 0.2.0 */
    .domainXMLFromNative = qemuDomainXMLFromNative, /* 0.6.4 */
    .domainXMLToNative = qemuDomainXMLToNative, /* 0.6.4 */
    .listDefinedDomains = qemudListDefinedDomains, /* 0.2.0 */
    .numOfDefinedDomains = qemudNumDefinedDomains, /* 0.2.0 */
13886 13887
    .domainCreate = qemuDomainStart, /* 0.2.0 */
    .domainCreateWithFlags = qemuDomainStartWithFlags, /* 0.8.2 */
13888 13889
    .domainDefineXML = qemudDomainDefine, /* 0.2.0 */
    .domainUndefine = qemudDomainUndefine, /* 0.2.0 */
13890
    .domainUndefineFlags = qemuDomainUndefineFlags, /* 0.9.4 */
13891 13892 13893 13894 13895 13896 13897 13898 13899
    .domainAttachDevice = qemuDomainAttachDevice, /* 0.4.1 */
    .domainAttachDeviceFlags = qemuDomainAttachDeviceFlags, /* 0.7.7 */
    .domainDetachDevice = qemuDomainDetachDevice, /* 0.5.0 */
    .domainDetachDeviceFlags = qemuDomainDetachDeviceFlags, /* 0.7.7 */
    .domainUpdateDeviceFlags = qemuDomainUpdateDeviceFlags, /* 0.8.0 */
    .domainGetAutostart = qemudDomainGetAutostart, /* 0.2.1 */
    .domainSetAutostart = qemudDomainSetAutostart, /* 0.2.1 */
    .domainGetSchedulerType = qemuGetSchedulerType, /* 0.7.0 */
    .domainGetSchedulerParameters = qemuGetSchedulerParameters, /* 0.7.0 */
13900
    .domainGetSchedulerParametersFlags = qemuGetSchedulerParametersFlags, /* 0.9.2 */
13901
    .domainSetSchedulerParameters = qemuSetSchedulerParameters, /* 0.7.0 */
13902
    .domainSetSchedulerParametersFlags = qemuSetSchedulerParametersFlags, /* 0.9.2 */
13903
    .domainMigratePerform = qemudDomainMigratePerform, /* 0.5.0 */
13904
    .domainBlockResize = qemuDomainBlockResize, /* 0.9.8 */
13905 13906
    .domainBlockStats = qemuDomainBlockStats, /* 0.4.1 */
    .domainBlockStatsFlags = qemuDomainBlockStatsFlags, /* 0.9.5 */
13907 13908 13909 13910 13911
    .domainInterfaceStats = qemudDomainInterfaceStats, /* 0.4.1 */
    .domainMemoryStats = qemudDomainMemoryStats, /* 0.7.5 */
    .domainBlockPeek = qemudDomainBlockPeek, /* 0.4.4 */
    .domainMemoryPeek = qemudDomainMemoryPeek, /* 0.4.4 */
    .domainGetBlockInfo = qemuDomainGetBlockInfo, /* 0.8.1 */
13912
    .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
13913
    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
13914 13915 13916 13917 13918 13919 13920 13921 13922 13923 13924 13925 13926 13927 13928 13929 13930 13931 13932 13933 13934
    .nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.4.4 */
    .nodeGetFreeMemory = nodeGetFreeMemory, /* 0.4.4 */
    .domainEventRegister = qemuDomainEventRegister, /* 0.5.0 */
    .domainEventDeregister = qemuDomainEventDeregister, /* 0.5.0 */
    .domainMigratePrepare2 = qemudDomainMigratePrepare2, /* 0.5.0 */
    .domainMigrateFinish2 = qemudDomainMigrateFinish2, /* 0.5.0 */
    .nodeDeviceDettach = qemudNodeDeviceDettach, /* 0.6.1 */
    .nodeDeviceReAttach = qemudNodeDeviceReAttach, /* 0.6.1 */
    .nodeDeviceReset = qemudNodeDeviceReset, /* 0.6.1 */
    .domainMigratePrepareTunnel = qemudDomainMigratePrepareTunnel, /* 0.7.2 */
    .isEncrypted = qemuIsEncrypted, /* 0.7.3 */
    .isSecure = qemuIsSecure, /* 0.7.3 */
    .domainIsActive = qemuDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = qemuDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = qemuDomainIsUpdated, /* 0.8.6 */
    .cpuCompare = qemuCPUCompare, /* 0.7.5 */
    .cpuBaseline = qemuCPUBaseline, /* 0.7.7 */
    .domainGetJobInfo = qemuDomainGetJobInfo, /* 0.7.7 */
    .domainAbortJob = qemuDomainAbortJob, /* 0.7.7 */
    .domainMigrateSetMaxDowntime = qemuDomainMigrateSetMaxDowntime, /* 0.8.0 */
    .domainMigrateSetMaxSpeed = qemuDomainMigrateSetMaxSpeed, /* 0.9.0 */
13935
    .domainMigrateGetMaxSpeed = qemuDomainMigrateGetMaxSpeed, /* 0.9.5 */
13936 13937 13938 13939 13940 13941 13942 13943 13944
    .domainEventRegisterAny = qemuDomainEventRegisterAny, /* 0.8.0 */
    .domainEventDeregisterAny = qemuDomainEventDeregisterAny, /* 0.8.0 */
    .domainManagedSave = qemuDomainManagedSave, /* 0.8.0 */
    .domainHasManagedSaveImage = qemuDomainHasManagedSaveImage, /* 0.8.0 */
    .domainManagedSaveRemove = qemuDomainManagedSaveRemove, /* 0.8.0 */
    .domainSnapshotCreateXML = qemuDomainSnapshotCreateXML, /* 0.8.0 */
    .domainSnapshotGetXMLDesc = qemuDomainSnapshotGetXMLDesc, /* 0.8.0 */
    .domainSnapshotNum = qemuDomainSnapshotNum, /* 0.8.0 */
    .domainSnapshotListNames = qemuDomainSnapshotListNames, /* 0.8.0 */
13945
    .domainListAllSnapshots = qemuDomainListAllSnapshots, /* 0.9.13 */
13946 13947
    .domainSnapshotNumChildren = qemuDomainSnapshotNumChildren, /* 0.9.7 */
    .domainSnapshotListChildrenNames = qemuDomainSnapshotListChildrenNames, /* 0.9.7 */
13948
    .domainSnapshotListAllChildren = qemuDomainSnapshotListAllChildren, /* 0.9.13 */
13949 13950
    .domainSnapshotLookupByName = qemuDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = qemuDomainHasCurrentSnapshot, /* 0.8.0 */
13951
    .domainSnapshotGetParent = qemuDomainSnapshotGetParent, /* 0.9.7 */
13952
    .domainSnapshotCurrent = qemuDomainSnapshotCurrent, /* 0.8.0 */
13953 13954
    .domainSnapshotIsCurrent = qemuDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = qemuDomainSnapshotHasMetadata, /* 0.9.13 */
13955 13956 13957
    .domainRevertToSnapshot = qemuDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = qemuDomainSnapshotDelete, /* 0.8.0 */
    .qemuDomainMonitorCommand = qemuDomainMonitorCommand, /* 0.8.3 */
13958
    .qemuDomainAttach = qemuDomainAttach, /* 0.9.4 */
13959
    .qemuDomainArbitraryAgentCommand = qemuDomainAgentCommand, /* 0.10.0 */
13960
    .domainOpenConsole = qemuDomainOpenConsole, /* 0.8.6 */
13961
    .domainOpenGraphics = qemuDomainOpenGraphics, /* 0.9.7 */
13962
    .domainInjectNMI = qemuDomainInjectNMI, /* 0.9.2 */
13963 13964 13965 13966 13967 13968
    .domainMigrateBegin3 = qemuDomainMigrateBegin3, /* 0.9.2 */
    .domainMigratePrepare3 = qemuDomainMigratePrepare3, /* 0.9.2 */
    .domainMigratePrepareTunnel3 = qemuDomainMigratePrepareTunnel3, /* 0.9.2 */
    .domainMigratePerform3 = qemuDomainMigratePerform3, /* 0.9.2 */
    .domainMigrateFinish3 = qemuDomainMigrateFinish3, /* 0.9.2 */
    .domainMigrateConfirm3 = qemuDomainMigrateConfirm3, /* 0.9.2 */
13969
    .domainSendKey = qemuDomainSendKey, /* 0.9.4 */
13970 13971 13972 13973
    .domainBlockJobAbort = qemuDomainBlockJobAbort, /* 0.9.4 */
    .domainGetBlockJobInfo = qemuDomainGetBlockJobInfo, /* 0.9.4 */
    .domainBlockJobSetSpeed = qemuDomainBlockJobSetSpeed, /* 0.9.4 */
    .domainBlockPull = qemuDomainBlockPull, /* 0.9.4 */
13974
    .domainBlockRebase = qemuDomainBlockRebase, /* 0.9.10 */
13975
    .isAlive = qemuIsAlive, /* 0.9.8 */
13976
    .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */
13977 13978
    .domainSetBlockIoTune = qemuDomainSetBlockIoTune, /* 0.9.8 */
    .domainGetBlockIoTune = qemuDomainGetBlockIoTune, /* 0.9.8 */
13979 13980
    .domainSetNumaParameters = qemuDomainSetNumaParameters, /* 0.9.9 */
    .domainGetNumaParameters = qemuDomainGetNumaParameters, /* 0.9.9 */
13981 13982
    .domainGetInterfaceParameters = qemuDomainGetInterfaceParameters, /* 0.9.9 */
    .domainSetInterfaceParameters = qemuDomainSetInterfaceParameters, /* 0.9.9 */
13983
    .domainGetDiskErrors = qemuDomainGetDiskErrors, /* 0.9.10 */
13984 13985
    .domainSetMetadata = qemuDomainSetMetadata, /* 0.9.10 */
    .domainGetMetadata = qemuDomainGetMetadata, /* 0.9.10 */
13986
    .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */
13987
    .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */
13988
    .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */
13989 13990
    .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */
13991 13992 13993
};


13994
static virStateDriver qemuStateDriver = {
13995
    .name = "QEMU",
13996 13997 13998 13999
    .initialize = qemudStartup,
    .cleanup = qemudShutdown,
    .reload = qemudReload,
    .active = qemudActive,
14000
};
14001

14002
int qemuRegister(void) {
14003 14004 14005 14006
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
    return 0;
}