qemu_driver.c 474.0 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-2013 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 38 39 40
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <paths.h>
41
#include <stdio.h>
42
#include <sys/wait.h>
43
#include <sys/ioctl.h>
44
#include <sys/un.h>
45
#include <byteswap.h>
D
Daniel P. Berrange 已提交
46

47

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

61
#include "virerror.h"
62
#include "virlog.h"
63
#include "datatypes.h"
64
#include "virbuffer.h"
65
#include "virutil.h"
66
#include "nodeinfo.h"
67
#include "virstatslinux.h"
68
#include "capabilities.h"
69
#include "viralloc.h"
70
#include "viruuid.h"
71
#include "domain_conf.h"
72
#include "domain_audit.h"
73
#include "node_device_conf.h"
74
#include "virpci.h"
75
#include "virusb.h"
76
#include "virprocess.h"
C
Chris Lalancette 已提交
77
#include "libvirt_internal.h"
78
#include "virxml.h"
79
#include "cpu/cpu.h"
80
#include "virsysinfo.h"
81
#include "domain_nwfilter.h"
82
#include "virhook.h"
83
#include "virstoragefile.h"
E
Eric Blake 已提交
84
#include "virfile.h"
85
#include "fdstream.h"
86
#include "configmake.h"
87
#include "virthreadpool.h"
88
#include "locking/lock_manager.h"
89
#include "locking/domain_lock.h"
90
#include "virkeycode.h"
91
#include "virnodesuspend.h"
92
#include "virtime.h"
93
#include "virtypedparam.h"
94
#include "virbitmap.h"
95

96 97
#define VIR_FROM_THIS VIR_FROM_QEMU

98 99
#define QEMU_DRIVER_NAME "QEMU"

100 101
#define QEMU_NB_MEM_PARAM  3

102 103
#define QEMU_NB_BLOCK_IO_TUNE_PARAM  6

104 105
#define QEMU_NB_NUMA_PARAM 2

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

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

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

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

121 122 123 124 125 126 127 128 129 130 131
/* 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

132
#define QEMU_NB_BLKIO_PARAM  2
133

134 135
#define QEMU_NB_BANDWIDTH_PARAM 6

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

138
static int qemuShutdown(void);
139

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

145
static int qemuDomainGetMaxVcpus(virDomainPtr dom);
146

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


152
virQEMUDriverPtr qemu_driver = NULL;
153 154


155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
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,
};


184
struct qemuAutostartData {
185
    virQEMUDriverPtr driver;
186 187
    virConnectPtr conn;
};
188

189 190 191 192 193 194 195 196 197 198 199 200
/**
 * qemuDomObjFromDomainDriver:
 * @domain: Domain pointer that has to be looked up
 * @drv: Pointer to virQEMUDriverPtr to return the driver object
 *
 * This function looks up @domain in the domain list and returns the
 * appropriate virDomainObjPtr. On successful lookup, both driver and domain
 * object are returned locked.
 *
 * Returns the domain object if it's found and the driver. Both are locked.
 * In case of failure NULL is returned and the driver isn't locked.
 */
201
static virDomainObjPtr
202
qemuDomObjFromDomainDriver(virDomainPtr domain, virQEMUDriverPtr *drv)
203
{
204
    virQEMUDriverPtr driver = domain->conn->privateData;
205 206 207 208 209 210 211 212 213
    virDomainObjPtr vm;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        virUUIDFormat(domain->uuid, uuidstr);
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
214 215 216
        qemuDriverUnlock(driver);
        *drv = NULL;
        return NULL;
217 218
    }

219
    *drv = driver;
220 221 222
    return vm;
}

223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
/**
 * qemuDomObjFromDomain:
 * @domain: Domain pointer that has to be looked up
 *
 * This function looks up @domain and returns the appropriate
 * virDomainObjPtr. The driver is unlocked after the call.
 *
 * Returns the domain object which is locked on success, NULL
 * otherwise. The driver remains unlocked after the call.
 */
static virDomainObjPtr
qemuDomObjFromDomain(virDomainPtr domain)
{
    virDomainObjPtr vm;
    virQEMUDriverPtr driver;

    if (!(vm = qemuDomObjFromDomainDriver(domain, &driver)))
        return NULL;

    qemuDriverUnlock(driver);

    return vm;
}
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280

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

281
static void
282 283
qemuAutostartDomain(void *payload, const void *name ATTRIBUTE_UNUSED,
                    void *opaque)
284 285 286
{
    virDomainObjPtr vm = payload;
    struct qemuAutostartData *data = opaque;
287
    virErrorPtr err;
288 289 290 291
    int flags = 0;

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

293
    virObjectLock(vm);
294
    virResetLastError();
295 296 297 298 299 300 301 302 303 304 305 306
    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) {
307
            err = virGetLastError();
308
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
309
                      vm->def->name,
310
                      err ? err->message : _("unknown error"));
311
        }
312

313
        if (qemuDomainObjEndJob(data->driver, vm) == 0)
314
            vm = NULL;
315
    }
316

317
cleanup:
318
    if (vm)
319
        virObjectUnlock(vm);
320 321
}

322

323
static void
324
qemuAutostartDomains(virQEMUDriverPtr driver)
325
{
326 327 328 329 330
    /* 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
     */
331 332 333
    virConnectPtr conn = virConnectOpen(driver->privileged ?
                                        "qemu:///system" :
                                        "qemu:///session");
334
    /* Ignoring NULL conn which is mostly harmless here */
335
    struct qemuAutostartData data = { driver, conn };
336

337
    qemuDriverLock(driver);
338
    virHashForEach(driver->domains.objs, qemuAutostartDomain, &data);
339
    qemuDriverUnlock(driver);
340

341 342
    if (conn)
        virConnectClose(conn);
343 344
}

345
static int
346
qemuSecurityInit(virQEMUDriverPtr driver)
347
{
348
    char **names;
349 350 351
    virSecurityManagerPtr mgr = NULL;
    virSecurityManagerPtr stack = NULL;

352 353
    if (driver->securityDriverNames &&
        driver->securityDriverNames[0]) {
354
        names = driver->securityDriverNames;
355
        while (names && *names) {
356 357 358 359 360
            if (!(mgr = virSecurityManagerNew(*names,
                                              QEMU_DRIVER_NAME,
                                              driver->allowDiskFormatProbing,
                                              driver->securityDefaultConfined,
                                              driver->securityRequireConfined)))
361
                goto error;
362 363 364 365 366 367 368 369
            if (!stack) {
                if (!(stack = virSecurityManagerNewStack(mgr)))
                    goto error;
            } else {
                if (virSecurityManagerStackAddNested(stack, mgr) < 0)
                    goto error;
            }
            mgr = NULL;
370 371
            names++;
        }
372 373 374 375 376 377
    } else {
        if (!(mgr = virSecurityManagerNew(NULL,
                                          QEMU_DRIVER_NAME,
                                          driver->allowDiskFormatProbing,
                                          driver->securityDefaultConfined,
                                          driver->securityRequireConfined)))
378
            goto error;
379
        if (!(stack = virSecurityManagerNewStack(mgr)))
380
            goto error;
381 382
        mgr = NULL;
    }
383

384
    if (driver->privileged) {
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
        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;
401
    }
D
Daniel Veillard 已提交
402

403
    driver->securityManager = stack;
404
    return 0;
405

406
error:
407
    VIR_ERROR(_("Failed to initialize security drivers"));
408
    virSecurityManagerFree(stack);
409 410 411
    virSecurityManagerFree(mgr);
    return -1;
}
412

413

414
static virCapsPtr
415
qemuCreateCapabilities(virQEMUDriverPtr driver)
416
{
417
    size_t i;
418
    virCapsPtr caps;
419 420 421
    virSecurityManagerPtr *sec_managers = NULL;
    /* Security driver data */
    const char *doi, *model;
422

423
    /* Basic host arch / guest machine capabilities */
424
    if (!(caps = qemuCapsInit(driver->capsCache))) {
425 426
        virReportOOMError();
        return NULL;
427 428
    }

429 430
    if (driver->allowDiskFormatProbing) {
        caps->defaultDiskDriverName = NULL;
431
        caps->defaultDiskDriverType = VIR_STORAGE_FILE_AUTO;
432 433
    } else {
        caps->defaultDiskDriverName = "qemu";
434
        caps->defaultDiskDriverType = VIR_STORAGE_FILE_RAW;
435 436
    }

437 438
    qemuDomainSetPrivateDataHooks(caps);
    qemuDomainSetNamespaceHooks(caps);
439

440
    if (virGetHostUUID(caps->host.host_uuid)) {
441 442
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot get the host uuid"));
443
        goto err_exit;
444
    }
445

446 447 448 449 450
    /* access sec drivers and create a sec model for each one */
    sec_managers = virSecurityManagerGetNested(driver->securityManager);
    if (sec_managers == NULL) {
        goto err_exit;
    }
451

452 453 454 455
    /* calculate length */
    for (i = 0; sec_managers[i]; i++)
        ;
    caps->host.nsecModels = i;
456

457
    if (VIR_ALLOC_N(caps->host.secModels, caps->host.nsecModels) < 0)
458 459
        goto no_memory;

460 461 462 463
    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)))
464
            goto no_memory;
465
        if (!(caps->host.secModels[i].doi = strdup(doi)))
466
            goto no_memory;
467 468
        VIR_DEBUG("Initialized caps for security driver \"%s\" with "
                  "DOI \"%s\"", model, doi);
469
    }
470
    VIR_FREE(sec_managers);
471

472
    return caps;
473

474 475 476
no_memory:
    virReportOOMError();
err_exit:
477
    VIR_FREE(sec_managers);
478
    virCapabilitiesFree(caps);
479 480 481
    return NULL;
}

482 483 484 485 486

static void
qemuDomainSnapshotLoad(void *payload,
                       const void *name ATTRIBUTE_UNUSED,
                       void *data)
487
{
488 489 490 491 492 493 494 495 496
    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;
497
    virDomainSnapshotObjPtr snap = NULL;
498
    virDomainSnapshotObjPtr current = NULL;
499
    char ebuf[1024];
500
    unsigned int flags = (VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE |
501
                          VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
502
                          VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL);
503

504
    virObjectLock(vm);
505 506 507
    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);
508
        goto cleanup;
509 510
    }

511 512
    VIR_INFO("Scanning for snapshots for domain %s in %s", vm->def->name,
             snapDir);
513

514 515 516 517 518
    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)));
519
        goto cleanup;
520 521
    }

522 523 524
    while ((entry = readdir(dir))) {
        if (entry->d_name[0] == '.')
            continue;
525

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

530
        if (virAsprintf(&fullpath, "%s/%s", snapDir, entry->d_name) < 0) {
531
            VIR_ERROR(_("Failed to allocate memory for path"));
532 533
            continue;
        }
534

535 536 537 538 539 540 541 542
        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;
        }
543

544 545 546
        def = virDomainSnapshotDefParseString(xmlStr, qemu_driver->caps,
                                              QEMU_EXPECTED_VIRT_TYPES,
                                              flags);
547 548
        if (def == NULL) {
            /* Nothing we can do here, skip this one */
549 550
            VIR_ERROR(_("Failed to parse snapshot XML from file '%s'"),
                      fullpath);
551 552 553 554
            VIR_FREE(fullpath);
            VIR_FREE(xmlStr);
            continue;
        }
555

556
        snap = virDomainSnapshotAssignDef(vm->snapshots, def);
557 558
        if (snap == NULL) {
            virDomainSnapshotDefFree(def);
559 560 561 562
        } else if (snap->def->current) {
            current = snap;
            if (!vm->current_snapshot)
                vm->current_snapshot = snap;
563
        }
564

565 566
        VIR_FREE(fullpath);
        VIR_FREE(xmlStr);
567 568
    }

569 570 571 572 573 574
    if (vm->current_snapshot != current) {
        VIR_ERROR(_("Too many snapshots claiming to be current for domain %s"),
                  vm->def->name);
        vm->current_snapshot = NULL;
    }

575
    if (virDomainSnapshotUpdateRelations(vm->snapshots) < 0)
576 577 578
        VIR_ERROR(_("Snapshots have inconsistent relations for domain %s"),
                  vm->def->name);

579 580 581 582 583 584 585 586
    /* 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.
     */
587

588
    virResetLastError();
589

590 591 592 593
cleanup:
    if (dir)
        closedir(dir);
    VIR_FREE(snapDir);
594
    virObjectUnlock(vm);
595 596
}

597

598 599 600 601
static void
qemuDomainNetsRestart(void *payload,
                      const void *name ATTRIBUTE_UNUSED,
                      void *data ATTRIBUTE_UNUSED)
602
{
603 604 605 606
    int i;
    virDomainObjPtr vm = (virDomainObjPtr)payload;
    virDomainDefPtr def = vm->def;

607
    virObjectLock(vm);
608 609 610 611 612 613 614 615

    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,
616
                                                                 &net->mac,
617 618 619 620 621 622 623
                                                                 virDomainNetGetActualDirectDev(net),
                                                                 def->uuid,
                                                                 virDomainNetGetActualVirtPortProfile(net),
                                                                 VIR_NETDEV_VPORT_PROFILE_OP_CREATE));
        }
    }

624
    virObjectUnlock(vm);
625 626
}

627 628 629 630 631 632 633 634 635 636 637 638 639 640

static void
qemuDomainFindMaxID(void *payload,
                    const void *name ATTRIBUTE_UNUSED,
                    void *data)
{
    virDomainObjPtr vm = payload;
    int *driver_maxid = data;

    if (vm->def->id >= *driver_maxid)
        *driver_maxid = vm->def->id + 1;
}


641
/**
642
 * qemuStartup:
643 644 645
 *
 * Initialization function for the QEmu daemon
 */
646
static int
647 648 649 650
qemuStartup(bool privileged,
            virStateInhibitCallback callback,
            void *opaque)
{
651
    char *base;
652 653 654
    char *driverConf = NULL;
    int rc;
    virConnectPtr conn = NULL;
655
    char ebuf[1024];
656 657
    char *membase = NULL;
    char *mempath = NULL;
658

659 660
    if (VIR_ALLOC(qemu_driver) < 0)
        return -1;
661

662
    if (virMutexInit(&qemu_driver->lock) < 0) {
663
        VIR_ERROR(_("cannot initialize mutex"));
664 665
        VIR_FREE(qemu_driver);
        return -1;
666
    }
667
    qemuDriverLock(qemu_driver);
668

669
    qemu_driver->privileged = privileged;
670
    qemu_driver->uri = privileged ? "qemu:///system" : "qemu:///session";
671 672
    qemu_driver->inhibitCallback = callback;
    qemu_driver->inhibitOpaque = opaque;
673

674 675
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;
676

677 678
    if (virDomainObjListInit(&qemu_driver->domains) < 0)
        goto out_of_memory;
679

680
    /* Init domain events */
681
    qemu_driver->domainEventState = virDomainEventStateNew();
682
    if (!qemu_driver->domainEventState)
683
        goto error;
684

685 686 687
    /* read the host sysinfo */
    if (privileged)
        qemu_driver->hostsysinfo = virSysinfoRead();
688

689 690 691 692
    if (privileged) {
        if (virAsprintf(&qemu_driver->logDir,
                        "%s/log/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
693

694
        if ((qemu_driver->configBaseDir = strdup(SYSCONFDIR "/libvirt")) == NULL)
695
            goto out_of_memory;
696
        base = qemu_driver->configBaseDir;
697

698 699 700
        if (virAsprintf(&qemu_driver->stateDir,
                      "%s/run/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
701

702 703 704
        if (virAsprintf(&qemu_driver->libDir,
                      "%s/lib/libvirt/qemu", LOCALSTATEDIR) == -1)
            goto out_of_memory;
705

706 707 708 709 710 711 712 713 714 715 716 717 718
        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 {
719 720 721
        char *rundir;
        char *cachedir;

722
        cachedir = virGetUserCacheDirectory();
723
        if (!cachedir)
724
            goto error;
725

726
        if (virAsprintf(&qemu_driver->logDir,
727 728
                        "%s/qemu/log", cachedir) == -1) {
            VIR_FREE(cachedir);
729 730
            goto out_of_memory;
        }
731 732
        if (virAsprintf(&qemu_driver->cacheDir, "%s/qemu/cache", cachedir) == -1) {
            VIR_FREE(cachedir);
733 734
            goto out_of_memory;
        }
735
        VIR_FREE(cachedir);
736

737
        rundir = virGetUserRuntimeDirectory();
738 739 740 741
        if (!rundir)
            goto error;
        if (virAsprintf(&qemu_driver->stateDir, "%s/qemu/run", rundir) == -1) {
            VIR_FREE(rundir);
742
            goto out_of_memory;
743 744 745
        }
        VIR_FREE(rundir);

746
        if (!(qemu_driver->configBaseDir = virGetUserConfigDirectory()))
747
            goto error;
748
        base = qemu_driver->configBaseDir;
749 750 751 752 753 754 755 756
        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;
757
    }
H
Hu Tao 已提交
758

759
    if (virFileMakePath(qemu_driver->stateDir) < 0) {
760
        VIR_ERROR(_("Failed to create state dir '%s': %s"),
761
                  qemu_driver->stateDir, virStrerror(errno, ebuf, sizeof(ebuf)));
762
        goto error;
H
Hu Tao 已提交
763
    }
764
    if (virFileMakePath(qemu_driver->libDir) < 0) {
765
        VIR_ERROR(_("Failed to create lib dir '%s': %s"),
766
                  qemu_driver->libDir, virStrerror(errno, ebuf, sizeof(ebuf)));
767 768
        goto error;
    }
769
    if (virFileMakePath(qemu_driver->cacheDir) < 0) {
770
        VIR_ERROR(_("Failed to create cache dir '%s': %s"),
771
                  qemu_driver->cacheDir, virStrerror(errno, ebuf, sizeof(ebuf)));
772 773
        goto error;
    }
774
    if (virFileMakePath(qemu_driver->saveDir) < 0) {
775
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
776
                  qemu_driver->saveDir, virStrerror(errno, ebuf, sizeof(ebuf)));
777 778
        goto error;
    }
779
    if (virFileMakePath(qemu_driver->snapshotDir) < 0) {
780
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
781
                  qemu_driver->snapshotDir, virStrerror(errno, ebuf, sizeof(ebuf)));
782 783
        goto error;
    }
784
    if (virFileMakePath(qemu_driver->autoDumpPath) < 0) {
785
        VIR_ERROR(_("Failed to create dump dir '%s': %s"),
786
                  qemu_driver->autoDumpPath, virStrerror(errno, ebuf, sizeof(ebuf)));
787
        goto error;
788 789
    }

790 791 792 793 794 795 796
    /* 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;
797

798 799 800
    rc = virCgroupForDriver("qemu", &qemu_driver->cgroup, privileged, 1);
    if (rc < 0) {
        VIR_INFO("Unable to create cgroup for driver: %s",
801
                 virStrerror(-rc, ebuf, sizeof(ebuf)));
802 803
    }

804
    if (qemuLoadDriverConfig(qemu_driver, driverConf) < 0) {
805 806 807
        goto error;
    }
    VIR_FREE(driverConf);
808

809 810 811
    /* Allocate bitmap for remote display port reservations. We cannot
     * do this before the config is loaded properly, since the port
     * numbers are configurable now */
812 813 814 815
    if ((qemu_driver->remotePorts =
         virPortAllocatorNew(qemu_driver->remotePortMin,
                             qemu_driver->remotePortMax)) == NULL)
        goto error;
816

817 818 819 820 821 822 823 824
    /* 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;
    }

825 826
    if (qemuSecurityInit(qemu_driver) < 0)
        goto error;
827

828
    qemu_driver->capsCache = qemuCapsCacheNew(qemu_driver->libDir,
829 830 831
                                              qemu_driver->stateDir,
                                              qemu_driver->user,
                                              qemu_driver->group);
832
    if (!qemu_driver->capsCache)
833 834
        goto error;

835
    if ((qemu_driver->activePciHostdevs = pciDeviceListNew()) == NULL)
836
        goto error;
837

838 839 840
    if ((qemu_driver->activeUsbHostdevs = usbDeviceListNew()) == NULL)
        goto error;

841 842 843
    if ((qemu_driver->inactivePciHostdevs = pciDeviceListNew()) == NULL)
        goto error;

844 845 846
    if (!(qemu_driver->sharedDisks = virHashCreate(30, NULL)))
        goto error;

847 848 849 850 851 852
    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;
853
        }
854
        if (chown(qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group) < 0) {
855
            virReportSystemError(errno,
856 857 858
                                 _("unable to set ownership of '%s' to %d:%d"),
                                 qemu_driver->cacheDir, qemu_driver->user, qemu_driver->group);
            goto error;
859
        }
860 861 862 863 864 865 866 867 868 869 870
        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;
871
        }
872
    }
873

874 875 876
    if ((qemu_driver->caps = qemuCreateCapabilities(qemu_driver)) == NULL)
        goto error;

877 878 879 880 881 882
    /* 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
883
     */
884 885
    if (qemu_driver->hugetlbfs_mount &&
        qemu_driver->hugetlbfs_mount[0] == '/') {
886 887 888
        if (virAsprintf(&membase, "%s/libvirt",
                        qemu_driver->hugetlbfs_mount) < 0 ||
            virAsprintf(&mempath, "%s/qemu", membase) < 0)
889
            goto out_of_memory;
890

891 892
        if (virFileMakePath(mempath) < 0) {
            virReportSystemError(errno,
893 894
                                 _("unable to create hugepage path %s"), mempath);
            goto error;
895
        }
896 897 898 899 900 901 902 903 904 905
        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 已提交
906
        }
S
Stefan Berger 已提交
907
        VIR_FREE(membase);
E
Eric Blake 已提交
908

909
        qemu_driver->hugepage_path = mempath;
910
    }
911

912 913 914
    if (qemuDriverCloseCallbackInit(qemu_driver) < 0)
        goto error;

915 916 917 918 919
    /* Get all the running persistent or transient configs first */
    if (virDomainLoadAllConfigs(qemu_driver->caps,
                                &qemu_driver->domains,
                                qemu_driver->stateDir,
                                NULL,
M
Matthias Bolte 已提交
920 921
                                1, QEMU_EXPECTED_VIRT_TYPES,
                                NULL, NULL) < 0)
922
        goto error;
923

924 925 926 927 928 929 930
    /* find the maximum ID from active and transient configs to initialize
     * the driver with. This is to avoid race between autostart and reconnect
     * threads */
    virHashForEach(qemu_driver->domains.objs,
                   qemuDomainFindMaxID,
                   &qemu_driver->nextvmid);

931 932
    virHashForEach(qemu_driver->domains.objs, qemuDomainNetsRestart, NULL);

933
    conn = virConnectOpen(qemu_driver->uri);
934

935
    qemuProcessReconnectAll(conn, qemu_driver);
936

937 938 939 940 941
    /* Then inactive persistent configs */
    if (virDomainLoadAllConfigs(qemu_driver->caps,
                                &qemu_driver->domains,
                                qemu_driver->configDir,
                                qemu_driver->autostartDir,
M
Matthias Bolte 已提交
942 943
                                0, QEMU_EXPECTED_VIRT_TYPES,
                                NULL, NULL) < 0)
944
        goto error;
945

946

947 948
    virHashForEach(qemu_driver->domains.objs, qemuDomainSnapshotLoad,
                   qemu_driver->snapshotDir);
949

950 951 952
    virHashForEach(qemu_driver->domains.objs, qemuDomainManagedSaveLoad,
                   qemu_driver);

953
    qemu_driver->workerPool = virThreadPoolNew(0, 1, 0, processWatchdogEvent, qemu_driver);
954 955
    if (!qemu_driver->workerPool)
        goto error;
956

957 958 959 960
    qemuDriverUnlock(qemu_driver);

    qemuAutostartDomains(qemu_driver);

961 962
    if (conn)
        virConnectClose(conn);
963

964
    virNWFilterRegisterCallbackDriver(&qemuCallbackDriver);
965
    return 0;
966

967 968 969 970 971 972 973 974
out_of_memory:
    virReportOOMError();
error:
    if (qemu_driver)
        qemuDriverUnlock(qemu_driver);
    if (conn)
        virConnectClose(conn);
    VIR_FREE(driverConf);
975 976
    VIR_FREE(membase);
    VIR_FREE(mempath);
977
    qemuShutdown();
978
    return -1;
979 980
}

981
static void qemuNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
982
{
983
    virQEMUDriverPtr driver = opaque;
984

985 986 987 988 989 990 991
    if (newVM) {
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
E
Eric Blake 已提交
992
    }
993
}
E
Eric Blake 已提交
994

995
/**
996
 * qemuReload:
997 998 999 1000 1001
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
1002
qemuReload(void) {
1003 1004
    if (!qemu_driver)
        return 0;
1005

1006 1007 1008 1009 1010
    qemuDriverLock(qemu_driver);
    virDomainLoadAllConfigs(qemu_driver->caps,
                            &qemu_driver->domains,
                            qemu_driver->configDir,
                            qemu_driver->autostartDir,
M
Matthias Bolte 已提交
1011
                            0, QEMU_EXPECTED_VIRT_TYPES,
1012
                            qemuNotifyLoadDomain, qemu_driver);
1013
    qemuDriverUnlock(qemu_driver);
1014

1015 1016
    return 0;
}
S
Stefan Berger 已提交
1017

1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085

/*
 * qemuStop:
 *
 * Save any VMs in preparation for shutdown
 *
 */
static int
qemuStop(void) {
    int ret = -1;
    const char *uri;
    virConnectPtr conn;
    int numDomains;
    size_t i;
    int state;
    virDomainPtr *domains = NULL;
    unsigned int *flags = NULL;

    qemuDriverLock(qemu_driver);
    uri = qemu_driver->privileged ?
        "qemu:///system" :
        "qemu:///session";
    qemuDriverUnlock(qemu_driver);

    if (!(conn = virConnectOpen(uri)))
        return -1;

    if ((numDomains = virConnectListAllDomains(conn,
                                               &domains,
                                               VIR_CONNECT_LIST_DOMAINS_ACTIVE)) < 0)
        goto cleanup;

    if (VIR_ALLOC_N(flags, numDomains) < 0) {
        virReportOOMError();
        goto cleanup;
    }

    /* First we pause all VMs to make them stop dirtying
       pages, etc. We remember if any VMs were paused so
       we can restore that on resume. */
    for (i = 0 ; i < numDomains ; i++) {
        flags[i] = VIR_DOMAIN_SAVE_RUNNING;
        if (virDomainGetState(domains[i], &state, NULL, 0) == 0) {
            if (state == VIR_DOMAIN_PAUSED) {
                flags[i] = VIR_DOMAIN_SAVE_PAUSED;
            }
        }
        virDomainSuspend(domains[i]);
    }

    ret = 0;
    /* Then we save the VMs to disk */
    for (i = 0 ; i < numDomains ; i++)
        if (virDomainManagedSave(domains[i], flags[i]) < 0)
            ret = -1;

    VIR_FREE(domains);
    VIR_FREE(flags);

 cleanup:
    for (i = 0 ; i < numDomains ; i++)
        virDomainFree(domains[i]);
    VIR_FREE(domains);
    VIR_FREE(flags);

    return ret;
}

1086
/**
1087
 * qemuShutdown:
1088 1089 1090 1091
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
1092
qemuShutdown(void) {
1093
    int i;
1094

1095 1096
    if (!qemu_driver)
        return -1;
1097

1098
    qemuDriverLock(qemu_driver);
1099
    virNWFilterUnRegisterCallbackDriver(&qemuCallbackDriver);
1100
    pciDeviceListFree(qemu_driver->activePciHostdevs);
1101
    pciDeviceListFree(qemu_driver->inactivePciHostdevs);
1102
    usbDeviceListFree(qemu_driver->activeUsbHostdevs);
1103
    virHashFree(qemu_driver->sharedDisks);
1104
    virCapabilitiesFree(qemu_driver->caps);
1105
    qemuCapsCacheFree(qemu_driver->capsCache);
1106

1107
    virDomainObjListDeinit(&qemu_driver->domains);
1108
    virObjectUnref(qemu_driver->remotePorts);
1109

1110
    virSysinfoDefFree(qemu_driver->hostsysinfo);
1111

1112
    qemuDriverCloseCallbackShutdown(qemu_driver);
1113

1114
    VIR_FREE(qemu_driver->configBaseDir);
1115 1116 1117 1118 1119 1120 1121 1122
    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 已提交
1123
    VIR_FREE(qemu_driver->qemuImgBinary);
1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
    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);
1136

1137 1138
    for (i = 0 ; (qemu_driver->securityDriverNames != NULL &&
                  qemu_driver->securityDriverNames[i] != NULL) ; i++)
1139 1140
        VIR_FREE(qemu_driver->securityDriverNames[i]);
    VIR_FREE(qemu_driver->securityDriverNames);
1141
    virSecurityManagerFree(qemu_driver->securityManager);
1142

1143
    ebtablesContextFree(qemu_driver->ebtables);
1144

1145 1146 1147 1148
    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 已提交
1149 1150
    }

1151
    /* Free domain callback list */
1152
    virDomainEventStateFree(qemu_driver->domainEventState);
D
Daniel P. Berrange 已提交
1153

1154
    virCgroupFree(&qemu_driver->cgroup);
1155

1156 1157
    virLockManagerPluginUnref(qemu_driver->lockManager);

1158 1159 1160 1161
    qemuDriverUnlock(qemu_driver);
    virMutexDestroy(&qemu_driver->lock);
    virThreadPoolFree(qemu_driver->workerPool);
    VIR_FREE(qemu_driver);
1162

1163
    return 0;
1164 1165
}

1166

1167 1168 1169
static virDrvOpenStatus qemuOpen(virConnectPtr conn,
                                 virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                 unsigned int flags)
1170
{
E
Eric Blake 已提交
1171 1172
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1173
    if (conn->uri == NULL) {
1174 1175 1176
        if (qemu_driver == NULL)
            return VIR_DRV_OPEN_DECLINED;

1177 1178 1179
        if (!(conn->uri = virURIParse(qemu_driver->privileged ?
                                      "qemu:///system" :
                                      "qemu:///session")))
1180
            return VIR_DRV_OPEN_ERROR;
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
    } 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;

1191
        if (qemu_driver == NULL) {
1192 1193
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("qemu state driver is not active"));
1194 1195 1196
            return VIR_DRV_OPEN_ERROR;
        }

1197
        if (conn->uri->path == NULL) {
1198 1199 1200 1201 1202
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no QEMU URI path given, try %s"),
                           qemu_driver->privileged
                           ? "qemu:///system"
                           : "qemu:///session");
1203 1204 1205
                return VIR_DRV_OPEN_ERROR;
        }

1206
        if (qemu_driver->privileged) {
1207 1208
            if (STRNEQ(conn->uri->path, "/system") &&
                STRNEQ(conn->uri->path, "/session")) {
1209 1210 1211
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected QEMU URI path '%s', try qemu:///system"),
                               conn->uri->path);
1212 1213 1214
                return VIR_DRV_OPEN_ERROR;
            }
        } else {
1215
            if (STRNEQ(conn->uri->path, "/session")) {
1216 1217 1218
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected QEMU URI path '%s', try qemu:///session"),
                               conn->uri->path);
1219 1220 1221
                return VIR_DRV_OPEN_ERROR;
            }
        }
1222 1223 1224 1225 1226 1227
    }
    conn->privateData = qemu_driver;

    return VIR_DRV_OPEN_SUCCESS;
}

1228
static int qemuClose(virConnectPtr conn) {
1229
    virQEMUDriverPtr driver = conn->privateData;
1230 1231

    /* Get rid of callbacks registered for this conn */
1232
    qemuDriverLock(driver);
1233
    qemuDriverCloseCallbackRunAll(driver, conn);
1234
    qemuDriverUnlock(driver);
1235 1236 1237 1238 1239 1240

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
1241 1242
/* Which features are supported by this driver? */
static int
1243
qemuSupportsFeature(virConnectPtr conn ATTRIBUTE_UNUSED, int feature)
D
Daniel Veillard 已提交
1244 1245
{
    switch (feature) {
1246
    case VIR_DRV_FEATURE_MIGRATION_V2:
1247
    case VIR_DRV_FEATURE_MIGRATION_V3:
1248
    case VIR_DRV_FEATURE_MIGRATION_P2P:
1249
    case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
1250
    case VIR_DRV_FEATURE_FD_PASSING:
1251
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
1252
    case VIR_DRV_FEATURE_XML_MIGRATABLE:
L
liguang 已提交
1253
    case VIR_DRV_FEATURE_MIGRATION_OFFLINE:
1254 1255 1256
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
1257 1258 1259
    }
}

1260
static const char *qemuGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
1261
    return "QEMU";
1262 1263
}

1264

1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
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;
}

1277 1278 1279 1280 1281
static int qemuIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
{
    return 1;
}

1282

1283 1284 1285 1286
static int kvmGetMaxVCPUs(void) {
    int maxvcpus = 1;

    int r, fd;
1287

1288 1289
    fd = open(KVM_DEVICE, O_RDONLY);
    if (fd < 0) {
1290
        virReportSystemError(errno, _("Unable to open %s"), KVM_DEVICE);
1291
        return -1;
1292 1293 1294 1295 1296 1297
    }

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

1298
    VIR_FORCE_CLOSE(fd);
1299 1300 1301 1302
    return maxvcpus;
}


E
Eric Blake 已提交
1303 1304 1305
static char *
qemuGetSysinfo(virConnectPtr conn, unsigned int flags)
{
1306
    virQEMUDriverPtr driver = conn->privateData;
1307
    virBuffer buf = VIR_BUFFER_INITIALIZER;
E
Eric Blake 已提交
1308 1309 1310 1311

    virCheckFlags(0, NULL);

    if (!driver->hostsysinfo) {
1312 1313
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Host SMBIOS information is not available"));
E
Eric Blake 已提交
1314 1315 1316
        return NULL;
    }

1317 1318 1319 1320 1321 1322 1323
    if (virSysinfoFormat(&buf, driver->hostsysinfo) < 0)
        return NULL;
    if (virBufferError(&buf)) {
        virReportOOMError();
        return NULL;
    }
    return virBufferContentAndReset(&buf);
E
Eric Blake 已提交
1324 1325
}

1326
static int qemuGetMaxVCPUs(virConnectPtr conn ATTRIBUTE_UNUSED, const char *type) {
1327 1328 1329
    if (!type)
        return 16;

1330
    if (STRCASEEQ(type, "qemu"))
1331 1332
        return 16;

1333
    if (STRCASEEQ(type, "kvm"))
1334
        return kvmGetMaxVCPUs();
1335

1336
    if (STRCASEEQ(type, "kqemu"))
1337
        return 1;
1338

1339 1340
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unknown type '%s'"), type);
1341 1342 1343
    return -1;
}

1344

1345
static char *qemuGetCapabilities(virConnectPtr conn) {
1346
    virQEMUDriverPtr driver = conn->privateData;
1347
    virCapsPtr caps = NULL;
1348
    char *xml = NULL;
1349

1350
    qemuDriverLock(driver);
1351

1352
    if ((caps = qemuCreateCapabilities(qemu_driver)) == NULL) {
1353 1354 1355
        virCapabilitiesFree(caps);
        goto cleanup;
    }
1356

1357
    virCapabilitiesFree(qemu_driver->caps);
1358 1359 1360
    qemu_driver->caps = caps;

    if ((xml = virCapabilitiesFormatXML(driver->caps)) == NULL)
1361
        virReportOOMError();
1362 1363

cleanup:
1364
    qemuDriverUnlock(driver);
1365

1366
    return xml;
1367 1368 1369
}


1370
static int
1371 1372
qemuGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss,
                   pid_t pid, int tid)
1373 1374
{
    char *proc;
D
Daniel P. Berrange 已提交
1375
    FILE *pidinfo;
1376
    unsigned long long usertime, systime;
1377
    long rss;
1378 1379
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
1380

1381 1382
    /* In general, we cannot assume pid_t fits in int; but /proc parsing
     * is specific to Linux where int works fine.  */
1383
    if (tid)
1384
        ret = virAsprintf(&proc, "/proc/%d/task/%d/stat", (int) pid, tid);
1385
    else
1386
        ret = virAsprintf(&proc, "/proc/%d/stat", (int) pid);
1387
    if (ret < 0)
D
Daniel P. Berrange 已提交
1388 1389 1390 1391
        return -1;

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
1392 1393 1394 1395
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
1396 1397
        if (vm_rss)
            *vm_rss = 0;
1398
        VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1399 1400
        return 0;
    }
1401
    VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1402

1403 1404 1405 1406 1407 1408
    /* 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 */
1409
               "%*d %*d %*d %*d %*d %*d %*u %*u %ld %*u %*u %*u"
1410 1411
               /* startstack -> processor */
               "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
1412
               &usertime, &systime, &rss, &cpu) != 4) {
1413
        VIR_FORCE_FCLOSE(pidinfo);
1414
        VIR_WARN("cannot parse process status data");
1415
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
1416 1417 1418 1419 1420 1421 1422 1423
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
1424 1425 1426 1427 1428
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

1429 1430 1431 1432 1433 1434
    /* 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 已提交
1435

1436 1437

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

1440
    VIR_FORCE_FCLOSE(pidinfo);
D
Daniel P. Berrange 已提交
1441 1442 1443 1444 1445

    return 0;
}


1446 1447
static virDomainPtr qemuDomainLookupByID(virConnectPtr conn,
                                         int id) {
1448
    virQEMUDriverPtr driver = conn->privateData;
1449 1450 1451
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

1452
    qemuDriverLock(driver);
1453
    vm  = virDomainFindByID(&driver->domains, id);
1454
    qemuDriverUnlock(driver);
1455 1456

    if (!vm) {
1457 1458
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), id);
1459
        goto cleanup;
1460 1461
    }

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

cleanup:
1466
    if (vm)
1467
        virObjectUnlock(vm);
1468 1469
    return dom;
}
1470

1471 1472
static virDomainPtr qemuDomainLookupByUUID(virConnectPtr conn,
                                           const unsigned char *uuid) {
1473
    virQEMUDriverPtr driver = conn->privateData;
1474 1475
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1476

1477
    qemuDriverLock(driver);
1478
    vm = virDomainFindByUUID(&driver->domains, uuid);
1479 1480
    qemuDriverUnlock(driver);

1481
    if (!vm) {
1482 1483
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
1484 1485
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1486
        goto cleanup;
1487 1488
    }

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

cleanup:
1493
    if (vm)
1494
        virObjectUnlock(vm);
1495 1496
    return dom;
}
1497

1498 1499
static virDomainPtr qemuDomainLookupByName(virConnectPtr conn,
                                           const char *name) {
1500
    virQEMUDriverPtr driver = conn->privateData;
1501 1502
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1503

1504
    qemuDriverLock(driver);
1505
    vm = virDomainFindByName(&driver->domains, name);
1506 1507
    qemuDriverUnlock(driver);

1508
    if (!vm) {
1509 1510
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), name);
1511
        goto cleanup;
1512 1513
    }

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

cleanup:
1518
    if (vm)
1519
        virObjectUnlock(vm);
1520 1521 1522
    return dom;
}

1523 1524 1525 1526 1527 1528

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

1529
    if (!(obj = qemuDomObjFromDomain(dom)))
1530
        goto cleanup;
1531

1532 1533 1534 1535
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
1536
        virObjectUnlock(obj);
1537 1538 1539 1540 1541 1542 1543 1544
    return ret;
}

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

1545
    if (!(obj = qemuDomObjFromDomain(dom)))
1546
        goto cleanup;
1547

1548 1549 1550 1551
    ret = obj->persistent;

cleanup:
    if (obj)
1552
        virObjectUnlock(obj);
1553 1554 1555
    return ret;
}

1556 1557 1558 1559 1560
static int qemuDomainIsUpdated(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

1561
    if (!(obj = qemuDomObjFromDomain(dom)))
1562
        goto cleanup;
1563

1564 1565 1566 1567
    ret = obj->updated;

cleanup:
    if (obj)
1568
        virObjectUnlock(obj);
1569 1570
    return ret;
}
1571

1572
static int qemuGetVersion(virConnectPtr conn, unsigned long *version) {
1573
    virQEMUDriverPtr driver = conn->privateData;
1574 1575
    int ret = -1;

1576
    qemuDriverLock(driver);
1577 1578 1579
    if (qemuCapsGetDefaultVersion(driver->caps,
                                  driver->capsCache,
                                  &driver->qemuVersion) < 0)
1580
        goto cleanup;
1581

1582
    *version = driver->qemuVersion;
1583 1584 1585
    ret = 0;

cleanup:
1586
    qemuDriverUnlock(driver);
1587
    return ret;
D
Daniel P. Berrange 已提交
1588 1589
}

1590
static int qemuListDomains(virConnectPtr conn, int *ids, int nids) {
1591
    virQEMUDriverPtr driver = conn->privateData;
1592
    int n;
1593

1594
    qemuDriverLock(driver);
1595
    n = virDomainObjListGetActiveIDs(&driver->domains, ids, nids);
1596
    qemuDriverUnlock(driver);
1597

1598
    return n;
D
Daniel P. Berrange 已提交
1599
}
1600

1601
static int qemuNumDomains(virConnectPtr conn) {
1602
    virQEMUDriverPtr driver = conn->privateData;
1603
    int n;
1604

1605
    qemuDriverLock(driver);
1606
    n = virDomainObjListNumOfDomains(&driver->domains, 1);
1607
    qemuDriverUnlock(driver);
1608

1609
    return n;
D
Daniel P. Berrange 已提交
1610
}
1611

1612 1613 1614 1615

static int
qemuCanonicalizeMachine(virDomainDefPtr def, qemuCapsPtr caps)
{
1616
    const char *canon;
1617

1618 1619 1620 1621
    if (!(canon = qemuCapsGetCanonicalMachine(caps, def->os.machine)))
        return 0;

    if (STRNEQ(canon, def->os.machine)) {
1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634
        char *tmp;
        if (!(tmp = strdup(canon))) {
            virReportOOMError();
            return -1;
        }
        VIR_FREE(def->os.machine);
        def->os.machine = tmp;
    }

    return 0;
}


1635 1636
static virDomainPtr qemuDomainCreate(virConnectPtr conn, const char *xml,
                                     unsigned int flags) {
1637
    virQEMUDriverPtr driver = conn->privateData;
1638
    virDomainDefPtr def;
1639
    virDomainObjPtr vm = NULL;
1640
    virDomainPtr dom = NULL;
1641
    virDomainEventPtr event = NULL;
1642
    virDomainEventPtr event2 = NULL;
1643
    unsigned int start_flags = VIR_QEMU_PROCESS_START_COLD;
1644
    qemuCapsPtr caps = NULL;
D
Daniel P. Berrange 已提交
1645

1646 1647
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
                  VIR_DOMAIN_START_AUTODESTROY, NULL);
1648

1649 1650 1651 1652 1653
    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;

1654
    qemuDriverLock(driver);
1655
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
1656
                                        QEMU_EXPECTED_VIRT_TYPES,
1657
                                        VIR_DOMAIN_XML_INACTIVE)))
1658
        goto cleanup;
1659

1660
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
1661 1662
        goto cleanup;

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

1666 1667 1668
    if (!(caps = qemuCapsCacheLookup(driver->capsCache, def->emulator)))
        goto cleanup;

1669
    if (qemuCanonicalizeMachine(def, caps) < 0)
1670 1671
        goto cleanup;

1672
    if (qemuDomainAssignAddresses(def, caps, NULL) < 0)
1673 1674
        goto cleanup;

1675
    if (!(vm = virDomainAssignDef(driver->caps,
1676
                                  &driver->domains,
1677
                                  def, false)))
1678 1679 1680
        goto cleanup;

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

1682
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
1683 1684
        goto cleanup; /* XXXX free the 'vm' we created ? */

1685 1686 1687
    if (qemuProcessStart(conn, driver, vm, NULL, -1, NULL, NULL,
                         VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                         start_flags) < 0) {
1688
        virDomainAuditStart(vm, "booted", false);
1689
        if (qemuDomainObjEndJob(driver, vm) > 0)
1690
            qemuDomainRemoveInactive(driver, vm);
1691
        vm = NULL;
1692
        goto cleanup;
D
Daniel P. Berrange 已提交
1693
    }
1694 1695 1696 1697

    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1698 1699 1700 1701 1702 1703 1704 1705 1706 1707
    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);
    }
1708
    virDomainAuditStart(vm, "booted", true);
D
Daniel P. Berrange 已提交
1709

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

1713
    if (vm &&
1714
        qemuDomainObjEndJob(driver, vm) == 0)
1715
        vm = NULL;
1716

1717 1718
cleanup:
    virDomainDefFree(def);
1719
    if (vm)
1720
        virObjectUnlock(vm);
1721
    if (event) {
1722
        qemuDomainEventQueue(driver, event);
1723 1724 1725
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
1726
    virObjectUnref(caps);
1727
    qemuDriverUnlock(driver);
1728
    return dom;
D
Daniel P. Berrange 已提交
1729 1730 1731
}


1732
static int qemuDomainSuspend(virDomainPtr dom) {
1733
    virQEMUDriverPtr driver = dom->conn->privateData;
1734 1735
    virDomainObjPtr vm;
    int ret = -1;
1736
    virDomainEventPtr event = NULL;
1737
    qemuDomainObjPrivatePtr priv;
1738 1739
    virDomainPausedReason reason;
    int eventDetail;
1740
    int state;
1741

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

D
Daniel P. Berrange 已提交
1745
    if (!vm) {
1746 1747
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1748 1749
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1750
        goto cleanup;
D
Daniel P. Berrange 已提交
1751
    }
D
Daniel P. Berrange 已提交
1752
    if (!virDomainObjIsActive(vm)) {
1753 1754
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1755
        goto cleanup;
D
Daniel P. Berrange 已提交
1756
    }
1757 1758 1759

    priv = vm->privateData;

1760 1761 1762 1763
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_SUSPEND) < 0)
        goto cleanup;

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

1769 1770 1771
    if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) {
        reason = VIR_DOMAIN_PAUSED_MIGRATION;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED;
1772 1773 1774
    } else if (priv->job.asyncJob == QEMU_ASYNC_JOB_SNAPSHOT) {
        reason = VIR_DOMAIN_PAUSED_SNAPSHOT;
        eventDetail = -1; /* don't create lifecycle events when doing snapshot */
1775 1776 1777 1778 1779
    } else {
        reason = VIR_DOMAIN_PAUSED_USER;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED;
    }

1780 1781 1782 1783 1784 1785
    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) {
1786
        if (qemuProcessStopCPUs(driver, vm, reason, QEMU_ASYNC_JOB_NONE) < 0) {
1787
            goto endjob;
1788
        }
1789 1790 1791 1792 1793 1794

        if (eventDetail >= 0) {
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             eventDetail);
        }
D
Daniel P. Berrange 已提交
1795
    }
1796 1797 1798
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
        goto endjob;
    ret = 0;
1799

1800
endjob:
1801
    if (qemuDomainObjEndJob(driver, vm) == 0)
1802
        vm = NULL;
1803

1804
cleanup:
1805
    if (vm)
1806
        virObjectUnlock(vm);
1807

1808
    if (event)
1809
        qemuDomainEventQueue(driver, event);
1810
    qemuDriverUnlock(driver);
1811
    return ret;
D
Daniel P. Berrange 已提交
1812 1813 1814
}


1815
static int qemuDomainResume(virDomainPtr dom) {
1816
    virQEMUDriverPtr driver = dom->conn->privateData;
1817 1818
    virDomainObjPtr vm;
    int ret = -1;
1819
    virDomainEventPtr event = NULL;
1820
    int state;
1821

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

D
Daniel P. Berrange 已提交
1825
    if (!vm) {
1826 1827
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
1828 1829
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1830
        goto cleanup;
D
Daniel P. Berrange 已提交
1831
    }
1832

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

D
Daniel P. Berrange 已提交
1836
    if (!virDomainObjIsActive(vm)) {
1837 1838
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1839
        goto endjob;
D
Daniel P. Berrange 已提交
1840
    }
1841 1842 1843 1844 1845 1846 1847

    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 已提交
1848
        if (qemuProcessStartCPUs(driver, vm, dom->conn,
1849 1850
                                 VIR_DOMAIN_RUNNING_UNPAUSED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
1851
            if (virGetLastError() == NULL)
1852 1853
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("resume operation failed"));
1854
            goto endjob;
1855
        }
1856 1857 1858
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
1859
    }
1860
    if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0)
1861
        goto endjob;
1862 1863
    ret = 0;

1864
endjob:
1865
    if (qemuDomainObjEndJob(driver, vm) == 0)
1866
        vm = NULL;
1867

1868
cleanup:
1869
    if (vm)
1870
        virObjectUnlock(vm);
1871
    if (event)
1872
        qemuDomainEventQueue(driver, event);
1873
    qemuDriverUnlock(driver);
1874
    return ret;
D
Daniel P. Berrange 已提交
1875 1876
}

1877
static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags) {
1878
    virQEMUDriverPtr driver = dom->conn->privateData;
1879 1880
    virDomainObjPtr vm;
    int ret = -1;
1881
    qemuDomainObjPrivatePtr priv;
1882 1883 1884 1885
    bool useAgent = false;

    virCheckFlags(VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN |
                  VIR_DOMAIN_SHUTDOWN_GUEST_AGENT, -1);
1886

1887 1888 1889 1890 1891 1892 1893 1894
    /* At most one of these two flags should be set.  */
    if ((flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN) &&
        (flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT)) {
        virReportInvalidArg(flags, "%s",
                            _("flags for acpi power button and guest agent are mutually exclusive"));
        return -1;
    }

1895
    if (!(vm = qemuDomObjFromDomain(dom)))
1896
        goto cleanup;
1897

1898 1899 1900 1901 1902 1903 1904 1905 1906
    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) {
1907 1908 1909
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                           _("QEMU guest agent is not "
                             "available due to an error"));
1910
            goto cleanup;
1911 1912
        }
        if (!priv->agent) {
1913 1914
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
1915
            goto cleanup;
1916 1917 1918
        }
    }

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

D
Daniel P. Berrange 已提交
1922
    if (!virDomainObjIsActive(vm)) {
1923 1924
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1925
        goto endjob;
1926 1927
    }

1928 1929 1930 1931 1932 1933
    if (useAgent) {
        qemuDomainObjEnterAgent(driver, vm);
        ret = qemuAgentShutdown(priv->agent, QEMU_AGENT_SHUTDOWN_POWERDOWN);
        qemuDomainObjExitAgent(driver, vm);
    } else {
        qemuDomainSetFakeReboot(driver, vm, false);
1934

1935 1936 1937 1938
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSystemPowerdown(priv->mon);
        qemuDomainObjExitMonitor(driver, vm);
    }
1939

1940
endjob:
1941
    if (qemuDomainObjEndJob(driver, vm) == 0)
1942
        vm = NULL;
1943

1944
cleanup:
1945
    if (vm)
1946
        virObjectUnlock(vm);
1947
    return ret;
1948 1949
}

1950 1951
static int qemuDomainShutdown(virDomainPtr dom)
{
1952 1953 1954
    return qemuDomainShutdownFlags(dom, 0);
}

1955

1956 1957 1958
static int
qemuDomainReboot(virDomainPtr dom, unsigned int flags)
{
1959
    virQEMUDriverPtr driver = dom->conn->privateData;
1960 1961 1962
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
1963
    bool useAgent = false;
1964

1965 1966
    virCheckFlags(VIR_DOMAIN_REBOOT_ACPI_POWER_BTN |
                  VIR_DOMAIN_REBOOT_GUEST_AGENT , -1);
1967

1968 1969 1970 1971 1972 1973 1974 1975
    /* At most one of these two flags should be set.  */
    if ((flags & VIR_DOMAIN_REBOOT_ACPI_POWER_BTN) &&
        (flags & VIR_DOMAIN_REBOOT_GUEST_AGENT)) {
        virReportInvalidArg(flags, "%s",
                            _("flags for acpi power button and guest agent are mutually exclusive"));
        return -1;
    }

1976
    if (!(vm = qemuDomObjFromDomain(dom)))
1977 1978
        goto cleanup;

1979 1980
    priv = vm->privateData;

1981 1982
    if ((flags & VIR_DOMAIN_REBOOT_GUEST_AGENT) ||
        (!(flags & VIR_DOMAIN_REBOOT_ACPI_POWER_BTN) &&
1983 1984 1985 1986 1987
         priv->agent))
        useAgent = true;

    if (useAgent) {
        if (priv->agentError) {
1988 1989 1990
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                           _("QEMU guest agent is not "
                             "available due to an error"));
1991 1992 1993
            goto cleanup;
        }
        if (!priv->agent) {
1994 1995
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
1996 1997 1998
            goto cleanup;
        }
    } else {
1999
#if WITH_YAJL
2000 2001
        if (qemuCapsGet(priv->caps, QEMU_CAPS_MONITOR_JSON)) {
            if (!qemuCapsGet(priv->caps, QEMU_CAPS_NO_SHUTDOWN)) {
2002 2003
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Reboot is not supported with this QEMU binary"));
2004 2005 2006 2007
                goto cleanup;
            }
        } else {
#endif
2008 2009
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Reboot is not supported without the JSON monitor"));
2010
            goto cleanup;
2011
#if WITH_YAJL
2012
        }
2013 2014
#endif
    }
2015

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

2019
    if (!virDomainObjIsActive(vm)) {
2020 2021
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2022 2023
        goto endjob;
    }
2024

2025 2026 2027 2028 2029
    if (useAgent) {
        qemuDomainObjEnterAgent(driver, vm);
        ret = qemuAgentShutdown(priv->agent, QEMU_AGENT_SHUTDOWN_REBOOT);
        qemuDomainObjExitAgent(driver, vm);
    } else {
2030
        qemuDomainObjEnterMonitor(driver, vm);
2031
        ret = qemuMonitorSystemPowerdown(priv->mon);
2032
        qemuDomainObjExitMonitor(driver, vm);
2033

2034 2035
        if (ret == 0)
            qemuDomainSetFakeReboot(driver, vm, true);
2036 2037
    }

2038 2039 2040 2041
endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

2042 2043
cleanup:
    if (vm)
2044
        virObjectUnlock(vm);
2045 2046 2047 2048
    return ret;
}


2049 2050 2051
static int
qemuDomainReset(virDomainPtr dom, unsigned int flags)
{
2052
    virQEMUDriverPtr driver = dom->conn->privateData;
2053 2054 2055 2056 2057 2058
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2059
    if (!(vm = qemuDomObjFromDomain(dom)))
2060 2061 2062 2063 2064 2065
        goto cleanup;

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

    if (!virDomainObjIsActive(vm)) {
2066 2067
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083
        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)
2084
        virObjectUnlock(vm);
2085 2086 2087 2088
    return ret;
}


2089
/* Count how many snapshots in a set are external snapshots or checkpoints.  */
2090 2091 2092 2093 2094 2095 2096 2097
static void
qemuDomainSnapshotCountExternal(void *payload,
                                const void *name ATTRIBUTE_UNUSED,
                                void *data)
{
    virDomainSnapshotObjPtr snap = payload;
    int *count = data;

2098
    if (virDomainSnapshotIsExternal(snap))
2099 2100 2101
        (*count)++;
}

2102 2103 2104 2105
static int
qemuDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
{
2106
    virQEMUDriverPtr driver = dom->conn->privateData;
2107 2108
    virDomainObjPtr vm;
    int ret = -1;
2109
    virDomainEventPtr event = NULL;
2110
    qemuDomainObjPrivatePtr priv;
2111

2112
    virCheckFlags(VIR_DOMAIN_DESTROY_GRACEFUL, -1);
2113

2114
    qemuDriverLock(driver);
2115
    vm  = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel P. Berrange 已提交
2116
    if (!vm) {
2117 2118
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
2119 2120
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2121
        goto cleanup;
D
Daniel P. Berrange 已提交
2122
    }
2123

2124 2125
    priv = vm->privateData;

2126
    qemuDomainSetFakeReboot(driver, vm, false);
2127

2128 2129 2130 2131 2132 2133

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

2134 2135 2136 2137 2138
    /* 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
     */
2139
    if (flags & VIR_DOMAIN_DESTROY_GRACEFUL) {
2140 2141
        if (qemuProcessKill(driver, vm, 0) < 0) {
            priv->beingDestroyed = false;
2142
            goto cleanup;
2143
        }
2144
    } else {
2145 2146
        if (qemuProcessKill(driver, vm, VIR_QEMU_PROCESS_KILL_FORCE) < 0) {
            priv->beingDestroyed = false;
2147
            goto cleanup;
2148
        }
2149
    }
2150

2151
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_DESTROY) < 0)
2152 2153
        goto cleanup;

2154 2155
    priv->beingDestroyed = false;

D
Daniel P. Berrange 已提交
2156
    if (!virDomainObjIsActive(vm)) {
2157 2158
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2159
        goto endjob;
2160
    }
2161

2162
    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED, 0);
2163 2164 2165
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
2166
    virDomainAuditStop(vm, "destroyed");
2167

2168
    if (!vm->persistent) {
2169
        if (qemuDomainObjEndJob(driver, vm) > 0)
2170
            qemuDomainRemoveInactive(driver, vm);
2171 2172
        vm = NULL;
    }
2173 2174
    ret = 0;

2175
endjob:
2176
    if (vm &&
2177
        qemuDomainObjEndJob(driver, vm) == 0)
2178
        vm = NULL;
2179

2180
cleanup:
2181
    if (vm)
2182
        virObjectUnlock(vm);
2183 2184
    if (event)
        qemuDomainEventQueue(driver, event);
2185
    qemuDriverUnlock(driver);
2186
    return ret;
D
Daniel P. Berrange 已提交
2187 2188
}

2189 2190 2191 2192 2193
static int
qemuDomainDestroy(virDomainPtr dom)
{
    return qemuDomainDestroyFlags(dom, 0);
}
D
Daniel P. Berrange 已提交
2194

2195
static char *qemuDomainGetOSType(virDomainPtr dom) {
2196 2197
    virDomainObjPtr vm;
    char *type = NULL;
2198

2199
    if (!(vm = qemuDomObjFromDomain(dom)))
2200
        goto cleanup;
2201

2202
    if (!(type = strdup(vm->def->os.type)))
2203
        virReportOOMError();
2204 2205

cleanup:
2206
    if (vm)
2207
        virObjectUnlock(vm);
2208 2209 2210
    return type;
}

2211
/* Returns max memory in kb, 0 if error */
2212 2213 2214
static unsigned long long
qemuDomainGetMaxMemory(virDomainPtr dom)
{
2215
    virDomainObjPtr vm;
2216
    unsigned long long ret = 0;
2217

2218
    if (!(vm = qemuDomObjFromDomain(dom)))
2219
        goto cleanup;
2220

2221
    ret = vm->def->mem.max_balloon;
2222 2223

cleanup:
2224
    if (vm)
2225
        virObjectUnlock(vm);
2226
    return ret;
2227 2228
}

2229 2230
static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
                                    unsigned int flags) {
2231
    virQEMUDriverPtr driver = dom->conn->privateData;
2232
    qemuDomainObjPrivatePtr priv;
2233
    virDomainObjPtr vm;
2234
    virDomainDefPtr persistentDef = NULL;
2235
    int ret = -1, r;
2236

2237 2238
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
2239
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
2240

2241
    if (!(vm = qemuDomObjFromDomain(dom)))
2242
        goto cleanup;
2243

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

2247 2248
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
2249
        goto endjob;
2250

2251 2252 2253
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
        /* resize the maximum memory */

2254
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2255 2256 2257
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot resize the maximum memory on an "
                             "active domain"));
2258
            goto endjob;
2259
        }
2260

2261
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
2262 2263
            /* Help clang 2.8 decipher the logic flow.  */
            sa_assert(persistentDef);
2264 2265 2266 2267
            persistentDef->mem.max_balloon = newmem;
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
            ret = virDomainSaveConfig(driver->configDir, persistentDef);
2268 2269 2270
            goto endjob;
        }

2271 2272 2273 2274
    } else {
        /* resize the current memory */

        if (newmem > vm->def->mem.max_balloon) {
2275 2276
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("cannot set memory higher than max memory"));
2277 2278 2279
            goto endjob;
        }

2280
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2281
            priv = vm->privateData;
2282
            qemuDomainObjEnterMonitor(driver, vm);
2283
            r = qemuMonitorSetBalloon(priv->mon, newmem);
2284
            qemuDomainObjExitMonitor(driver, vm);
2285 2286
            virDomainAuditMemory(vm, vm->def->mem.cur_balloon, newmem, "update",
                                 r == 1);
2287 2288 2289 2290 2291
            if (r < 0)
                goto endjob;

            /* Lack of balloon support is a fatal error */
            if (r == 0) {
2292 2293 2294
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("Unable to change memory of active domain without "
                                 "the balloon device and guest OS balloon driver"));
2295 2296 2297 2298
                goto endjob;
            }
        }

2299
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
2300
            sa_assert(persistentDef);
2301 2302 2303 2304
            persistentDef->mem.cur_balloon = newmem;
            ret = virDomainSaveConfig(driver->configDir, persistentDef);
            goto endjob;
        }
2305
    }
2306

2307
    ret = 0;
2308
endjob:
2309
    if (qemuDomainObjEndJob(driver, vm) == 0)
2310
        vm = NULL;
2311

2312
cleanup:
2313
    if (vm)
2314
        virObjectUnlock(vm);
2315
    return ret;
2316 2317
}

2318
static int qemuDomainSetMemory(virDomainPtr dom, unsigned long newmem)
2319
{
2320
    return qemuDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
2321 2322
}

2323
static int qemuDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
2324
{
2325
    return qemuDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
2326 2327
}

2328 2329
static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags)
{
2330
    virQEMUDriverPtr driver = domain->conn->privateData;
2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341
    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);
2342 2343
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2344 2345 2346 2347
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
2348 2349
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2350 2351 2352 2353 2354
        goto cleanup;
    }

    priv = vm->privateData;

2355
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
2356
        goto cleanup;
2357 2358

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

2364
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2365 2366
    ret = qemuMonitorInjectNMI(priv->mon);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2367 2368

endjob:
2369
    if (qemuDomainObjEndJob(driver, vm) == 0) {
2370 2371 2372 2373 2374 2375
        vm = NULL;
        goto cleanup;
    }

cleanup:
    if (vm)
2376
        virObjectUnlock(vm);
2377 2378 2379 2380
    qemuDriverUnlock(driver);
    return ret;
}

2381 2382 2383 2384 2385 2386 2387
static int qemuDomainSendKey(virDomainPtr domain,
                             unsigned int codeset,
                             unsigned int holdtime,
                             unsigned int *keycodes,
                             int nkeycodes,
                             unsigned int flags)
{
2388
    virQEMUDriverPtr driver = domain->conn->privateData;
2389 2390 2391 2392 2393 2394
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2395 2396
    /* translate the keycode to RFB for qemu driver */
    if (codeset != VIR_KEYCODE_SET_RFB) {
2397 2398 2399 2400
        int i;
        int keycode;

        for (i = 0; i < nkeycodes; i++) {
2401
            keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_RFB,
2402 2403
                                               keycodes[i]);
            if (keycode < 0) {
2404 2405 2406 2407
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot translate keycode %u of %s codeset to rfb keycode"),
                               keycodes[i],
                               virKeycodeSetTypeToString(codeset));
2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418
                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);
2419 2420
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
2421 2422 2423 2424 2425 2426 2427 2428 2429
        goto cleanup;
    }

    priv = vm->privateData;

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

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

2435
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
2436 2437
    ret = qemuMonitorSendKey(priv->mon, holdtime, keycodes, nkeycodes);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
2438 2439 2440

endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
2441 2442 2443 2444
        vm = NULL;

cleanup:
    if (vm)
2445
        virObjectUnlock(vm);
2446
    qemuDriverUnlock(driver);
2447 2448 2449
    return ret;
}

2450 2451
static int qemuDomainGetInfo(virDomainPtr dom,
                             virDomainInfoPtr info)
2452
{
2453
    virQEMUDriverPtr driver = dom->conn->privateData;
2454 2455
    virDomainObjPtr vm;
    int ret = -1;
2456
    int err;
2457
    unsigned long long balloon;
2458

2459
    if (!(vm = qemuDomObjFromDomain(dom)))
2460
        goto cleanup;
D
Daniel P. Berrange 已提交
2461

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

D
Daniel P. Berrange 已提交
2464
    if (!virDomainObjIsActive(vm)) {
2465
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
2466
    } else {
2467
        if (qemuGetProcessInfo(&(info->cpuTime), NULL, NULL, vm->pid, 0) < 0) {
2468 2469
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("cannot read cputime for domain"));
2470
            goto cleanup;
D
Daniel P. Berrange 已提交
2471 2472 2473
        }
    }

2474
    info->maxMem = vm->def->mem.max_balloon;
2475

D
Daniel P. Berrange 已提交
2476
    if (virDomainObjIsActive(vm)) {
2477
        qemuDomainObjPrivatePtr priv = vm->privateData;
2478 2479 2480

        if ((vm->def->memballoon != NULL) &&
            (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
2481
            info->memory = vm->def->mem.max_balloon;
2482
        } else if (qemuCapsGet(priv->caps, QEMU_CAPS_BALLOON_EVENT)) {
2483
            info->memory = vm->def->mem.cur_balloon;
2484
        } else if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
2485
            if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
2486
                goto cleanup;
2487 2488 2489
            if (!virDomainObjIsActive(vm))
                err = 0;
            else {
2490
                qemuDomainObjEnterMonitor(driver, vm);
2491
                err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
2492
                qemuDomainObjExitMonitor(driver, vm);
2493
            }
2494
            if (qemuDomainObjEndJob(driver, vm) == 0) {
2495
                vm = NULL;
2496 2497 2498
                goto cleanup;
            }

2499 2500 2501 2502 2503 2504 2505
            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) {
2506
                /* Balloon not supported, so maxmem is always the allocation */
2507
                info->memory = vm->def->mem.max_balloon;
2508
            } else {
2509
                info->memory = balloon;
2510
            }
2511
        } else {
2512
            info->memory = vm->def->mem.cur_balloon;
2513
        }
2514
    } else {
2515
        info->memory = vm->def->mem.cur_balloon;
2516 2517
    }

2518
    info->nrVirtCpu = vm->def->vcpus;
2519 2520 2521
    ret = 0;

cleanup:
2522
    if (vm)
2523
        virObjectUnlock(vm);
2524
    return ret;
D
Daniel P. Berrange 已提交
2525 2526
}

2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537
static int
qemuDomainGetState(virDomainPtr dom,
                   int *state,
                   int *reason,
                   unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

2538
    if (!(vm = qemuDomObjFromDomain(dom)))
2539 2540
        goto cleanup;

J
Jiri Denemark 已提交
2541
    *state = virDomainObjGetState(vm, reason);
2542 2543 2544 2545
    ret = 0;

cleanup:
    if (vm)
2546
        virObjectUnlock(vm);
2547 2548 2549
    return ret;
}

2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560
static int
qemuDomainGetControlInfo(virDomainPtr dom,
                          virDomainControlInfoPtr info,
                          unsigned int flags)
{
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

2561
    if (!(vm = qemuDomObjFromDomain(dom)))
2562 2563 2564
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
2565 2566
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2567 2568 2569 2570 2571 2572 2573 2574 2575
        goto cleanup;
    }

    priv = vm->privateData;

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

    if (priv->monError) {
        info->state = VIR_DOMAIN_CONTROL_ERROR;
2576
    } else if (priv->job.active) {
2577 2578
        if (!priv->monStart) {
            info->state = VIR_DOMAIN_CONTROL_JOB;
2579
            if (virTimeMillisNow(&info->stateTime) < 0)
2580
                goto cleanup;
2581
            info->stateTime -= priv->job.start;
2582 2583
        } else {
            info->state = VIR_DOMAIN_CONTROL_OCCUPIED;
2584
            if (virTimeMillisNow(&info->stateTime) < 0)
2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595
                goto cleanup;
            info->stateTime -= priv->monStart;
        }
    } else {
        info->state = VIR_DOMAIN_CONTROL_OK;
    }

    ret = 0;

cleanup:
    if (vm)
2596
        virObjectUnlock(vm);
2597 2598 2599
    return ret;
}

D
Daniel P. Berrange 已提交
2600

2601 2602 2603 2604 2605 2606
/* It would be nice to replace 'Qemud' with 'Qemu' but
 * this magic string is ABI, so it can't be changed
 */
#define QEMU_SAVE_MAGIC   "LibvirtQemudSave"
#define QEMU_SAVE_PARTIAL "LibvirtQemudPart"
#define QEMU_SAVE_VERSION 2
2607

2608
verify(sizeof(QEMU_SAVE_MAGIC) == sizeof(QEMU_SAVE_PARTIAL));
E
Eric Blake 已提交
2609

2610
typedef enum {
2611 2612 2613
    QEMU_SAVE_FORMAT_RAW = 0,
    QEMU_SAVE_FORMAT_GZIP = 1,
    QEMU_SAVE_FORMAT_BZIP2 = 2,
2614 2615
    /*
     * Deprecated by xz and never used as part of a release
2616
     * QEMU_SAVE_FORMAT_LZMA
2617
     */
2618 2619
    QEMU_SAVE_FORMAT_XZ = 3,
    QEMU_SAVE_FORMAT_LZOP = 4,
2620 2621 2622
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
2623

2624
    QEMU_SAVE_FORMAT_LAST
2625
} virQEMUSaveFormat;
2626

2627 2628
VIR_ENUM_DECL(qemuSaveCompression)
VIR_ENUM_IMPL(qemuSaveCompression, QEMU_SAVE_FORMAT_LAST,
2629 2630 2631
              "raw",
              "gzip",
              "bzip2",
2632 2633
              "xz",
              "lzop")
2634

2635 2636 2637
typedef struct _virQEMUSaveHeader virQEMUSaveHeader;
typedef virQEMUSaveHeader *virQEMUSaveHeaderPtr;
struct _virQEMUSaveHeader {
2638
    char magic[sizeof(QEMU_SAVE_MAGIC)-1];
2639 2640 2641 2642 2643
    uint32_t version;
    uint32_t xml_len;
    uint32_t was_running;
    uint32_t compressed;
    uint32_t unused[15];
2644 2645
};

2646
static inline void
2647
bswap_header(virQEMUSaveHeaderPtr hdr) {
2648 2649 2650 2651 2652 2653 2654
    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);
}


2655
/* return -errno on failure, or 0 on success */
E
Eric Blake 已提交
2656
static int
2657
qemuDomainSaveHeader(int fd, const char *path, const char *xml,
2658
                     virQEMUSaveHeaderPtr header)
E
Eric Blake 已提交
2659
{
2660 2661
    int ret = 0;

E
Eric Blake 已提交
2662
    if (safewrite(fd, header, sizeof(*header)) != sizeof(*header)) {
2663
        ret = -errno;
2664 2665 2666
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to write header to domain save file '%s'"),
                       path);
2667 2668 2669
        goto endjob;
    }

E
Eric Blake 已提交
2670
    if (safewrite(fd, xml, header->xml_len) != header->xml_len) {
2671
        ret = -errno;
2672 2673
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to write xml to '%s'"), path);
2674 2675 2676 2677 2678 2679
        goto endjob;
    }
endjob:
    return ret;
}

2680
/* Given a virQEMUSaveFormat compression level, return the name
2681 2682 2683 2684
 * of the program to run, or NULL if no program is needed.  */
static const char *
qemuCompressProgramName(int compress)
{
2685 2686
    return (compress == QEMU_SAVE_FORMAT_RAW ? NULL :
            qemuSaveCompressionTypeToString(compress));
2687 2688
}

E
Eric Blake 已提交
2689 2690 2691
/* Internal function to properly create or open existing files, with
 * ownership affected by qemu driver setup.  */
static int
2692
qemuOpenFile(virQEMUDriverPtr driver, const char *path, int oflags,
E
Eric Blake 已提交
2693 2694 2695 2696 2697 2698
             bool *needUnlink, bool *bypassSecurityDriver)
{
    struct stat sb;
    bool is_reg = true;
    bool need_unlink = false;
    bool bypass_security = false;
L
Laine Stump 已提交
2699
    unsigned int vfoflags = 0;
E
Eric Blake 已提交
2700
    int fd = -1;
2701
    int path_shared = virStorageFileIsSharedFS(path);
E
Eric Blake 已提交
2702 2703 2704 2705 2706 2707 2708 2709
    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;
2710 2711 2712 2713 2714 2715

        /* 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 已提交
2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735
        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 已提交
2736 2737
        if ((fd = virFileOpenAs(path, oflags, S_IRUSR | S_IWUSR, uid, gid,
                                vfoflags | VIR_FILE_OPEN_NOFORK)) < 0) {
E
Eric Blake 已提交
2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752
            /* 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. */
2753
            switch (path_shared) {
E
Eric Blake 已提交
2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780
                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 已提交
2781
                                    vfoflags | VIR_FILE_OPEN_FORK)) < 0) {
E
Eric Blake 已提交
2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803
                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;
}

2804 2805 2806
/* Helper function to execute a migration to file with a correct save header
 * the caller needs to make sure that the processors are stopped and do all other
 * actions besides saving memory */
2807
static int
2808
qemuDomainSaveMemory(virQEMUDriverPtr driver,
2809 2810
                     virDomainObjPtr vm,
                     const char *path,
2811
                     const char *domXML,
2812 2813 2814 2815
                     int compressed,
                     bool was_running,
                     unsigned int flags,
                     enum qemuDomainAsyncJob asyncJob)
2816
{
2817
    virQEMUSaveHeader header;
2818
    bool bypassSecurityDriver = false;
E
Eric Blake 已提交
2819
    bool needUnlink = false;
2820
    int ret = -1;
2821
    int fd = -1;
2822
    int directFlag = 0;
J
Jiri Denemark 已提交
2823
    virFileWrapperFdPtr wrapperFd = NULL;
2824
    unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
2825 2826 2827
    unsigned long long pad;
    unsigned long long offset;
    size_t len;
2828
    char *xml = NULL;
2829

2830
    memset(&header, 0, sizeof(header));
2831 2832
    memcpy(header.magic, QEMU_SAVE_PARTIAL, sizeof(header.magic));
    header.version = QEMU_SAVE_VERSION;
2833
    header.was_running = was_running ? 1 : 0;
2834

2835
    header.compressed = compressed;
2836

2837
    len = strlen(domXML) + 1;
2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850
    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));
2851
    if (VIR_ALLOC_N(xml, len + pad) < 0) {
2852
        virReportOOMError();
2853
        goto cleanup;
2854
    }
2855 2856
    strcpy(xml, domXML);

2857 2858
    offset += pad;
    header.xml_len = len;
2859

2860
    /* Obtain the file handle.  */
2861 2862
    if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE)) {
        wrapperFlags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
2863 2864
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
2865 2866
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
E
Eric Blake 已提交
2867
            goto cleanup;
2868
        }
2869
    }
E
Eric Blake 已提交
2870 2871 2872
    fd = qemuOpenFile(driver, path, O_WRONLY | O_TRUNC | O_CREAT | directFlag,
                      &needUnlink, &bypassSecurityDriver);
    if (fd < 0)
2873 2874
        goto cleanup;

2875
    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, wrapperFlags)))
2876
        goto cleanup;
2877

2878
    /* Write header to file, followed by XML */
2879 2880
    if (qemuDomainSaveHeader(fd, path, xml, &header) < 0)
        goto cleanup;
2881

2882
    /* Perform the migration */
2883
    if (qemuMigrationToFile(driver, vm, fd, offset, path,
2884
                            qemuCompressProgramName(compressed),
E
Eric Blake 已提交
2885
                            bypassSecurityDriver,
2886 2887
                            asyncJob) < 0)
        goto cleanup;
E
Eric Blake 已提交
2888

2889 2890 2891 2892 2893 2894 2895 2896
    /* 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);
2897
        goto cleanup;
E
Eric Blake 已提交
2898
    }
2899

2900
    if (virFileWrapperFdClose(wrapperFd) < 0)
2901 2902 2903 2904
        goto cleanup;

    if ((fd = qemuOpenFile(driver, path, O_WRONLY, NULL, NULL)) < 0)
        goto cleanup;
2905

2906
    memcpy(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic));
2907

E
Eric Blake 已提交
2908 2909
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
        virReportSystemError(errno, _("unable to write %s"), path);
2910
        goto cleanup;
E
Eric Blake 已提交
2911
    }
2912

2913 2914
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("unable to close %s"), path);
2915
        goto cleanup;
2916 2917
    }

2918 2919
    ret = 0;

2920 2921
cleanup:
    VIR_FORCE_CLOSE(fd);
2922
    virFileWrapperFdCatchError(wrapperFd);
2923
    virFileWrapperFdFree(wrapperFd);
2924
    VIR_FREE(xml);
2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 2937 2938

    if (ret != 0 && needUnlink)
        unlink(path);

    return ret;
}

/* This internal function expects the driver lock to already be held on
 * 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).
 */
static int
2939
qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
2940 2941 2942 2943 2944 2945 2946 2947 2948 2949
                       virDomainObjPtr vm, const char *path,
                       int compressed, const char *xmlin, unsigned int flags)
{
    char *xml = NULL;
    bool was_running = false;
    int ret = -1;
    int rc;
    virDomainEventPtr event = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;

2950
    if (!qemuMigrationIsAllowed(driver, vm, vm->def, false))
2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009
        goto cleanup;

    if (qemuDomainObjBeginAsyncJobWithDriver(driver, vm,
                                             QEMU_ASYNC_JOB_SAVE) < 0)

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

    /* Pause */
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
        was_running = true;
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_SAVE) < 0)
            goto endjob;

        if (!virDomainObjIsActive(vm)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
            goto endjob;
        }
    }

   /* libvirt.c already guaranteed these two flags are exclusive.  */
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        was_running = true;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        was_running = false;

    /* 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;
        }
        xml = qemuDomainDefFormatLive(driver, def, true, true);
    } else {
        xml = qemuDomainDefFormatLive(driver, vm->def, true, true);
    }
    if (!xml) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to get domain xml"));
        goto endjob;
    }

    ret = qemuDomainSaveMemory(driver, vm, path, xml, compressed,
                               was_running, flags, QEMU_ASYNC_JOB_SAVE);
    if (ret < 0)
        goto endjob;

3010
    /* Shut it down */
3011
    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SAVED, 0);
3012
    virDomainAuditStop(vm, "saved");
3013 3014 3015
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
3016
    if (!vm->persistent) {
3017
        if (qemuDomainObjEndAsyncJob(driver, vm) > 0)
3018
            qemuDomainRemoveInactive(driver, vm);
3019 3020
        vm = NULL;
    }
3021

3022
endjob:
3023
    if (vm) {
3024
        if (ret != 0) {
3025
            if (was_running && virDomainObjIsActive(vm)) {
J
Jiri Denemark 已提交
3026
                rc = qemuProcessStartCPUs(driver, vm, dom->conn,
3027 3028
                                          VIR_DOMAIN_RUNNING_SAVE_CANCELED,
                                          QEMU_ASYNC_JOB_SAVE);
3029
                if (rc < 0) {
3030
                    VIR_WARN("Unable to resume guest CPUs after save failure");
3031 3032 3033 3034
                    event = virDomainEventNewFromObj(vm,
                                                     VIR_DOMAIN_EVENT_SUSPENDED,
                                                     VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
                }
3035
            }
3036
        }
3037
        if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
3038
            vm = NULL;
3039
    }
3040

3041 3042
cleanup:
    VIR_FREE(xml);
3043 3044
    if (event)
        qemuDomainEventQueue(driver, event);
3045
    if (vm)
3046
        virObjectUnlock(vm);
3047
    return ret;
D
Daniel P. Berrange 已提交
3048 3049
}

3050
/* Returns true if a compression program is available in PATH */
3051
static bool qemuCompressProgramAvailable(virQEMUSaveFormat compress)
3052 3053 3054 3055
{
    const char *prog;
    char *c;

3056
    if (compress == QEMU_SAVE_FORMAT_RAW)
3057
        return true;
3058
    prog = qemuSaveCompressionTypeToString(compress);
3059 3060 3061 3062 3063 3064 3065
    c = virFindFileInPath(prog);
    if (!c)
        return false;
    VIR_FREE(c);
    return true;
}

3066 3067 3068
static int
qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
                    unsigned int flags)
3069
{
3070
    virQEMUDriverPtr driver = dom->conn->privateData;
3071
    int compressed;
3072 3073 3074
    int ret = -1;
    virDomainObjPtr vm = NULL;

3075 3076 3077
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
3078

3079
    qemuDriverLock(driver);
3080 3081

    if (driver->saveImageFormat == NULL)
3082
        compressed = QEMU_SAVE_FORMAT_RAW;
3083
    else {
3084
        compressed = qemuSaveCompressionTypeFromString(driver->saveImageFormat);
3085
        if (compressed < 0) {
3086 3087 3088
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Invalid save image format specified "
                                   "in configuration file"));
3089
            goto cleanup;
3090
        }
3091
        if (!qemuCompressProgramAvailable(compressed)) {
3092 3093 3094
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("Compression program for image format "
                                   "in configuration file isn't available"));
3095
            goto cleanup;
3096
        }
3097 3098
    }

3099 3100 3101 3102
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3103 3104
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
3105 3106 3107
        goto cleanup;
    }

3108
    if (!virDomainObjIsActive(vm)) {
3109 3110
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3111 3112 3113
        goto cleanup;
    }

3114
    ret = qemuDomainSaveInternal(driver, dom, vm, path, compressed,
3115
                                 dxml, flags);
3116
    vm = NULL;
3117 3118 3119

cleanup:
    if (vm)
3120
        virObjectUnlock(vm);
3121 3122 3123
    qemuDriverUnlock(driver);

    return ret;
3124 3125
}

3126 3127 3128 3129 3130 3131
static int
qemuDomainSave(virDomainPtr dom, const char *path)
{
    return qemuDomainSaveFlags(dom, path, NULL, 0);
}

3132
static char *
3133 3134
qemuDomainManagedSavePath(virQEMUDriverPtr driver, virDomainObjPtr vm)
{
3135 3136 3137 3138
    char *ret;

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

3142
    return ret;
3143 3144 3145 3146 3147
}

static int
qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
{
3148 3149
    virQEMUDriverPtr driver;
    virDomainObjPtr vm;
3150 3151 3152 3153
    char *name = NULL;
    int ret = -1;
    int compressed;

3154 3155 3156
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
3157

3158 3159
    if (!(vm = qemuDomObjFromDomainDriver(dom, &driver)))
        return -1;
3160

3161
    if (!virDomainObjIsActive(vm)) {
3162 3163
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3164 3165
        goto cleanup;
    }
3166
    if (!vm->persistent) {
3167 3168
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot do managed save for transient domain"));
3169 3170
        goto cleanup;
    }
3171

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

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

3177
    compressed = QEMU_SAVE_FORMAT_RAW;
3178 3179 3180 3181
    if ((ret = qemuDomainSaveInternal(driver, dom, vm, name, compressed,
                                      NULL, flags)) == 0)
        vm->hasManagedSave = true;

3182
    vm = NULL;
3183 3184 3185

cleanup:
    if (vm)
3186
        virObjectUnlock(vm);
3187
    qemuDriverUnlock(driver);
3188 3189 3190
    VIR_FREE(name);

    return ret;
3191 3192
}

3193 3194 3195 3196 3197 3198
static void
qemuDomainManagedSaveLoad(void *payload,
                          const void *n ATTRIBUTE_UNUSED,
                          void *opaque)
{
    virDomainObjPtr vm = payload;
3199
    virQEMUDriverPtr driver = opaque;
3200 3201
    char *name;

3202
    virObjectLock(vm);
3203 3204 3205 3206 3207 3208 3209

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

    vm->hasManagedSave = virFileExists(name);

cleanup:
3210
    virObjectUnlock(vm);
3211 3212 3213
    VIR_FREE(name);
}

3214 3215 3216 3217
static int
qemuDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    virDomainObjPtr vm = NULL;
3218
    int ret;
3219

3220
    virCheckFlags(0, -1);
3221

3222 3223
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
3224

3225
    ret = vm->hasManagedSave;
3226
    virObjectUnlock(vm);
3227 3228 3229 3230 3231 3232
    return ret;
}

static int
qemuDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
{
3233 3234
    virQEMUDriverPtr driver;
    virDomainObjPtr vm;
3235 3236 3237
    int ret = -1;
    char *name = NULL;

3238
    virCheckFlags(0, -1);
3239

3240 3241
    if (!(vm = qemuDomObjFromDomainDriver(dom, &driver)))
        return -1;
3242

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

3246 3247 3248 3249 3250 3251 3252
    if (unlink(name) < 0) {
        virReportSystemError(errno,
                             _("Failed to remove managed save file '%s'"),
                             name);
        goto cleanup;
    }

3253
    vm->hasManagedSave = false;
3254
    ret = 0;
3255 3256 3257

cleanup:
    VIR_FREE(name);
3258
    virObjectUnlock(vm);
3259 3260 3261
    qemuDriverUnlock(driver);
    return ret;
}
D
Daniel P. Berrange 已提交
3262

3263
static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm,
3264 3265 3266 3267 3268
                        int fd, enum qemuDomainAsyncJob asyncJob)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;

3269
    if (!qemuCapsGet(priv->caps, QEMU_CAPS_DUMP_GUEST_MEMORY)) {
3270 3271
        virReportError(VIR_ERR_NO_SUPPORT, "%s",
                       _("dump-guest-memory is not supported"));
3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283
        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;

3284
    ret = qemuMonitorDumpToFd(priv->mon, fd);
3285 3286 3287 3288 3289
    qemuDomainObjExitMonitorWithDriver(driver, vm);

    return ret;
}

3290
static int
3291
doCoreDump(virQEMUDriverPtr driver,
3292 3293
           virDomainObjPtr vm,
           const char *path,
3294
           virQEMUSaveFormat compress,
3295
           unsigned int dump_flags)
H
Hu Tao 已提交
3296 3297 3298
{
    int fd = -1;
    int ret = -1;
J
Jiri Denemark 已提交
3299
    virFileWrapperFdPtr wrapperFd = NULL;
3300
    int directFlag = 0;
3301
    unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
H
Hu Tao 已提交
3302 3303

    /* Create an empty file with appropriate ownership.  */
3304
    if (dump_flags & VIR_DUMP_BYPASS_CACHE) {
3305
        flags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
3306 3307
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
3308 3309
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
3310 3311 3312
            goto cleanup;
        }
    }
E
Eric Blake 已提交
3313 3314 3315 3316 3317 3318
    /* 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 已提交
3319 3320
        goto cleanup;

3321
    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, flags)))
3322 3323
        goto cleanup;

3324 3325 3326 3327 3328 3329 3330 3331 3332
    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)
3333 3334
        goto cleanup;

H
Hu Tao 已提交
3335 3336
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno,
3337
                             _("unable to close file %s"),
H
Hu Tao 已提交
3338 3339 3340
                             path);
        goto cleanup;
    }
J
Jiri Denemark 已提交
3341
    if (virFileWrapperFdClose(wrapperFd) < 0)
3342
        goto cleanup;
H
Hu Tao 已提交
3343

3344
    ret = 0;
H
Hu Tao 已提交
3345 3346

cleanup:
3347
    VIR_FORCE_CLOSE(fd);
3348
    if (ret != 0) {
3349
        virFileWrapperFdCatchError(wrapperFd);
H
Hu Tao 已提交
3350
        unlink(path);
3351 3352
    }
    virFileWrapperFdFree(wrapperFd);
H
Hu Tao 已提交
3353 3354 3355
    return ret;
}

3356
static virQEMUSaveFormat
3357
getCompressionType(virQEMUDriverPtr driver)
3358
{
3359
    int compress = QEMU_SAVE_FORMAT_RAW;
3360

3361 3362 3363 3364 3365
    /*
     * We reuse "save" flag for "dump" here. Then, we can support the same
     * format in "save" and "dump".
     */
    if (driver->dumpImageFormat) {
3366
        compress = qemuSaveCompressionTypeFromString(driver->dumpImageFormat);
3367 3368 3369
        /* Use "raw" as the format if the specified format is not valid,
         * or the compress program is not available.
         */
3370
        if (compress < 0) {
3371 3372
            VIR_WARN("%s", _("Invalid dump image format specified in "
                             "configuration file, using raw"));
3373
            return QEMU_SAVE_FORMAT_RAW;
3374
        }
3375
        if (!qemuCompressProgramAvailable(compress)) {
3376 3377 3378
            VIR_WARN("%s", _("Compression program for dump image format "
                             "in configuration file isn't available, "
                             "using raw"));
3379
            return QEMU_SAVE_FORMAT_RAW;
3380
        }
3381
    }
3382 3383 3384
    return compress;
}

3385 3386 3387
static int qemuDomainCoreDump(virDomainPtr dom,
                              const char *path,
                              unsigned int flags)
3388
{
3389
    virQEMUDriverPtr driver = dom->conn->privateData;
3390
    virDomainObjPtr vm;
M
Michal Privoznik 已提交
3391
    qemuDomainObjPrivatePtr priv;
3392
    int resume = 0, paused = 0;
H
Hu Tao 已提交
3393
    int ret = -1;
3394 3395
    virDomainEventPtr event = NULL;

M
Michal Privoznik 已提交
3396
    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH |
3397 3398
                  VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET |
                  VIR_DUMP_MEMORY_ONLY, -1);
3399

P
Paolo Bonzini 已提交
3400 3401 3402 3403 3404 3405
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
3406 3407
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
P
Paolo Bonzini 已提交
3408 3409 3410
        goto cleanup;
    }

3411 3412
    if (qemuDomainObjBeginAsyncJobWithDriver(driver, vm,
                                             QEMU_ASYNC_JOB_DUMP) < 0)
3413 3414
        goto cleanup;

D
Daniel P. Berrange 已提交
3415
    if (!virDomainObjIsActive(vm)) {
3416 3417
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3418
        goto endjob;
P
Paolo Bonzini 已提交
3419 3420
    }

P
Paolo Bonzini 已提交
3421 3422
    /* Migrate will always stop the VM, so the resume condition is
       independent of whether the stop command is issued.  */
J
Jiri Denemark 已提交
3423
    resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
P
Paolo Bonzini 已提交
3424 3425

    /* Pause domain for non-live dump */
J
Jiri Denemark 已提交
3426 3427
    if (!(flags & VIR_DUMP_LIVE) &&
        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
3428 3429
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_DUMP,
                                QEMU_ASYNC_JOB_DUMP) < 0)
3430
            goto endjob;
P
Paolo Bonzini 已提交
3431
        paused = 1;
3432 3433

        if (!virDomainObjIsActive(vm)) {
3434 3435
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
3436 3437
            goto endjob;
        }
P
Paolo Bonzini 已提交
3438 3439
    }

3440
    ret = doCoreDump(driver, vm, path, getCompressionType(driver), flags);
3441 3442 3443 3444
    if (ret < 0)
        goto endjob;

    paused = 1;
3445 3446

endjob:
3447
    if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
3448
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED, 0);
3449
        virDomainAuditStop(vm, "crashed");
3450 3451 3452 3453 3454
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
    }

P
Paolo Bonzini 已提交
3455 3456 3457
    /* 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 已提交
3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469
    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) {
3470 3471 3472
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
3473
            if (virGetLastError() == NULL)
3474 3475
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
3476 3477
        }
    }
3478

3479
    if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
3480
        vm = NULL;
3481
    else if ((ret == 0) && (flags & VIR_DUMP_CRASH) && !vm->persistent) {
3482
        qemuDomainRemoveInactive(driver, vm);
3483 3484
        vm = NULL;
    }
3485 3486

cleanup:
P
Paolo Bonzini 已提交
3487
    if (vm)
3488
        virObjectUnlock(vm);
3489 3490
    if (event)
        qemuDomainEventQueue(driver, event);
3491
    qemuDriverUnlock(driver);
P
Paolo Bonzini 已提交
3492 3493 3494
    return ret;
}

3495 3496 3497 3498
static char *
qemuDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
3499
                     unsigned int flags)
3500
{
3501
    virQEMUDriverPtr driver = dom->conn->privateData;
3502 3503 3504 3505 3506
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    char *tmp = NULL;
    int tmp_fd = -1;
    char *ret = NULL;
E
Eric Blake 已提交
3507
    bool unlink_tmp = false;
3508

E
Eric Blake 已提交
3509 3510
    virCheckFlags(0, NULL);

3511
    if (!(vm = qemuDomObjFromDomain(dom)))
3512 3513 3514 3515
        goto cleanup;

    priv = vm->privateData;

3516
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
3517 3518 3519
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
3520 3521
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3522 3523 3524 3525 3526 3527
        goto endjob;
    }

    /* Well, even if qemu allows multiple graphic cards, heads, whatever,
     * screenshot command does not */
    if (screen) {
3528 3529 3530
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("currently is supported only taking "
                               "screenshots of screen ID 0"));
3531 3532 3533 3534 3535 3536 3537 3538
        goto endjob;
    }

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

3539 3540
    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
3541 3542
        goto endjob;
    }
E
Eric Blake 已提交
3543
    unlink_tmp = true;
3544

3545
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
3546

3547
    qemuDomainObjEnterMonitor(driver, vm);
3548
    if (qemuMonitorScreendump(priv->mon, tmp) < 0) {
3549
        qemuDomainObjExitMonitor(driver, vm);
3550 3551
        goto endjob;
    }
3552
    qemuDomainObjExitMonitor(driver, vm);
3553 3554 3555 3556 3557 3558

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

E
Eric Blake 已提交
3559
    if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
3560 3561
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to open stream"));
3562 3563 3564 3565 3566 3567 3568
        goto endjob;
    }

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

endjob:
    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
3569 3570
    if (unlink_tmp)
        unlink(tmp);
E
Eric Blake 已提交
3571
    VIR_FREE(tmp);
3572

3573
    if (qemuDomainObjEndJob(driver, vm) == 0)
3574 3575 3576 3577
        vm = NULL;

cleanup:
    if (vm)
3578
        virObjectUnlock(vm);
3579 3580 3581
    return ret;
}

H
Hu Tao 已提交
3582 3583 3584
static void processWatchdogEvent(void *data, void *opaque)
{
    int ret;
3585
    struct qemuDomainWatchdogEvent *wdEvent = data;
3586
    virQEMUDriverPtr driver = opaque;
H
Hu Tao 已提交
3587

W
Wen Congyang 已提交
3588
    qemuDriverLock(driver);
3589
    virObjectLock(wdEvent->vm);
W
Wen Congyang 已提交
3590

H
Hu Tao 已提交
3591 3592 3593 3594
    switch (wdEvent->action) {
    case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
        {
            char *dumpfile;
3595
            unsigned int flags = 0;
H
Hu Tao 已提交
3596

E
Eric Blake 已提交
3597
            if (virAsprintf(&dumpfile, "%s/%s-%u",
H
Hu Tao 已提交
3598 3599
                            driver->autoDumpPath,
                            wdEvent->vm->def->name,
E
Eric Blake 已提交
3600 3601
                            (unsigned int)time(NULL)) < 0) {
                virReportOOMError();
W
Wen Congyang 已提交
3602
                goto unlock;
E
Eric Blake 已提交
3603
            }
H
Hu Tao 已提交
3604

3605 3606
            if (qemuDomainObjBeginAsyncJobWithDriver(driver, wdEvent->vm,
                                                     QEMU_ASYNC_JOB_DUMP) < 0) {
W
Wen Congyang 已提交
3607 3608 3609
                VIR_FREE(dumpfile);
                goto unlock;
            }
H
Hu Tao 已提交
3610 3611

            if (!virDomainObjIsActive(wdEvent->vm)) {
3612 3613
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("domain is not running"));
W
Wen Congyang 已提交
3614 3615
                VIR_FREE(dumpfile);
                goto endjob;
H
Hu Tao 已提交
3616 3617
            }

3618
            flags |= driver->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0;
3619
            ret = doCoreDump(driver, wdEvent->vm, dumpfile,
3620
                             getCompressionType(driver), flags);
H
Hu Tao 已提交
3621
            if (ret < 0)
3622 3623
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Dump failed"));
H
Hu Tao 已提交
3624

J
Jiri Denemark 已提交
3625
            ret = qemuProcessStartCPUs(driver, wdEvent->vm, NULL,
3626 3627
                                       VIR_DOMAIN_RUNNING_UNPAUSED,
                                       QEMU_ASYNC_JOB_DUMP);
H
Hu Tao 已提交
3628 3629

            if (ret < 0)
3630 3631
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Resuming after dump failed"));
H
Hu Tao 已提交
3632 3633 3634 3635

            VIR_FREE(dumpfile);
        }
        break;
W
Wen Congyang 已提交
3636 3637
    default:
        goto unlock;
H
Hu Tao 已提交
3638 3639
    }

W
Wen Congyang 已提交
3640 3641 3642 3643
endjob:
    /* Safe to ignore value since ref count was incremented in
     * qemuProcessHandleWatchdog().
     */
3644
    ignore_value(qemuDomainObjEndAsyncJob(driver, wdEvent->vm));
W
Wen Congyang 已提交
3645 3646

unlock:
3647
    virObjectUnlock(wdEvent->vm);
3648
    virObjectUnref(wdEvent->vm);
W
Wen Congyang 已提交
3649
    qemuDriverUnlock(driver);
H
Hu Tao 已提交
3650 3651
    VIR_FREE(wdEvent);
}
P
Paolo Bonzini 已提交
3652

3653
static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver,
3654 3655
                                  virDomainObjPtr vm,
                                  unsigned int nvcpus)
3656 3657
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
3658
    int i, rc = 1;
3659
    int ret = -1;
3660
    int oldvcpus = vm->def->vcpus;
E
Eric Blake 已提交
3661
    int vcpus = oldvcpus;
3662 3663
    pid_t *cpupids = NULL;
    int ncpupids;
3664 3665
    virCgroupPtr cgroup = NULL;
    virCgroupPtr cgroup_vcpu = NULL;
3666
    bool cgroup_available = false;
3667

3668
    qemuDomainObjEnterMonitor(driver, vm);
3669

3670 3671 3672
    /* 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 已提交
3673 3674
    if (nvcpus > vcpus) {
        for (i = vcpus ; i < nvcpus ; i++) {
3675 3676 3677 3678 3679 3680 3681
            /* Online new CPU */
            rc = qemuMonitorSetCPU(priv->mon, i, 1);
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3682
            vcpus++;
3683 3684
        }
    } else {
E
Eric Blake 已提交
3685
        for (i = vcpus - 1 ; i >= nvcpus ; i--) {
3686 3687 3688 3689 3690 3691 3692
            /* Offline old CPU */
            rc = qemuMonitorSetCPU(priv->mon, i, 0);
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3693
            vcpus--;
3694 3695 3696
        }
    }

3697 3698
    /* hotplug succeeded */

3699 3700
    ret = 0;

3701 3702 3703 3704 3705 3706 3707 3708 3709 3710
    /* 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;
    }

3711 3712 3713 3714 3715 3716 3717 3718 3719
    /* check if hotplug has failed */
    if (vcpus < oldvcpus && ncpupids == oldvcpus) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("qemu didn't unplug the vCPUs properly"));
        vcpus = oldvcpus;
        ret = -1;
        goto cleanup;
    }

3720
    if (ncpupids != vcpus) {
3721 3722 3723 3724
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("got wrong number of vCPU pids from QEMU monitor. "
                         "got %d, wanted %d"),
                       ncpupids, vcpus);
3725 3726 3727 3728
        ret = -1;
        goto cleanup;
    }

3729 3730
    cgroup_available = (virCgroupForDomain(driver->cgroup, vm->def->name,
                                           &cgroup, 0) == 0);
3731

3732 3733 3734 3735
    if (nvcpus > oldvcpus) {
        for (i = oldvcpus; i < nvcpus; i++) {
            if (cgroup_available) {
                int rv = -1;
3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754
                /* Create cgroup for the onlined vcpu */
                rv = virCgroupForVcpu(cgroup, i, &cgroup_vcpu, 1);
                if (rv < 0) {
                    virReportSystemError(-rv,
                                         _("Unable to create vcpu cgroup for %s(vcpu:"
                                           " %d)"),
                                         vm->def->name, i);
                    goto cleanup;
                }

                /* Add vcpu thread to the cgroup */
                rv = virCgroupAddTask(cgroup_vcpu, cpupids[i]);
                if (rv < 0) {
                    virReportSystemError(-rv,
                                         _("unable to add vcpu %d task %d to cgroup"),
                                         i, cpupids[i]);
                    virCgroupRemove(cgroup_vcpu);
                    goto cleanup;
                }
3755
            }
3756

3757 3758 3759 3760 3761 3762 3763 3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790
            /* Inherit def->cpuset */
            if (vm->def->cpumask) {
                /* vm->def->cputune.vcpupin can't be NULL if
                 * vm->def->cpumask is not NULL.
                 */
                virDomainVcpuPinDefPtr vcpupin = NULL;

                if (VIR_REALLOC_N(vm->def->cputune.vcpupin,
                                  vm->def->cputune.nvcpupin + 1) < 0) {
                    virReportOOMError();
                    goto cleanup;
                }

                if (VIR_ALLOC(vcpupin) < 0) {
                    virReportOOMError();
                    goto cleanup;
                }

                vcpupin->cpumask = virBitmapNew(VIR_DOMAIN_CPUMASK_LEN);
                virBitmapCopy(vcpupin->cpumask, vm->def->cpumask);
                vcpupin->vcpuid = i;
                vm->def->cputune.vcpupin[vm->def->cputune.nvcpupin++] = vcpupin;

                if (cgroup_available) {
                    if (qemuSetupCgroupVcpuPin(cgroup_vcpu,
                                               vm->def->cputune.vcpupin,
                                               vm->def->cputune.nvcpupin, i) < 0) {
                        virReportError(VIR_ERR_OPERATION_INVALID,
                                       _("failed to set cpuset.cpus in cgroup"
                                         " for vcpu %d"), i);
                        ret = -1;
                        goto cleanup;
                    }
                } else {
3791 3792
                    if (virProcessSetAffinity(cpupids[i],
                                              vcpupin->cpumask) < 0) {
3793 3794 3795 3796 3797 3798 3799
                        virReportError(VIR_ERR_SYSTEM_ERROR,
                                       _("failed to set cpu affinity for vcpu %d"),
                                       i);
                        ret = -1;
                        goto cleanup;
                    }
                }
3800
            }
3801 3802

            virCgroupFree(&cgroup_vcpu);
G
Guido Günther 已提交
3803
        }
3804 3805 3806 3807 3808 3809 3810
    } else {
        for (i = oldvcpus - 1; i >= nvcpus; i--) {
            virDomainVcpuPinDefPtr vcpupin = NULL;

            if (cgroup_available) {
                int rv = -1;

3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824
                rv = virCgroupForVcpu(cgroup, i, &cgroup_vcpu, 0);
                if (rv < 0) {
                    virReportSystemError(-rv,
                                         _("Unable to access vcpu cgroup for %s(vcpu:"
                                           " %d)"),
                                         vm->def->name, i);
                    goto cleanup;
                }

                /* Remove cgroup for the offlined vcpu */
                virCgroupRemove(cgroup_vcpu);
                virCgroupFree(&cgroup_vcpu);
            }

3825 3826 3827 3828 3829
            /* Free vcpupin setting */
            if ((vcpupin = virDomainLookupVcpuPin(vm->def, i))) {
                VIR_FREE(vcpupin);
            }
        }
3830 3831
    }

3832 3833 3834 3835 3836
    priv->nvcpupids = ncpupids;
    VIR_FREE(priv->vcpupids);
    priv->vcpupids = cpupids;
    cpupids = NULL;

3837
cleanup:
3838
    qemuDomainObjExitMonitor(driver, vm);
E
Eric Blake 已提交
3839
    vm->def->vcpus = vcpus;
3840
    VIR_FREE(cpupids);
3841
    virDomainAuditVcpu(vm, oldvcpus, nvcpus, "update", rc == 1);
3842 3843 3844 3845
    if (cgroup)
        virCgroupFree(&cgroup);
    if (cgroup_vcpu)
        virCgroupFree(&cgroup_vcpu);
3846 3847 3848
    return ret;

unsupported:
3849 3850
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("cannot change vcpu count of this domain"));
3851 3852 3853 3854
    goto cleanup;
}


3855
static int
3856 3857
qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
3858
{
3859
    virQEMUDriverPtr driver = dom->conn->privateData;
3860
    virDomainObjPtr vm;
3861
    virDomainDefPtr persistentDef;
3862 3863
    const char * type;
    int max;
3864
    int ret = -1;
3865
    bool maximum;
3866

3867 3868
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
3869 3870 3871
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

    if (!nvcpus || (unsigned short) nvcpus != nvcpus) {
3872 3873
        virReportError(VIR_ERR_INVALID_ARG,
                       _("argument out of range: %d"), nvcpus);
3874 3875 3876
        return -1;
    }

3877
    if (!(vm = qemuDomObjFromDomain(dom)))
3878
        goto cleanup;
3879

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

3883 3884 3885
    maximum = (flags & VIR_DOMAIN_VCPU_MAXIMUM) != 0;
    flags &= ~VIR_DOMAIN_VCPU_MAXIMUM;

3886 3887 3888
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto endjob;
3889 3890 3891

    /* MAXIMUM cannot be mixed with LIVE.  */
    if (maximum && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
3892 3893
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("cannot adjust maximum on running domain"));
3894 3895 3896
        goto endjob;
    }

3897
    if (!(type = virDomainVirtTypeToString(vm->def->virtType))) {
3898 3899 3900
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
3901 3902 3903
        goto endjob;
    }

3904
    if ((max = qemuGetMaxVCPUs(NULL, type)) < 0) {
3905 3906
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("could not determine max vcpus for the domain"));
3907 3908 3909
        goto endjob;
    }

3910
    if (!maximum && vm->def->maxvcpus < max) {
3911 3912 3913
        max = vm->def->maxvcpus;
    }

3914
    if (nvcpus > max) {
3915 3916 3917
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
                         " vcpus for the domain: %d > %d"), nvcpus, max);
3918 3919 3920
        goto endjob;
    }

3921
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
3922
        if (qemuDomainHotplugVcpus(driver, vm, nvcpus) < 0)
3923 3924 3925 3926
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
3927 3928 3929 3930 3931 3932 3933
        if (maximum) {
            persistentDef->maxvcpus = nvcpus;
            if (nvcpus < persistentDef->vcpus)
                persistentDef->vcpus = nvcpus;
        } else {
            persistentDef->vcpus = nvcpus;
        }
3934

3935 3936
        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            goto endjob;
3937
    }
3938

3939
    ret = 0;
3940

3941
endjob:
3942
    if (qemuDomainObjEndJob(driver, vm) == 0)
3943
        vm = NULL;
3944

3945
cleanup:
3946
    if (vm)
3947
        virObjectUnlock(vm);
3948
    return ret;
3949 3950
}

3951
static int
3952
qemuDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
3953
{
3954
    return qemuDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
3955 3956
}

3957 3958

static int
3959 3960 3961 3962 3963
qemuDomainPinVcpuFlags(virDomainPtr dom,
                       unsigned int vcpu,
                       unsigned char *cpumap,
                       int maplen,
                       unsigned int flags) {
3964

3965
    virQEMUDriverPtr driver = dom->conn->privateData;
3966
    virDomainObjPtr vm;
3967
    virDomainDefPtr persistentDef = NULL;
3968 3969
    virCgroupPtr cgroup_dom = NULL;
    virCgroupPtr cgroup_vcpu = NULL;
3970
    int ret = -1;
3971
    qemuDomainObjPrivatePtr priv;
3972
    bool doReset = false;
3973 3974
    int newVcpuPinNum = 0;
    virDomainVcpuPinDefPtr *newVcpuPin = NULL;
3975
    virBitmapPtr pcpumap = NULL;
3976

3977 3978 3979
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

3980
    if (!(vm = qemuDomObjFromDomain(dom)))
3981 3982
        goto cleanup;

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

3987 3988 3989
    priv = vm->privateData;

    if (vcpu > (priv->nvcpupids-1)) {
3990 3991 3992
        virReportError(VIR_ERR_INVALID_ARG,
                       _("vcpu number out of range %d > %d"),
                       vcpu, priv->nvcpupids);
3993
        goto cleanup;
3994 3995
    }

3996 3997 3998 3999
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

4000 4001 4002
    /* pinning to all physical cpus means resetting,
     * so check if we can reset setting.
     */
4003 4004
    if (virBitmapIsAllSet(pcpumap))
        doReset = true;
4005

4006
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4007

4008
        if (priv->vcpupids == NULL) {
4009 4010
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cpu affinity is not supported"));
4011 4012 4013
            goto cleanup;
        }

4014 4015 4016 4017 4018 4019 4020 4021 4022 4023 4024 4025 4026 4027 4028
        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;
        }

4029
        if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, vcpu) < 0) {
4030 4031
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("failed to update vcpupin"));
H
Hu Tao 已提交
4032
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
4033 4034 4035 4036 4037 4038 4039 4040 4041 4042 4043
            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);
4044 4045 4046
                goto cleanup;
            }
        } else {
4047
            if (virProcessSetAffinity(priv->vcpupids[vcpu], pcpumap) < 0) {
4048 4049 4050 4051
                virReportError(VIR_ERR_SYSTEM_ERROR,
                               _("failed to set cpu affinity for vcpu %d"),
                               vcpu);
                goto cleanup;
H
Hu Tao 已提交
4052
            }
4053 4054
        }

4055
        if (doReset) {
4056
            if (virDomainVcpuPinDel(vm->def, vcpu) < 0) {
4057
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4058
                               _("failed to delete vcpupin xml of "
4059
                                 "a running domain"));
4060 4061
                goto cleanup;
            }
4062 4063
        } else {
            if (vm->def->cputune.vcpupin)
H
Hu Tao 已提交
4064
                virDomainVcpuPinDefArrayFree(vm->def->cputune.vcpupin, vm->def->cputune.nvcpupin);
4065 4066 4067 4068

            vm->def->cputune.vcpupin = newVcpuPin;
            vm->def->cputune.nvcpupin = newVcpuPinNum;
            newVcpuPin = NULL;
4069 4070
        }

4071
        if (newVcpuPin)
H
Hu Tao 已提交
4072
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
4073

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

4078 4079
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

4080
        if (doReset) {
E
Eric Blake 已提交
4081
            if (virDomainVcpuPinDel(persistentDef, vcpu) < 0) {
4082 4083 4084
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to delete vcpupin xml of "
                                 "a persistent domain"));
4085 4086 4087
                goto cleanup;
            }
        } else {
H
Hu Tao 已提交
4088 4089 4090 4091 4092 4093 4094
            if (!persistentDef->cputune.vcpupin) {
                if (VIR_ALLOC(persistentDef->cputune.vcpupin) < 0) {
                    virReportOOMError();
                    goto cleanup;
                }
                persistentDef->cputune.nvcpupin = 0;
            }
4095
            if (virDomainVcpuPinAdd(&persistentDef->cputune.vcpupin,
H
Hu Tao 已提交
4096 4097 4098 4099
                                    &persistentDef->cputune.nvcpupin,
                                    cpumap,
                                    maplen,
                                    vcpu) < 0) {
4100 4101 4102
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update or add vcpupin xml of "
                                 "a persistent domain"));
4103 4104
                goto cleanup;
            }
4105
        }
4106

4107
        ret = virDomainSaveConfig(driver->configDir, persistentDef);
4108 4109 4110
        goto cleanup;
    }

4111
    ret = 0;
4112

4113
cleanup:
4114 4115 4116 4117
    if (cgroup_vcpu)
        virCgroupFree(&cgroup_vcpu);
    if (cgroup_dom)
        virCgroupFree(&cgroup_dom);
4118
    if (vm)
4119
        virObjectUnlock(vm);
4120
    virBitmapFree(pcpumap);
4121
    return ret;
4122 4123
}

4124
static int
4125
qemuDomainPinVcpu(virDomainPtr dom,
4126 4127 4128
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
4129 4130
    return qemuDomainPinVcpuFlags(dom, vcpu, cpumap, maplen,
                                  VIR_DOMAIN_AFFECT_LIVE);
4131 4132
}

4133
static int
4134 4135 4136 4137 4138
qemuDomainGetVcpuPinInfo(virDomainPtr dom,
                         int ncpumaps,
                         unsigned char *cpumaps,
                         int maplen,
                         unsigned int flags) {
4139

4140
    virQEMUDriverPtr driver = dom->conn->privateData;
E
Eric Blake 已提交
4141
    virDomainObjPtr vm = NULL;
4142 4143 4144 4145
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    int maxcpu, hostcpus, vcpu, pcpu;
    int n;
E
Eric Blake 已提交
4146
    virDomainVcpuPinDefPtr *vcpupin_list;
H
Hu Tao 已提交
4147
    virBitmapPtr cpumask = NULL;
4148
    unsigned char *cpumap;
H
Hu Tao 已提交
4149
    bool pinned;
4150 4151 4152 4153

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4154
    if (!(vm = qemuDomObjFromDomain(dom)))
4155 4156
        goto cleanup;

4157 4158 4159
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &targetDef) < 0)
        goto cleanup;
4160 4161 4162 4163 4164

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

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

4168
    if ((hostcpus = nodeGetCPUCount()) < 0)
4169
        goto cleanup;
4170

4171 4172 4173 4174 4175 4176 4177 4178 4179 4180 4181 4182 4183 4184 4185 4186 4187 4188 4189 4190 4191 4192 4193 4194 4195 4196 4197 4198
    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 已提交
4199 4200 4201
            if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0)
                goto cleanup;
            if (!pinned)
4202 4203 4204 4205 4206 4207 4208
                VIR_UNUSE_CPU(cpumap, pcpu);
        }
    }
    ret = ncpumaps;

cleanup:
    if (vm)
4209
        virObjectUnlock(vm);
4210 4211 4212
    return ret;
}

H
Hu Tao 已提交
4213
static int
4214 4215 4216 4217
qemuDomainPinEmulator(virDomainPtr dom,
                      unsigned char *cpumap,
                      int maplen,
                      unsigned int flags)
H
Hu Tao 已提交
4218
{
4219
    virQEMUDriverPtr driver = dom->conn->privateData;
H
Hu Tao 已提交
4220 4221 4222 4223 4224 4225 4226
    virDomainObjPtr vm;
    virCgroupPtr cgroup_dom = NULL;
    virCgroupPtr cgroup_emulator = NULL;
    pid_t pid;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
4227
    bool doReset = false;
H
Hu Tao 已提交
4228 4229
    int newVcpuPinNum = 0;
    virDomainVcpuPinDefPtr *newVcpuPin = NULL;
4230
    virBitmapPtr pcpumap = NULL;
H
Hu Tao 已提交
4231 4232 4233 4234

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4235
    if (!(vm = qemuDomObjFromDomain(dom)))
H
Hu Tao 已提交
4236 4237
        goto cleanup;

4238 4239 4240 4241 4242 4243 4244
    if (vm->def->placement_mode == VIR_DOMAIN_CPU_PLACEMENT_MODE_AUTO) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("Changing affinity for emulator thread dynamically "
                         "is not allowed when CPU placement is 'auto'"));
        goto cleanup;
    }

H
Hu Tao 已提交
4245 4246 4247 4248 4249 4250
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
        goto cleanup;

    priv = vm->privateData;

4251 4252 4253 4254
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

H
Hu Tao 已提交
4255 4256 4257
    /* pinning to all physical cpus means resetting,
     * so check if we can reset setting.
     */
4258 4259
    if (virBitmapIsAllSet(pcpumap))
        doReset = true;
H
Hu Tao 已提交
4260 4261 4262 4263 4264 4265 4266 4267 4268 4269 4270

    pid = vm->pid;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {

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

4271
            if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, -1) < 0) {
H
Hu Tao 已提交
4272 4273
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update vcpupin"));
H
Hu Tao 已提交
4274
                virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
H
Hu Tao 已提交
4275 4276 4277 4278 4279 4280 4281 4282 4283 4284 4285 4286
                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) {
4287 4288
                        if (qemuSetupCgroupEmulatorPin(cgroup_emulator,
                                                       newVcpuPin[0]->cpumask) < 0) {
H
Hu Tao 已提交
4289 4290 4291 4292 4293 4294 4295 4296
                            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                           _("failed to set cpuset.cpus in cgroup"
                                             " for emulator threads"));
                            goto cleanup;
                        }
                    }
                }
            } else {
4297
                if (virProcessSetAffinity(pid, pcpumap) < 0) {
H
Hu Tao 已提交
4298 4299 4300 4301 4302 4303 4304
                    virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
                                   _("failed to set cpu affinity for "
                                     "emulator threads"));
                    goto cleanup;
                }
            }

4305
            if (doReset) {
H
Hu Tao 已提交
4306 4307 4308 4309 4310 4311 4312
                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 已提交
4313
                virDomainVcpuPinDefFree(vm->def->cputune.emulatorpin);
H
Hu Tao 已提交
4314 4315 4316 4317 4318
                vm->def->cputune.emulatorpin = newVcpuPin[0];
                VIR_FREE(newVcpuPin);
            }

            if (newVcpuPin)
H
Hu Tao 已提交
4319
                virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
H
Hu Tao 已提交
4320 4321 4322 4323 4324 4325 4326 4327 4328 4329 4330 4331
        } 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) {

4332
        if (doReset) {
H
Hu Tao 已提交
4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357 4358
            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);
4359
    virBitmapFree(pcpumap);
H
Hu Tao 已提交
4360 4361

    if (vm)
4362
        virObjectUnlock(vm);
H
Hu Tao 已提交
4363 4364 4365 4366
    return ret;
}

static int
4367 4368 4369 4370
qemuDomainGetEmulatorPinInfo(virDomainPtr dom,
                             unsigned char *cpumaps,
                             int maplen,
                             unsigned int flags)
H
Hu Tao 已提交
4371
{
4372
    virQEMUDriverPtr driver = dom->conn->privateData;
H
Hu Tao 已提交
4373 4374 4375 4376
    virDomainObjPtr vm = NULL;
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    int maxcpu, hostcpus, pcpu;
H
Hu Tao 已提交
4377 4378
    virBitmapPtr cpumask = NULL;
    bool pinned;
H
Hu Tao 已提交
4379 4380 4381 4382

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4383
    if (!(vm = qemuDomObjFromDomain(dom)))
H
Hu Tao 已提交
4384 4385 4386 4387 4388 4389 4390 4391 4392 4393 4394 4395
        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);

4396
    if ((hostcpus = nodeGetCPUCount()) < 0)
H
Hu Tao 已提交
4397
        goto cleanup;
4398

H
Hu Tao 已提交
4399 4400 4401 4402 4403 4404 4405 4406 4407 4408
    maxcpu = maplen * 8;
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;

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

4409 4410 4411 4412 4413
    if (targetDef->cputune.emulatorpin) {
        cpumask = targetDef->cputune.emulatorpin->cpumask;
    } else if (targetDef->cpumask) {
        cpumask = targetDef->cpumask;
    } else {
H
Hu Tao 已提交
4414 4415 4416 4417 4418
        ret = 0;
        goto cleanup;
    }

    for (pcpu = 0; pcpu < maxcpu; pcpu++) {
H
Hu Tao 已提交
4419 4420 4421
        if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0)
            goto cleanup;
        if (!pinned)
H
Hu Tao 已提交
4422 4423 4424 4425 4426 4427 4428
            VIR_UNUSE_CPU(cpumaps, pcpu);
    }

    ret = 1;

cleanup:
    if (vm)
4429
        virObjectUnlock(vm);
H
Hu Tao 已提交
4430 4431 4432
    return ret;
}

4433
static int
4434 4435 4436 4437 4438
qemuDomainGetVcpus(virDomainPtr dom,
                   virVcpuInfoPtr info,
                   int maxinfo,
                   unsigned char *cpumaps,
                   int maplen) {
4439
    virDomainObjPtr vm;
4440
    int i, v, maxcpu, hostcpus;
4441
    int ret = -1;
4442
    qemuDomainObjPrivatePtr priv;
4443

4444
    if (!(vm = qemuDomObjFromDomain(dom)))
4445 4446
        goto cleanup;

D
Daniel P. Berrange 已提交
4447
    if (!virDomainObjIsActive(vm)) {
4448 4449 4450
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s",
                       _("cannot list vcpu pinning for an inactive domain"));
4451
        goto cleanup;
4452 4453
    }

4454 4455
    priv = vm->privateData;

4456
    if ((hostcpus = nodeGetCPUCount()) < 0)
4457
        goto cleanup;
4458 4459

    maxcpu = maplen * 8;
4460 4461
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
4462 4463

    /* Clamp to actual number of vcpus */
4464 4465
    if (maxinfo > priv->nvcpupids)
        maxinfo = priv->nvcpupids;
4466

4467 4468 4469 4470 4471 4472
    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;
4473

4474
                if (priv->vcpupids != NULL &&
4475 4476 4477 4478 4479
                    qemuGetProcessInfo(&(info[i].cpuTime),
                                       &(info[i].cpu),
                                       NULL,
                                       vm->pid,
                                       priv->vcpupids[i]) < 0) {
4480
                    virReportSystemError(errno, "%s",
4481 4482 4483
                                         _("cannot get vCPU placement & pCPU time"));
                    goto cleanup;
                }
4484
            }
4485 4486
        }

4487 4488
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
4489
            if (priv->vcpupids != NULL) {
4490 4491
                for (v = 0 ; v < maxinfo ; v++) {
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);
4492 4493 4494
                    virBitmapPtr map = NULL;
                    unsigned char *tmpmap = NULL;
                    int tmpmapLen = 0;
4495

4496 4497
                    if (virProcessGetAffinity(priv->vcpupids[v],
                                              &map, maxcpu) < 0)
4498
                        goto cleanup;
4499 4500 4501 4502 4503 4504 4505
                    virBitmapToData(map, &tmpmap, &tmpmapLen);
                    if (tmpmapLen > maplen)
                        tmpmapLen = maplen;
                    memcpy(cpumap, tmpmap, tmpmapLen);

                    VIR_FREE(tmpmap);
                    virBitmapFree(map);
4506
                }
4507
            } else {
4508 4509
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("cpu affinity is not available"));
4510
                goto cleanup;
4511 4512 4513
            }
        }
    }
4514
    ret = maxinfo;
4515

4516
cleanup:
4517
    if (vm)
4518
        virObjectUnlock(vm);
4519
    return ret;
4520 4521 4522
}


4523
static int
4524
qemuDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
4525
{
4526
    virQEMUDriverPtr driver = dom->conn->privateData;
4527
    virDomainObjPtr vm;
4528
    virDomainDefPtr def;
4529
    int ret = -1;
4530

4531 4532
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
4533 4534
                  VIR_DOMAIN_VCPU_MAXIMUM, -1);

4535
    if (!(vm = qemuDomObjFromDomain(dom)))
4536
        goto cleanup;
4537

4538 4539
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags, &def) < 0)
        goto cleanup;
4540

4541
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4542
        def = vm->def;
4543 4544
    }

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

4547
cleanup:
4548
    if (vm)
4549
        virObjectUnlock(vm);
4550 4551 4552
    return ret;
}

4553
static int
4554
qemuDomainGetMaxVcpus(virDomainPtr dom)
4555
{
4556 4557
    return qemuDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
                                         VIR_DOMAIN_VCPU_MAXIMUM));
4558 4559
}

4560
static int qemuDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
4561
{
4562
    virQEMUDriverPtr driver = dom->conn->privateData;
4563 4564 4565 4566 4567 4568
    virDomainObjPtr vm;
    int ret = -1;

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

4569 4570
    memset(seclabel, 0, sizeof(*seclabel));

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

4579
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
4580 4581 4582
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
4583 4584 4585 4586 4587 4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599
        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 已提交
4600
    if (virDomainObjIsActive(vm)) {
4601
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
4602
                                              vm->def, vm->pid, seclabel) < 0) {
4603 4604
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to get security label"));
4605
            goto cleanup;
4606 4607 4608 4609 4610 4611 4612
        }
    }

    ret = 0;

cleanup:
    if (vm)
4613
        virObjectUnlock(vm);
4614
    qemuDriverUnlock(driver);
4615 4616 4617
    return ret;
}

M
Marcelo Cerri 已提交
4618 4619 4620
static int qemuDomainGetSecurityLabelList(virDomainPtr dom,
                                          virSecurityLabelPtr* seclabels)
{
4621
    virQEMUDriverPtr driver = dom->conn->privateData;
M
Marcelo Cerri 已提交
4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644
    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;
    }

    /*
4645
     * Check the comment in qemuDomainGetSecurityLabel function.
M
Marcelo Cerri 已提交
4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657 4658 4659 4660 4661 4662 4663 4664 4665 4666 4667 4668 4669 4670 4671 4672 4673 4674 4675 4676 4677 4678 4679 4680 4681 4682 4683 4684 4685
     */
    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)
4686
        virObjectUnlock(vm);
M
Marcelo Cerri 已提交
4687 4688 4689
    qemuDriverUnlock(driver);
    return ret;
}
4690 4691
static int qemuNodeGetSecurityModel(virConnectPtr conn,
                                    virSecurityModelPtr secmodel)
4692
{
4693
    virQEMUDriverPtr driver = conn->privateData;
4694
    char *p;
4695
    int ret = 0;
4696

4697
    qemuDriverLock(driver);
4698 4699
    memset(secmodel, 0, sizeof(*secmodel));

4700 4701 4702
    /* 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)
4703
        goto cleanup;
4704

4705
    p = driver->caps->host.secModels[0].model;
4706
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
4707 4708 4709
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security model string exceeds max %d bytes"),
                       VIR_SECURITY_MODEL_BUFLEN-1);
4710 4711
        ret = -1;
        goto cleanup;
4712 4713 4714
    }
    strcpy(secmodel->model, p);

4715
    p = driver->caps->host.secModels[0].doi;
4716
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
4717 4718 4719
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security DOI string exceeds max %d bytes"),
                       VIR_SECURITY_DOI_BUFLEN-1);
4720 4721
        ret = -1;
        goto cleanup;
4722 4723
    }
    strcpy(secmodel->doi, p);
4724 4725 4726 4727

cleanup:
    qemuDriverUnlock(driver);
    return ret;
4728 4729
}

E
Eric Blake 已提交
4730
/* Return -1 on most failures after raising error, -2 if edit was specified
4731 4732 4733
 * 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.  */
4734
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
4735
qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
4736 4737
                        const char *path,
                        virDomainDefPtr *ret_def,
4738
                        virQEMUSaveHeaderPtr ret_header,
J
Jiri Denemark 已提交
4739 4740
                        bool bypass_cache,
                        virFileWrapperFdPtr *wrapperFd,
4741 4742
                        const char *xmlin, int state, bool edit,
                        bool unlink_corrupt)
J
Jiri Denemark 已提交
4743
{
W
Wen Congyang 已提交
4744
    int fd = -1;
4745
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
4746 4747
    char *xml = NULL;
    virDomainDefPtr def = NULL;
4748
    int oflags = edit ? O_RDWR : O_RDONLY;
4749

4750
    if (bypass_cache) {
4751
        int directFlag = virFileDirectFdFlag();
4752
        if (directFlag < 0) {
4753 4754
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
4755 4756
            goto error;
        }
4757
        oflags |= directFlag;
4758
    }
4759

E
Eric Blake 已提交
4760 4761
    if ((fd = qemuOpenFile(driver, path, oflags, NULL, NULL)) < 0)
        goto error;
J
Jiri Denemark 已提交
4762 4763 4764
    if (bypass_cache &&
        !(*wrapperFd = virFileWrapperFdNew(&fd, path,
                                           VIR_FILE_WRAPPER_BYPASS_CACHE)))
4765
        goto error;
4766 4767

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
4768 4769 4770 4771 4772 4773 4774 4775 4776
        if (unlink_corrupt) {
            if (VIR_CLOSE(fd) < 0 || unlink(path) < 0) {
                virReportSystemError(errno,
                                     _("cannot remove corrupt file: %s"),
                                     path);
                goto error;
            }
            return -3;
        }
4777 4778
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to read qemu header"));
J
Jiri Denemark 已提交
4779
        goto error;
4780 4781
    }

4782
    if (memcmp(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic)) != 0) {
E
Eric Blake 已提交
4783 4784
        const char *msg = _("image magic is incorrect");

4785
        if (memcmp(header.magic, QEMU_SAVE_PARTIAL,
E
Eric Blake 已提交
4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797
                   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;
            }
        }
4798
        virReportError(VIR_ERR_OPERATION_FAILED, "%s", msg);
J
Jiri Denemark 已提交
4799
        goto error;
4800 4801
    }

4802
    if (header.version > QEMU_SAVE_VERSION) {
4803 4804 4805 4806
        /* convert endianess and try again */
        bswap_header(&header);
    }

4807
    if (header.version > QEMU_SAVE_VERSION) {
4808 4809
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("image version is not supported (%d > %d)"),
4810
                       header.version, QEMU_SAVE_VERSION);
J
Jiri Denemark 已提交
4811
        goto error;
4812 4813
    }

4814
    if (header.xml_len <= 0) {
4815 4816
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("invalid XML length: %d"), header.xml_len);
J
Jiri Denemark 已提交
4817
        goto error;
4818 4819
    }

4820 4821
    if (VIR_ALLOC_N(xml, header.xml_len) < 0) {
        virReportOOMError();
J
Jiri Denemark 已提交
4822
        goto error;
4823 4824 4825
    }

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
4826 4827
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to read XML"));
J
Jiri Denemark 已提交
4828
        goto error;
4829 4830
    }

4831 4832
    if (edit && STREQ(xml, xmlin) &&
        (state < 0 || state == header.was_running)) {
4833 4834 4835 4836 4837 4838 4839
        VIR_FREE(xml);
        if (VIR_CLOSE(fd) < 0) {
            virReportSystemError(errno, _("cannot close file: %s"), path);
            goto error;
        }
        return -2;
    }
4840 4841
    if (state >= 0)
        header.was_running = state;
4842

4843
    /* Create a domain from this XML */
4844
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
4845
                                        QEMU_EXPECTED_VIRT_TYPES,
4846
                                        VIR_DOMAIN_XML_INACTIVE)))
J
Jiri Denemark 已提交
4847
        goto error;
4848 4849 4850 4851 4852 4853 4854 4855 4856 4857 4858 4859 4860 4861
    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;
    }
4862

J
Jiri Denemark 已提交
4863
    VIR_FREE(xml);
4864

J
Jiri Denemark 已提交
4865 4866
    *ret_def = def;
    *ret_header = header;
4867

J
Jiri Denemark 已提交
4868
    return fd;
4869

J
Jiri Denemark 已提交
4870 4871 4872
error:
    virDomainDefFree(def);
    VIR_FREE(xml);
4873
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
4874 4875 4876 4877

    return -1;
}

4878 4879
static int ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(6)
qemuDomainSaveImageStartVM(virConnectPtr conn,
4880
                           virQEMUDriverPtr driver,
4881 4882
                           virDomainObjPtr vm,
                           int *fd,
4883
                           const virQEMUSaveHeaderPtr header,
4884 4885
                           const char *path,
                           bool start_paused)
J
Jiri Denemark 已提交
4886 4887 4888 4889
{
    int ret = -1;
    virDomainEventPtr event;
    int intermediatefd = -1;
4890
    virCommandPtr cmd = NULL;
J
Jiri Denemark 已提交
4891 4892

    if (header->version == 2) {
4893
        const char *prog = qemuSaveCompressionTypeToString(header->compressed);
4894
        if (prog == NULL) {
4895 4896 4897
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("Invalid compressed save format %d"),
                           header->compressed);
J
Jiri Denemark 已提交
4898
            goto out;
4899
        }
4900

4901
        if (header->compressed != QEMU_SAVE_FORMAT_RAW) {
4902
            cmd = virCommandNewArgList(prog, "-dc", NULL);
4903 4904
            intermediatefd = *fd;
            *fd = -1;
4905 4906 4907 4908 4909

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

            if (virCommandRunAsync(cmd, NULL) < 0) {
4910 4911 4912
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("Failed to start decompression binary %s"),
                               prog);
4913
                *fd = intermediatefd;
J
Jiri Denemark 已提交
4914
                goto out;
4915 4916 4917
            }
        }
    }
J
Jiri Denemark 已提交
4918

4919
    /* Set the migration source and start it up. */
4920 4921 4922
    ret = qemuProcessStart(conn, driver, vm, "stdio", *fd, path, NULL,
                           VIR_NETDEV_VPORT_PROFILE_OP_RESTORE,
                           VIR_QEMU_PROCESS_START_PAUSED);
J
Jiri Denemark 已提交
4923

4924
    if (intermediatefd != -1) {
4925
        if (ret < 0) {
4926 4927 4928
            /* if there was an error setting up qemu, the intermediate
             * process will wait forever to write to stdout, so we
             * must manually kill it.
4929 4930
             */
            VIR_FORCE_CLOSE(intermediatefd);
4931
            VIR_FORCE_CLOSE(*fd);
4932 4933
        }

4934 4935
        if (virCommandWait(cmd, NULL) < 0)
            ret = -1;
4936
    }
4937
    VIR_FORCE_CLOSE(intermediatefd);
J
Jiri Denemark 已提交
4938

4939 4940 4941
    if (VIR_CLOSE(*fd) < 0) {
        virReportSystemError(errno, _("cannot close file: %s"), path);
        ret = -1;
4942
    }
J
Jiri Denemark 已提交
4943

4944
    if (ret < 0) {
4945
        virDomainAuditStart(vm, "restored", false);
J
Jiri Denemark 已提交
4946
        goto out;
4947
    }
4948

4949 4950 4951
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
4952
    virDomainAuditStart(vm, "restored", true);
J
Jiri Denemark 已提交
4953 4954 4955
    if (event)
        qemuDomainEventQueue(driver, event);

4956

4957 4958
    /* If it was running before, resume it now unless caller requested pause. */
    if (header->was_running && !start_paused) {
J
Jiri Denemark 已提交
4959
        if (qemuProcessStartCPUs(driver, vm, conn,
4960 4961
                                 VIR_DOMAIN_RUNNING_RESTORED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
4962
            if (virGetLastError() == NULL)
4963 4964
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("failed to resume domain"));
J
Jiri Denemark 已提交
4965
            goto out;
4966
        }
4967 4968
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
J
Jiri Denemark 已提交
4969
            goto out;
4970
        }
4971 4972 4973 4974 4975 4976 4977 4978
    } 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);
4979
    }
J
Jiri Denemark 已提交
4980

4981
    ret = 0;
4982

J
Jiri Denemark 已提交
4983
out:
4984
    virCommandFree(cmd);
4985
    if (virSecurityManagerRestoreSavedStateLabel(driver->securityManager,
4986
                                                 vm->def, path) < 0)
4987 4988
        VIR_WARN("failed to restore save state label on %s", path);

J
Jiri Denemark 已提交
4989 4990 4991
    return ret;
}

4992
static int
4993 4994 4995 4996
qemuDomainRestoreFlags(virConnectPtr conn,
                       const char *path,
                       const char *dxml,
                       unsigned int flags)
4997
{
4998
    virQEMUDriverPtr driver = conn->privateData;
J
Jiri Denemark 已提交
4999 5000 5001 5002
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    int fd = -1;
    int ret = -1;
5003
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
5004
    virFileWrapperFdPtr wrapperFd = NULL;
5005
    int state = -1;
J
Jiri Denemark 已提交
5006

5007 5008 5009
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
5010

J
Jiri Denemark 已提交
5011 5012
    qemuDriverLock(driver);

5013 5014 5015 5016 5017
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

5018 5019
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
                                 (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
J
Jiri Denemark 已提交
5020
                                 &wrapperFd, dxml, state, false, false);
J
Jiri Denemark 已提交
5021 5022 5023 5024 5025 5026 5027 5028 5029
    if (fd < 0)
        goto cleanup;

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

    if (!(vm = virDomainAssignDef(driver->caps,
                                  &driver->domains,
                                  def, true))) {
5030
        /* virDomainAssignDef already set the error */
J
Jiri Denemark 已提交
5031 5032 5033 5034
        goto cleanup;
    }
    def = NULL;

5035
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
J
Jiri Denemark 已提交
5036 5037
        goto cleanup;

5038 5039
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     false);
J
Jiri Denemark 已提交
5040
    if (virFileWrapperFdClose(wrapperFd) < 0)
5041
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
5042

5043
    if (qemuDomainObjEndJob(driver, vm) == 0)
5044
        vm = NULL;
J
Jiri Denemark 已提交
5045
    else if (ret < 0 && !vm->persistent) {
5046
        qemuDomainRemoveInactive(driver, vm);
J
Jiri Denemark 已提交
5047 5048
        vm = NULL;
    }
5049

5050 5051
cleanup:
    virDomainDefFree(def);
5052
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
5053
    virFileWrapperFdFree(wrapperFd);
5054
    if (vm)
5055
        virObjectUnlock(vm);
5056
    qemuDriverUnlock(driver);
5057
    return ret;
D
Daniel P. Berrange 已提交
5058 5059
}

5060 5061 5062 5063 5064 5065 5066
static int
qemuDomainRestore(virConnectPtr conn,
                  const char *path)
{
    return qemuDomainRestoreFlags(conn, path, NULL, 0);
}

5067 5068 5069 5070
static char *
qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
                              unsigned int flags)
{
5071
    virQEMUDriverPtr driver = conn->privateData;
5072 5073 5074
    char *ret = NULL;
    virDomainDefPtr def = NULL;
    int fd = -1;
5075
    virQEMUSaveHeader header;
5076 5077 5078 5079 5080 5081 5082

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

    qemuDriverLock(driver);

    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
5083
                                 NULL, -1, false, false);
5084 5085 5086 5087

    if (fd < 0)
        goto cleanup;

5088
    ret = qemuDomainDefFormatXML(driver, def, flags);
5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100

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)
{
5101
    virQEMUDriverPtr driver = conn->privateData;
5102 5103 5104
    int ret = -1;
    virDomainDefPtr def = NULL;
    int fd = -1;
5105
    virQEMUSaveHeader header;
5106 5107
    char *xml = NULL;
    size_t len;
5108
    int state = -1;
5109

5110 5111
    virCheckFlags(VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
5112 5113 5114

    qemuDriverLock(driver);

5115 5116 5117 5118 5119
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

5120
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
5121
                                 dxml, state, true, false);
5122 5123 5124 5125 5126 5127 5128 5129

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

5130 5131
    xml = qemuDomainDefFormatXML(driver, def,
                                 VIR_DOMAIN_XML_INACTIVE |
5132 5133
                                 VIR_DOMAIN_XML_SECURE |
                                 VIR_DOMAIN_XML_MIGRATABLE);
5134 5135 5136 5137 5138
    if (!xml)
        goto cleanup;
    len = strlen(xml) + 1;

    if (len > header.xml_len) {
5139 5140
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("new xml too large to fit in file"));
5141 5142 5143 5144 5145 5146 5147
        goto cleanup;
    }
    if (VIR_EXPAND_N(xml, len, header.xml_len - len) < 0) {
        virReportOOMError();
        goto cleanup;
    }

5148
    if (lseek(fd, 0, SEEK_SET) != 0) {
5149 5150 5151
        virReportSystemError(errno, _("cannot seek in '%s'"), path);
        goto cleanup;
    }
5152 5153
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header) ||
        safewrite(fd, xml, len) != len ||
5154 5155 5156 5157 5158 5159 5160 5161 5162 5163 5164 5165 5166 5167 5168
        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 已提交
5169 5170
/* Return 0 on success, 1 if incomplete saved image was silently unlinked,
 * and -1 on failure with error raised.  */
5171 5172
static int
qemuDomainObjRestore(virConnectPtr conn,
5173
                     virQEMUDriverPtr driver,
5174
                     virDomainObjPtr vm,
5175
                     const char *path,
5176
                     bool start_paused,
5177
                     bool bypass_cache)
J
Jiri Denemark 已提交
5178 5179 5180 5181
{
    virDomainDefPtr def = NULL;
    int fd = -1;
    int ret = -1;
5182
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
5183
    virFileWrapperFdPtr wrapperFd = NULL;
J
Jiri Denemark 已提交
5184

5185
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
J
Jiri Denemark 已提交
5186
                                 bypass_cache, &wrapperFd, NULL, -1, false,
5187
                                 true);
E
Eric Blake 已提交
5188 5189 5190
    if (fd < 0) {
        if (fd == -3)
            ret = 1;
J
Jiri Denemark 已提交
5191
        goto cleanup;
E
Eric Blake 已提交
5192
    }
J
Jiri Denemark 已提交
5193 5194 5195 5196 5197 5198 5199

    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);
5200 5201 5202 5203 5204
        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 已提交
5205 5206 5207 5208 5209 5210
        goto cleanup;
    }

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

5211 5212
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     start_paused);
J
Jiri Denemark 已提交
5213
    if (virFileWrapperFdClose(wrapperFd) < 0)
5214
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
5215 5216 5217

cleanup:
    virDomainDefFree(def);
5218
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
5219
    virFileWrapperFdFree(wrapperFd);
J
Jiri Denemark 已提交
5220 5221 5222
    return ret;
}

D
Daniel P. Berrange 已提交
5223

5224
static char *qemuDomainGetXMLDesc(virDomainPtr dom,
5225 5226
                                  unsigned int flags)
{
5227
    virQEMUDriverPtr driver = dom->conn->privateData;
5228 5229
    virDomainObjPtr vm;
    char *ret = NULL;
5230
    unsigned long long balloon;
5231
    int err = 0;
5232
    qemuDomainObjPrivatePtr priv;
5233

5234
    /* Flags checked by virDomainDefFormat */
5235

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

D
Daniel P. Berrange 已提交
5239
    if (!vm) {
5240 5241
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5242 5243
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
5244
        goto cleanup;
D
Daniel P. Berrange 已提交
5245 5246
    }

5247 5248
    priv = vm->privateData;

5249 5250 5251
    /* Refresh current memory based on balloon info if supported */
    if ((vm->def->memballoon != NULL) &&
        (vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) &&
5252
        !qemuCapsGet(priv->caps, QEMU_CAPS_BALLOON_EVENT) &&
5253
        (virDomainObjIsActive(vm))) {
5254 5255
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
5256
        if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
5257
            if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_QUERY) < 0)
5258 5259
                goto cleanup;

5260
            if (!virDomainObjIsActive(vm)) {
5261 5262
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("domain is not running"));
5263 5264 5265
                goto endjob;
            }

5266
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
5267
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
5268
            qemuDomainObjExitMonitorWithDriver(driver, vm);
5269 5270

endjob:
5271
            if (qemuDomainObjEndJob(driver, vm) == 0) {
5272 5273 5274
                vm = NULL;
                goto cleanup;
            }
5275 5276 5277
            if (err < 0)
                goto cleanup;
            if (err > 0)
5278
                vm->def->mem.cur_balloon = balloon;
5279 5280
            /* err == 0 indicates no balloon support, so ignore it */
        }
5281
    }
5282

5283 5284 5285 5286
    if ((flags & VIR_DOMAIN_XML_MIGRATABLE))
        flags |= QEMU_DOMAIN_FORMAT_LIVE_FLAGS;

    ret = qemuDomainFormatXML(driver, vm, flags);
5287 5288

cleanup:
5289
    if (vm)
5290
        virObjectUnlock(vm);
5291
    qemuDriverUnlock(driver);
5292
    return ret;
D
Daniel P. Berrange 已提交
5293 5294 5295
}


5296 5297 5298
static char *qemuDomainXMLFromNative(virConnectPtr conn,
                                     const char *format,
                                     const char *config,
E
Eric Blake 已提交
5299 5300
                                     unsigned int flags)
{
5301
    virQEMUDriverPtr driver = conn->privateData;
5302 5303 5304
    virDomainDefPtr def = NULL;
    char *xml = NULL;

E
Eric Blake 已提交
5305 5306
    virCheckFlags(0, NULL);

5307
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
5308 5309
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), format);
5310 5311 5312
        goto cleanup;
    }

5313
    qemuDriverLock(driver);
5314 5315
    def = qemuParseCommandLineString(driver->caps, config,
                                     NULL, NULL, NULL);
5316
    qemuDriverUnlock(driver);
5317 5318 5319
    if (!def)
        goto cleanup;

5320 5321 5322 5323 5324 5325
    if (!def->name &&
        !(def->name = strdup("unnamed"))) {
        virReportOOMError();
        goto cleanup;
    }

5326
    xml = qemuDomainDefFormatXML(driver, def, VIR_DOMAIN_XML_INACTIVE);
5327 5328 5329 5330 5331 5332

cleanup:
    virDomainDefFree(def);
    return xml;
}

5333 5334 5335
static char *qemuDomainXMLToNative(virConnectPtr conn,
                                   const char *format,
                                   const char *xmlData,
E
Eric Blake 已提交
5336 5337
                                   unsigned int flags)
{
5338
    virQEMUDriverPtr driver = conn->privateData;
5339
    virDomainDefPtr def = NULL;
5340
    virDomainChrSourceDef monConfig;
5341
    qemuCapsPtr caps = NULL;
T
tangchen 已提交
5342
    bool monitor_json = false;
E
Eric Blake 已提交
5343
    virCommandPtr cmd = NULL;
5344 5345 5346
    char *ret = NULL;
    int i;

E
Eric Blake 已提交
5347 5348
    virCheckFlags(0, NULL);

5349 5350
    qemuDriverLock(driver);

5351
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
5352 5353
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), format);
5354 5355 5356
        goto cleanup;
    }

M
Matthias Bolte 已提交
5357 5358
    def = virDomainDefParseString(driver->caps, xmlData,
                                  QEMU_EXPECTED_VIRT_TYPES, 0);
5359 5360 5361
    if (!def)
        goto cleanup;

5362 5363 5364
    if (!(caps = qemuCapsCacheLookup(driver->capsCache, def->emulator)))
        goto cleanup;

5365 5366
    /* Since we're just exporting args, we can't do bridge/network/direct
     * setups, since libvirt will normally create TAP/macvtap devices
5367 5368 5369 5370 5371
     * 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];
5372
        int bootIndex = net->info.bootIndex;
5373 5374
        char *model = net->model;

5375 5376 5377 5378
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            int actualType = virDomainNetGetActualType(net);
            const char *brname;

5379
            VIR_FREE(net->data.network.name);
5380 5381 5382 5383 5384 5385 5386 5387 5388 5389 5390 5391
            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);

5392
                memset(net, 0, sizeof(*net));
5393 5394

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5395
                net->script = NULL;
5396 5397 5398 5399 5400 5401 5402
                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);
5403
                memset(net, 0, sizeof(*net));
5404 5405

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5406
                net->script = NULL;
5407 5408 5409 5410 5411
                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);
5412

5413
            memset(net, 0, sizeof(*net));
5414 5415

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5416
            net->script = NULL;
5417 5418 5419
            net->data.ethernet.dev = NULL;
            net->data.ethernet.ipaddr = NULL;
        } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
5420
            char *script = net->script;
5421 5422 5423
            char *brname = net->data.bridge.brname;
            char *ipaddr = net->data.bridge.ipaddr;

5424
            memset(net, 0, sizeof(*net));
5425 5426

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5427
            net->script = script;
5428 5429 5430
            net->data.ethernet.dev = brname;
            net->data.ethernet.ipaddr = ipaddr;
        }
5431

5432
        VIR_FREE(net->virtPortProfile);
5433
        net->info.bootIndex = bootIndex;
5434
        net->model = model;
5435 5436
    }

5437
    monitor_json = qemuCapsGet(caps, QEMU_CAPS_MONITOR_JSON);
T
tangchen 已提交
5438

5439
    if (qemuProcessPrepareMonitorChr(driver, &monConfig, def->name) < 0)
5440
        goto cleanup;
5441

5442
    if (qemuAssignDeviceAliases(def, caps) < 0)
5443 5444
        goto cleanup;

5445
    if (!(cmd = qemuBuildCommandLine(conn, driver, def,
5446
                                     &monConfig, monitor_json, caps,
5447
                                     NULL, -1, NULL, VIR_NETDEV_VPORT_PROFILE_OP_NO_OP)))
5448 5449
        goto cleanup;

E
Eric Blake 已提交
5450
    ret = virCommandToString(cmd);
5451 5452

cleanup:
5453
    qemuDriverUnlock(driver);
5454

5455
    virObjectUnref(caps);
E
Eric Blake 已提交
5456
    virCommandFree(cmd);
5457 5458 5459 5460 5461
    virDomainDefFree(def);
    return ret;
}


5462 5463
static int qemuListDefinedDomains(virConnectPtr conn,
                                  char **const names, int nnames) {
5464
    virQEMUDriverPtr driver = conn->privateData;
5465
    int n;
5466

5467
    qemuDriverLock(driver);
5468
    n = virDomainObjListGetInactiveNames(&driver->domains, names, nnames);
5469
    qemuDriverUnlock(driver);
5470
    return n;
D
Daniel P. Berrange 已提交
5471 5472
}

5473
static int qemuNumDefinedDomains(virConnectPtr conn) {
5474
    virQEMUDriverPtr driver = conn->privateData;
5475
    int n;
5476

5477
    qemuDriverLock(driver);
5478
    n = virDomainObjListNumOfDomains(&driver->domains, 0);
5479
    qemuDriverUnlock(driver);
5480

5481
    return n;
D
Daniel P. Berrange 已提交
5482 5483 5484
}


5485 5486
static int
qemuDomainObjStart(virConnectPtr conn,
5487
                   virQEMUDriverPtr driver,
5488
                   virDomainObjPtr vm,
5489
                   unsigned int flags)
J
Jiri Denemark 已提交
5490 5491 5492
{
    int ret = -1;
    char *managed_save;
5493 5494 5495 5496
    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;
5497 5498 5499 5500
    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 已提交
5501 5502 5503

    /*
     * If there is a managed saved state restore it instead of starting
5504
     * from scratch. The old state is removed once the restoring succeeded.
J
Jiri Denemark 已提交
5505 5506
     */
    managed_save = qemuDomainManagedSavePath(driver, vm);
5507 5508 5509 5510

    if (!managed_save)
        goto cleanup;

E
Eric Blake 已提交
5511
    if (virFileExists(managed_save)) {
5512 5513 5514 5515 5516 5517 5518 5519 5520
        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,
5521
                                       start_paused, bypass_cache);
J
Jiri Denemark 已提交
5522

5523 5524 5525 5526 5527 5528 5529
            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 已提交
5530 5531 5532 5533
            if (ret > 0)
                VIR_WARN("Ignoring incomplete managed state %s", managed_save);
            else
                goto cleanup;
5534
        }
J
Jiri Denemark 已提交
5535 5536
    }

5537 5538
    ret = qemuProcessStart(conn, driver, vm, NULL, -1, NULL, NULL,
                           VIR_NETDEV_VPORT_PROFILE_OP_CREATE, start_flags);
5539
    virDomainAuditStart(vm, "booted", ret >= 0);
5540
    if (ret >= 0) {
J
Jiri Denemark 已提交
5541 5542 5543 5544
        virDomainEventPtr event =
            virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
5545
        if (event) {
J
Jiri Denemark 已提交
5546
            qemuDomainEventQueue(driver, event);
5547 5548 5549 5550 5551 5552 5553 5554
            if (start_paused) {
                event = virDomainEventNewFromObj(vm,
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
                if (event)
                    qemuDomainEventQueue(driver, event);
            }
        }
J
Jiri Denemark 已提交
5555 5556 5557 5558 5559 5560 5561
    }

cleanup:
    VIR_FREE(managed_save);
    return ret;
}

5562
static int
5563
qemuDomainStartWithFlags(virDomainPtr dom, unsigned int flags)
5564
{
5565
    virQEMUDriverPtr driver = dom->conn->privateData;
5566 5567
    virDomainObjPtr vm;
    int ret = -1;
5568

5569
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
5570
                  VIR_DOMAIN_START_AUTODESTROY |
5571 5572
                  VIR_DOMAIN_START_BYPASS_CACHE |
                  VIR_DOMAIN_START_FORCE_BOOT, -1);
5573

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

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

5585
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
5586 5587 5588
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
5589 5590
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is already running"));
5591 5592 5593
        goto endjob;
    }

5594
    if (qemuDomainObjStart(dom->conn, driver, vm, flags) < 0)
5595 5596 5597
        goto endjob;

    ret = 0;
5598

5599
endjob:
5600
    if (qemuDomainObjEndJob(driver, vm) == 0)
5601
        vm = NULL;
5602

5603
cleanup:
5604
    if (vm)
5605
        virObjectUnlock(vm);
5606
    qemuDriverUnlock(driver);
5607
    return ret;
D
Daniel P. Berrange 已提交
5608 5609
}

5610
static int
5611
qemuDomainStart(virDomainPtr dom)
5612
{
5613
    return qemuDomainStartWithFlags(dom, 0);
5614 5615
}

5616
static virDomainPtr qemuDomainDefine(virConnectPtr conn, const char *xml) {
5617
    virQEMUDriverPtr driver = conn->privateData;
5618
    virDomainDefPtr def;
M
Michal Privoznik 已提交
5619
    virDomainDefPtr def_backup = NULL;
5620
    virDomainObjPtr vm = NULL;
5621
    virDomainPtr dom = NULL;
5622
    virDomainEventPtr event = NULL;
5623
    qemuCapsPtr caps = NULL;
5624
    int dupVM;
5625

5626
    qemuDriverLock(driver);
5627
    if (!(def = virDomainDefParseString(driver->caps, xml,
M
Matthias Bolte 已提交
5628
                                        QEMU_EXPECTED_VIRT_TYPES,
5629
                                        VIR_DOMAIN_XML_INACTIVE)))
5630
        goto cleanup;
5631

5632
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
5633 5634
        goto cleanup;

5635 5636
    if ((dupVM = virDomainObjIsDuplicate(&driver->domains, def, 0)) < 0)
        goto cleanup;
5637

5638 5639 5640
    if (!(caps = qemuCapsCacheLookup(driver->capsCache, def->emulator)))
        goto cleanup;

5641
    if (qemuCanonicalizeMachine(def, caps) < 0)
5642 5643
        goto cleanup;

5644
    if (qemuDomainAssignAddresses(def, caps, NULL) < 0)
5645 5646
        goto cleanup;

M
Michal Privoznik 已提交
5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665
    /* 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;
        }
5666
    }
5667
    def = NULL;
E
Eric Blake 已提交
5668 5669 5670 5671 5672 5673
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
        virDomainObjAssignDef(vm, NULL, false);
        goto cleanup;
    }
5674
    vm->persistent = 1;
5675

5676
    if (virDomainSaveConfig(driver->configDir,
5677
                            vm->newDef ? vm->newDef : vm->def) < 0) {
M
Michal Privoznik 已提交
5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691
        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;
        }
5692
        goto cleanup;
M
Michal Privoznik 已提交
5693 5694
    } else {
        virDomainDefFree(def_backup);
5695 5696
    }

5697 5698
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_DEFINED,
5699
                                     !dupVM ?
5700 5701
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
5702

5703
    VIR_INFO("Creating domain '%s'", vm->def->name);
5704
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
5705
    if (dom) dom->id = vm->def->id;
5706 5707

cleanup:
5708
    virDomainDefFree(def);
5709
    if (vm)
5710
        virObjectUnlock(vm);
5711 5712
    if (event)
        qemuDomainEventQueue(driver, event);
5713
    virObjectUnref(caps);
5714
    qemuDriverUnlock(driver);
5715
    return dom;
D
Daniel P. Berrange 已提交
5716 5717
}

5718 5719
static int
qemuDomainUndefineFlags(virDomainPtr dom,
5720
                        unsigned int flags)
5721
{
5722
    virQEMUDriverPtr driver = dom->conn->privateData;
5723
    virDomainObjPtr vm;
5724
    virDomainEventPtr event = NULL;
5725
    char *name = NULL;
5726
    int ret = -1;
5727
    int nsnapshots;
D
Daniel P. Berrange 已提交
5728

5729 5730
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
                  VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
5731

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

D
Daniel P. Berrange 已提交
5735
    if (!vm) {
5736 5737
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
5738 5739
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
5740
        goto cleanup;
D
Daniel P. Berrange 已提交
5741 5742
    }

5743
    if (!vm->persistent) {
5744 5745
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
5746 5747 5748
        goto cleanup;
    }

5749
    if (!virDomainObjIsActive(vm) &&
5750
        (nsnapshots = virDomainSnapshotObjListNum(vm->snapshots, NULL, 0))) {
5751
        if (!(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
5752 5753 5754 5755
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("cannot delete inactive domain with %d "
                             "snapshots"),
                           nsnapshots);
5756 5757
            goto cleanup;
        }
5758
        if (qemuDomainSnapshotDiscardAllMetadata(driver, vm) < 0)
5759
            goto cleanup;
5760 5761
    }

5762 5763 5764 5765 5766 5767 5768
    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    if (virFileExists(name)) {
        if (flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE) {
            if (unlink(name) < 0) {
5769 5770 5771
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to remove domain managed "
                                 "save image"));
5772 5773 5774
                goto cleanup;
            }
        } else {
5775 5776 5777
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Refusing to undefine while domain managed "
                             "save image exists"));
5778 5779 5780 5781
            goto cleanup;
        }
    }

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

5785 5786 5787
    event = virDomainEventNewFromObj(vm,
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
5788

5789
    VIR_INFO("Undefining domain '%s'", vm->def->name);
5790 5791 5792 5793 5794 5795 5796 5797

    /* 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 {
5798
        qemuDomainRemoveInactive(driver, vm);
5799 5800 5801
        vm = NULL;
    }

5802
    ret = 0;
D
Daniel P. Berrange 已提交
5803

5804
cleanup:
5805
    VIR_FREE(name);
5806
    if (vm)
5807
        virObjectUnlock(vm);
5808 5809
    if (event)
        qemuDomainEventQueue(driver, event);
5810
    qemuDriverUnlock(driver);
5811
    return ret;
D
Daniel P. Berrange 已提交
5812 5813
}

5814
static int
5815
qemuDomainUndefine(virDomainPtr dom)
5816 5817 5818 5819
{
    return qemuDomainUndefineFlags(dom, 0);
}

5820
static int
5821
qemuDomainAttachDeviceDiskLive(virConnectPtr conn,
5822
                               virQEMUDriverPtr driver,
5823
                               virDomainObjPtr vm,
5824
                               virDomainDeviceDefPtr dev)
5825 5826 5827 5828
{
    virDomainDiskDefPtr disk = dev->data.disk;
    virCgroupPtr cgroup = NULL;
    int ret = -1;
5829

5830
    if (disk->driverName != NULL && !STREQ(disk->driverName, "qemu")) {
5831 5832 5833
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("unsupported driver name '%s' for disk '%s'"),
                       disk->driverName, disk->src);
5834 5835 5836
        goto end;
    }

5837 5838 5839 5840 5841
    if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
        disk->shared &&
        (qemuCheckSharedDisk(driver->sharedDisks, disk) < 0))
        goto end;

5842 5843 5844
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
        goto end;

5845 5846
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0)) {
5847 5848 5849
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to find cgroup for %s"),
                           vm->def->name);
5850 5851
            goto end;
        }
5852
        if (qemuSetupDiskCgroup(vm, cgroup, disk) < 0)
5853 5854 5855 5856 5857
            goto end;
    }
    switch (disk->device)  {
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
5858
        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, false);
5859 5860
        break;
    case VIR_DOMAIN_DISK_DEVICE_DISK:
5861
    case VIR_DOMAIN_DISK_DEVICE_LUN:
5862 5863
        if (disk->bus == VIR_DOMAIN_DISK_BUS_USB) {
            if (disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
5864 5865
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("disk device='lun' is not supported for usb bus"));
5866 5867
                break;
            }
5868
            ret = qemuDomainAttachUsbMassstorageDevice(conn, driver, vm,
5869
                                                       disk);
5870
        } else if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO) {
5871
            ret = qemuDomainAttachPciDiskDevice(conn, driver, vm, disk);
5872
        } else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI) {
5873
            ret = qemuDomainAttachSCSIDisk(conn, driver, vm, disk);
5874
        } else {
5875 5876 5877
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("disk bus '%s' cannot be hotplugged."),
                           virDomainDiskBusTypeToString(disk->bus));
5878
        }
5879 5880
        break;
    default:
5881 5882 5883
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk device type '%s' cannot be hotplugged"),
                       virDomainDiskDeviceTypeToString(disk->device));
5884 5885 5886 5887
        break;
    }

    if (ret != 0 && cgroup) {
5888
        if (qemuTeardownDiskCgroup(vm, cgroup, disk) < 0)
5889 5890 5891
            VIR_WARN("Failed to teardown cgroup for disk path %s",
                     NULLSTR(disk->src));
    }
5892

5893 5894 5895 5896 5897 5898 5899 5900 5901
    if (ret == 0) {
        if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK && disk->shared) {
            if (qemuAddSharedDisk(driver->sharedDisks, disk->src) < 0)
                VIR_WARN("Failed to add disk '%s' to shared disk table",
                         disk->src);
        }

        if (qemuSetUnprivSGIO(disk) < 0)
            VIR_WARN("Failed to set unpriv_sgio of disk '%s'", disk->src);
5902 5903
    }

5904 5905 5906 5907 5908 5909 5910
end:
    if (cgroup)
        virCgroupFree(&cgroup);
    return ret;
}

static int
5911
qemuDomainAttachDeviceControllerLive(virQEMUDriverPtr driver,
5912
                                     virDomainObjPtr vm,
5913
                                     virDomainDeviceDefPtr dev)
5914 5915 5916 5917 5918 5919
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
5920
        ret = qemuDomainAttachPciControllerDevice(driver, vm, cont);
5921 5922
        break;
    default:
5923 5924 5925
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk controller bus '%s' cannot be hotplugged."),
                       virDomainControllerTypeToString(cont->type));
5926 5927 5928 5929 5930 5931 5932 5933
        break;
    }
    return ret;
}

static int
qemuDomainAttachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
5934
                           virDomainPtr dom)
5935
{
5936
    virQEMUDriverPtr driver = dom->conn->privateData;
5937 5938 5939 5940
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
5941
        qemuDomainObjCheckDiskTaint(driver, vm, dev->data.disk, -1);
5942
        ret = qemuDomainAttachDeviceDiskLive(dom->conn, driver, vm, dev);
5943 5944 5945 5946 5947
        if (!ret)
            dev->data.disk = NULL;
        break;

    case VIR_DOMAIN_DEVICE_CONTROLLER:
5948
        ret = qemuDomainAttachDeviceControllerLive(driver, vm, dev);
5949 5950 5951 5952
        if (!ret)
            dev->data.controller = NULL;
        break;

5953 5954 5955 5956 5957 5958 5959
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainAttachLease(driver, vm,
                                    dev->data.lease);
        if (ret == 0)
            dev->data.lease = NULL;
        break;

5960
    case VIR_DOMAIN_DEVICE_NET:
5961
        qemuDomainObjCheckNetTaint(driver, vm, dev->data.net, -1);
5962
        ret = qemuDomainAttachNetDevice(dom->conn, driver, vm,
5963
                                        dev->data.net);
5964 5965 5966 5967 5968 5969
        if (!ret)
            dev->data.net = NULL;
        break;

    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = qemuDomainAttachHostDevice(driver, vm,
5970
                                         dev->data.hostdev);
5971 5972 5973 5974
        if (!ret)
            dev->data.hostdev = NULL;
        break;

5975 5976 5977 5978 5979 5980 5981
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        ret = qemuDomainAttachRedirdevDevice(driver, vm,
                                             dev->data.redirdev);
        if (!ret)
            dev->data.redirdev = NULL;
        break;

5982
    default:
5983 5984 5985
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be attached"),
                       virDomainDeviceTypeToString(dev->type));
5986 5987 5988 5989 5990 5991 5992
        break;
    }

    return ret;
}

static int
5993
qemuDomainDetachDeviceDiskLive(virQEMUDriverPtr driver,
5994
                               virDomainObjPtr vm,
5995
                               virDomainDeviceDefPtr dev)
5996 5997 5998 5999 6000 6001
{
    virDomainDiskDefPtr disk = dev->data.disk;
    int ret = -1;

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_DISK:
6002
    case VIR_DOMAIN_DISK_DEVICE_LUN:
6003
        if (disk->bus == VIR_DOMAIN_DISK_BUS_VIRTIO)
6004
            ret = qemuDomainDetachPciDiskDevice(driver, vm, dev);
O
Osier Yang 已提交
6005 6006
        else if (disk->bus == VIR_DOMAIN_DISK_BUS_SCSI ||
                 disk->bus == VIR_DOMAIN_DISK_BUS_USB)
6007
            ret = qemuDomainDetachDiskDevice(driver, vm, dev);
6008
        else
6009 6010
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("This type of disk cannot be hot unplugged"));
6011 6012
        break;
    default:
6013 6014 6015
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk device type '%s' cannot be detached"),
                       virDomainDiskDeviceTypeToString(disk->type));
6016 6017
        break;
    }
6018 6019 6020 6021 6022 6023 6024 6025 6026

    if (ret == 0 &&
        disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
        disk->shared) {
        if (qemuRemoveSharedDisk(driver->sharedDisks, disk->src) < 0)
             VIR_WARN("Failed to remove disk '%s' from shared disk table",
                      disk->src);
    }

6027 6028 6029 6030
    return ret;
}

static int
6031
qemuDomainDetachDeviceControllerLive(virQEMUDriverPtr driver,
6032
                                     virDomainObjPtr vm,
6033
                                     virDomainDeviceDefPtr dev)
6034 6035 6036 6037 6038 6039
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
6040
        ret = qemuDomainDetachPciControllerDevice(driver, vm, dev);
6041 6042
        break;
    default :
6043 6044 6045
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk controller bus '%s' cannot be hotunplugged."),
                       virDomainControllerTypeToString(cont->type));
6046 6047 6048 6049 6050 6051 6052
    }
    return ret;
}

static int
qemuDomainDetachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
6053
                           virDomainPtr dom)
6054
{
6055
    virQEMUDriverPtr driver = dom->conn->privateData;
6056 6057 6058 6059
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
6060
        ret = qemuDomainDetachDeviceDiskLive(driver, vm, dev);
6061 6062
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
6063
        ret = qemuDomainDetachDeviceControllerLive(driver, vm, dev);
6064
        break;
6065 6066 6067
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainDetachLease(driver, vm, dev->data.lease);
        break;
6068
    case VIR_DOMAIN_DEVICE_NET:
6069
        ret = qemuDomainDetachNetDevice(driver, vm, dev);
6070 6071
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
6072
        ret = qemuDomainDetachHostDevice(driver, vm, dev);
6073 6074
        break;
    default:
6075 6076
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       "%s", _("This type of device cannot be hot unplugged"));
6077 6078 6079 6080 6081 6082
        break;
    }

    return ret;
}

6083 6084 6085
static int
qemuDomainChangeDiskMediaLive(virDomainObjPtr vm,
                              virDomainDeviceDefPtr dev,
6086
                              virQEMUDriverPtr driver,
6087 6088 6089 6090
                              bool force)
{
    virDomainDiskDefPtr disk = dev->data.disk;
    virCgroupPtr cgroup = NULL;
6091
    int ret = -1;
6092

6093 6094 6095
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
        goto end;

6096 6097
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES)) {
        if (virCgroupForDomain(driver->cgroup,
6098
                               vm->def->name, &cgroup, 0) != 0) {
6099 6100 6101
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("Unable to find cgroup for %s"),
                           vm->def->name);
6102 6103
            goto end;
        }
6104
        if (qemuSetupDiskCgroup(vm, cgroup, disk) < 0)
6105 6106 6107 6108 6109 6110
            goto end;
    }

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
6111
        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, force);
6112 6113 6114 6115
        if (ret == 0)
            dev->data.disk = NULL;
        break;
    default:
6116 6117 6118
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk bus '%s' cannot be updated."),
                       virDomainDiskBusTypeToString(disk->bus));
6119 6120 6121 6122
        break;
    }

    if (ret != 0 && cgroup) {
6123
        if (qemuTeardownDiskCgroup(vm, cgroup, disk) < 0)
6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 6136 6137 6138
             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)
{
6139
    virQEMUDriverPtr driver = dom->conn->privateData;
6140 6141 6142 6143
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
6144
        ret = qemuDomainChangeDiskMediaLive(vm, dev, driver, force);
6145 6146 6147 6148
        break;
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
        break;
6149
    case VIR_DOMAIN_DEVICE_NET:
6150
        ret = qemuDomainChangeNet(driver, vm, dom, dev);
6151
        break;
6152
    default:
6153 6154 6155
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("device type '%s' cannot be updated"),
                       virDomainDeviceTypeToString(dev->type));
6156 6157 6158 6159 6160 6161
        break;
    }

    return ret;
}

6162
static int
6163 6164
qemuDomainAttachDeviceConfig(qemuCapsPtr caps,
                             virDomainDefPtr vmdef,
6165 6166
                             virDomainDeviceDefPtr dev)
{
6167
    virDomainDiskDefPtr disk;
6168
    virDomainNetDefPtr net;
6169
    virDomainHostdevDefPtr hostdev;
6170
    virDomainLeaseDefPtr lease;
6171
    virDomainControllerDefPtr controller;
6172

6173
    switch (dev->type) {
6174 6175
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6176
        if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
6177 6178
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("target %s already exists"), disk->dst);
6179 6180 6181 6182 6183 6184 6185 6186 6187 6188 6189
            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;
6190
        if (qemuDomainAssignAddresses(vmdef, caps, NULL) < 0)
6191 6192 6193
            return -1;
        break;

6194 6195 6196 6197 6198 6199 6200
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
        if (virDomainNetInsert(vmdef, net)) {
            virReportOOMError();
            return -1;
        }
        dev->data.net = NULL;
6201
        if (qemuDomainAssignAddresses(vmdef, caps, NULL) < 0)
6202 6203
            return -1;
        break;
6204

6205 6206 6207
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        hostdev = dev->data.hostdev;
        if (virDomainHostdevFind(vmdef, hostdev, NULL) >= 0) {
6208
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6209
                           _("device is already in the domain configuration"));
6210 6211 6212 6213 6214 6215 6216
            return -1;
        }
        if (virDomainHostdevInsert(vmdef, hostdev)) {
            virReportOOMError();
            return -1;
        }
        dev->data.hostdev = NULL;
6217
        if (qemuDomainAssignAddresses(vmdef, caps, NULL) < 0)
6218 6219 6220
            return -1;
        break;

6221 6222 6223
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
        if (virDomainLeaseIndex(vmdef, lease) >= 0) {
6224
            virReportError(VIR_ERR_OPERATION_INVALID,
6225 6226
                           _("Lease %s in lockspace %s already exists"),
                           lease->key, NULLSTR(lease->lockspace));
6227 6228 6229 6230 6231 6232 6233 6234 6235
            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;

6236 6237 6238 6239
    case VIR_DOMAIN_DEVICE_CONTROLLER:
        controller = dev->data.controller;
        if (virDomainControllerFind(vmdef, controller->type,
                                    controller->idx) > 0) {
6240
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6241 6242 6243 6244 6245 6246 6247 6248
                           _("Target already exists"));
            return -1;
        }

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

6249
        if (qemuDomainAssignAddresses(vmdef, caps, NULL) < 0)
6250 6251 6252
            return -1;
        break;

6253
    default:
6254 6255
         virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                        _("persistent attach of device is not supported"));
6256 6257 6258 6259 6260 6261 6262
         return -1;
    }
    return 0;
}


static int
6263
qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
6264 6265
                             virDomainDeviceDefPtr dev)
{
6266
    virDomainDiskDefPtr disk, det_disk;
6267
    virDomainNetDefPtr net;
6268
    virDomainHostdevDefPtr hostdev, det_hostdev;
6269
    virDomainLeaseDefPtr lease, det_lease;
6270 6271
    virDomainControllerDefPtr cont, det_cont;
    int idx;
6272
    char mac[VIR_MAC_STRING_BUFLEN];
6273

6274
    switch (dev->type) {
6275 6276
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6277
        if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) {
6278 6279
            virReportError(VIR_ERR_INVALID_ARG,
                           _("no target device %s"), disk->dst);
6280 6281
            return -1;
        }
6282
        virDomainDiskDefFree(det_disk);
6283
        break;
6284

6285 6286
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
6287 6288 6289 6290 6291 6292 6293 6294 6295
        idx = virDomainNetFindIdx(vmdef, net);
        if (idx == -2) {
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("multiple devices matching mac address %s found"),
                           virMacAddrFormat(&net->mac, mac));
            return -1;
        } else if (idx < 0) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("no matching network device was found"));
6296 6297
            return -1;
        }
6298 6299
        /* this is guaranteed to succeed */
        virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
6300
        break;
6301

6302 6303 6304
    case VIR_DOMAIN_DEVICE_HOSTDEV: {
        hostdev = dev->data.hostdev;
        if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) {
6305 6306
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("device not present in domain configuration"));
6307 6308 6309 6310 6311 6312 6313
            return -1;
        }
        virDomainHostdevRemove(vmdef, idx);
        virDomainHostdevDefFree(det_hostdev);
        break;
    }

6314 6315
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
6316
        if (!(det_lease = virDomainLeaseRemove(vmdef, lease))) {
6317 6318 6319
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Lease %s in lockspace %s does not exist"),
                           lease->key, NULLSTR(lease->lockspace));
6320 6321
            return -1;
        }
6322
        virDomainLeaseDefFree(det_lease);
6323 6324
        break;

6325 6326 6327 6328 6329 6330 6331 6332 6333 6334 6335 6336 6337
    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;

6338
    default:
6339 6340
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent detach of device is not supported"));
6341 6342 6343 6344 6345 6346
        return -1;
    }
    return 0;
}

static int
6347 6348
qemuDomainUpdateDeviceConfig(qemuCapsPtr caps,
                             virDomainDefPtr vmdef,
6349 6350
                             virDomainDeviceDefPtr dev)
{
6351
    virDomainDiskDefPtr orig, disk;
6352
    virDomainNetDefPtr net;
6353
    int pos;
6354 6355
    char mac[VIR_MAC_STRING_BUFLEN];

6356

6357
    switch (dev->type) {
6358 6359
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6360
        pos = virDomainDiskIndexByName(vmdef, disk->dst, false);
6361
        if (pos < 0) {
6362 6363
            virReportError(VIR_ERR_INVALID_ARG,
                           _("target %s doesn't exist."), disk->dst);
6364 6365 6366 6367 6368
            return -1;
        }
        orig = vmdef->disks[pos];
        if (!(orig->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
            !(orig->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)) {
6369 6370
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("this disk doesn't support update"));
6371 6372 6373 6374 6375 6376 6377 6378 6379 6380 6381 6382 6383 6384 6385
            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;
        }
6386 6387
        if (disk->format)
            orig->format = disk->format;
6388 6389
        disk->src = NULL;
        break;
6390 6391 6392

    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
6393 6394 6395 6396 6397 6398 6399 6400 6401 6402 6403 6404
        pos = virDomainNetFindIdx(vmdef, net);
        if (pos == -2) {
            virMacAddrFormat(&net->mac, mac);
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("couldn't find matching device "
                             "with mac address %s"), mac);
            return -1;
        } else if (pos < 0) {
            virMacAddrFormat(&net->mac, mac);
            virReportError(VIR_ERR_OPERATION_FAILED,
                           _("couldn't find matching device "
                             "with mac address %s"), mac);
6405 6406 6407
            return -1;
        }

6408
        virDomainNetDefFree(vmdef->nets[pos]);
6409 6410 6411 6412

        vmdef->nets[pos] = net;
        dev->data.net = NULL;

6413
        if (qemuDomainAssignAddresses(vmdef, caps, NULL) < 0)
6414 6415 6416
            return -1;
        break;

6417
    default:
6418 6419
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("persistent update of device is not supported"));
6420 6421 6422 6423 6424
        return -1;
    }
    return 0;
}

6425 6426 6427 6428 6429 6430 6431 6432 6433 6434 6435
/* 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)
6436
{
6437
    virQEMUDriverPtr driver = dom->conn->privateData;
6438
    virDomainObjPtr vm = NULL;
6439
    virDomainDefPtr vmdef = NULL;
6440
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
6441
    bool force = (flags & VIR_DOMAIN_DEVICE_MODIFY_FORCE) != 0;
6442
    int ret = -1;
6443
    unsigned int affect;
6444 6445
    qemuCapsPtr caps = NULL;
    qemuDomainObjPrivatePtr priv;
6446

6447 6448
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
6449 6450 6451
                  (action == QEMU_DEVICE_UPDATE ?
                   VIR_DOMAIN_DEVICE_MODIFY_FORCE : 0), -1);

6452 6453
    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);

6454 6455 6456 6457 6458
    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
6459 6460
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
6461 6462
        goto cleanup;
    }
6463
    priv = vm->privateData;
6464

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

6468
    if (virDomainObjIsActive(vm)) {
6469
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
6470
            flags |= VIR_DOMAIN_AFFECT_LIVE;
6471
    } else {
6472
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
6473
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
6474
        /* check consistency between flags and the vm state */
6475
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6476
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6477 6478
                           _("cannot do live update a device on "
                             "inactive domain"));
6479 6480
            goto endjob;
        }
6481
    }
6482

6483
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
6484 6485
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot modify device on transient domain"));
6486 6487
         goto endjob;
    }
6488

6489 6490 6491 6492 6493 6494 6495 6496 6497 6498 6499 6500 6501
    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)
6502
            goto endjob;
6503
    }
6504

6505 6506 6507 6508 6509
    if (priv->caps)
        caps = virObjectRef(priv->caps);
    else if (!(caps = qemuCapsCacheLookup(driver->capsCache, vm->def->emulator)))
        goto cleanup;

6510
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6511
        if (virDomainDefCompatibleDevice(vm->def, dev) < 0)
6512 6513
            goto endjob;

6514 6515 6516 6517 6518 6519
        /* Make a copy for updated domain. */
        vmdef = virDomainObjCopyPersistentDef(driver->caps, vm);
        if (!vmdef)
            goto endjob;
        switch (action) {
        case QEMU_DEVICE_ATTACH:
6520
            ret = qemuDomainAttachDeviceConfig(caps, vmdef, dev);
6521 6522 6523 6524 6525
            break;
        case QEMU_DEVICE_DETACH:
            ret = qemuDomainDetachDeviceConfig(vmdef, dev);
            break;
        case QEMU_DEVICE_UPDATE:
6526
            ret = qemuDomainUpdateDeviceConfig(caps, vmdef, dev);
6527 6528
            break;
        default:
6529 6530
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown domain modify action %d"), action);
6531 6532
            break;
        }
6533

6534 6535 6536 6537 6538
        if (ret == -1)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6539 6540 6541
        if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
            goto endjob;

6542 6543
        switch (action) {
        case QEMU_DEVICE_ATTACH:
6544
            ret = qemuDomainAttachDeviceLive(vm, dev_copy, dom);
6545 6546
            break;
        case QEMU_DEVICE_DETACH:
6547
            ret = qemuDomainDetachDeviceLive(vm, dev_copy, dom);
6548 6549
            break;
        case QEMU_DEVICE_UPDATE:
6550
            ret = qemuDomainUpdateDeviceLive(vm, dev_copy, dom, force);
6551 6552
            break;
        default:
6553 6554
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("unknown domain modify action %d"), action);
6555
            ret = -1;
6556 6557
            break;
        }
6558 6559 6560

        if (ret == -1)
            goto endjob;
6561 6562
        /*
         * update domain status forcibly because the domain status may be
6563 6564
         * changed even if we failed to attach the device. For example,
         * a new controller may be created.
6565
         */
6566
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0) {
6567
            ret = -1;
6568 6569
            goto endjob;
        }
6570
    }
6571

6572
    /* Finally, if no error until here, we can save config. */
6573
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6574 6575 6576 6577 6578 6579
        ret = virDomainSaveConfig(driver->configDir, vmdef);
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false);
            vmdef = NULL;
        }
    }
6580 6581

endjob:
6582
    if (qemuDomainObjEndJob(driver, vm) == 0)
6583 6584 6585
        vm = NULL;

cleanup:
6586
    virObjectUnref(caps);
6587
    virDomainDefFree(vmdef);
6588 6589
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
6590 6591
    virDomainDeviceDefFree(dev);
    if (vm)
6592
        virObjectUnlock(vm);
6593
    qemuDriverUnlock(driver);
6594 6595 6596
    return ret;
}

6597 6598 6599 6600 6601 6602
static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_ATTACH);
}

6603 6604 6605
static int qemuDomainAttachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainAttachDeviceFlags(dom, xml,
6606
                                       VIR_DOMAIN_AFFECT_LIVE);
6607
}
6608

6609

6610 6611 6612 6613
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
                                       const char *xml,
                                       unsigned int flags)
{
6614
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_UPDATE);
6615 6616
}

6617 6618 6619
static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
6620
    return qemuDomainModifyDeviceFlags(dom, xml, flags, QEMU_DEVICE_DETACH);
6621 6622
}

6623 6624 6625
static int qemuDomainDetachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainDetachDeviceFlags(dom, xml,
6626
                                       VIR_DOMAIN_AFFECT_LIVE);
6627 6628
}

6629 6630
static int qemuDomainGetAutostart(virDomainPtr dom,
                                  int *autostart) {
6631 6632
    virDomainObjPtr vm;
    int ret = -1;
6633

6634
    if (!(vm = qemuDomObjFromDomain(dom)))
6635
        goto cleanup;
6636 6637

    *autostart = vm->autostart;
6638
    ret = 0;
6639

6640
cleanup:
6641
    if (vm)
6642
        virObjectUnlock(vm);
6643
    return ret;
6644 6645
}

6646 6647
static int qemuDomainSetAutostart(virDomainPtr dom,
                                  int autostart) {
6648
    virQEMUDriverPtr driver = dom->conn->privateData;
6649
    virDomainObjPtr vm;
6650 6651
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
6652

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

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

6664
    if (!vm->persistent) {
6665 6666
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient domain"));
6667
        goto cleanup;
6668 6669
    }

6670 6671
    autostart = (autostart != 0);

6672
    if (vm->autostart != autostart) {
6673
        if ((configFile = virDomainConfigFile(driver->configDir, vm->def->name)) == NULL)
6674
            goto cleanup;
6675
        if ((autostartLink = virDomainConfigFile(driver->autostartDir, vm->def->name)) == NULL)
6676
            goto cleanup;
6677

6678
        if (autostart) {
6679 6680
            if (virFileMakePath(driver->autostartDir) < 0) {
                virReportSystemError(errno,
6681 6682
                                     _("cannot create autostart directory %s"),
                                     driver->autostartDir);
6683 6684
                goto cleanup;
            }
6685

6686
            if (symlink(configFile, autostartLink) < 0) {
6687
                virReportSystemError(errno,
6688 6689
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
6690 6691 6692 6693
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
6694
                virReportSystemError(errno,
6695 6696
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
6697 6698
                goto cleanup;
            }
6699 6700
        }

6701
        vm->autostart = autostart;
6702
    }
6703
    ret = 0;
6704

6705 6706 6707
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
6708
    if (vm)
6709
        virObjectUnlock(vm);
6710
    qemuDriverUnlock(driver);
6711
    return ret;
6712 6713
}

6714

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


6748 6749 6750
static char *qemuGetSchedulerType(virDomainPtr dom,
                                  int *nparams)
{
6751
    virQEMUDriverPtr driver = dom->conn->privateData;
6752
    char *ret = NULL;
6753
    int rc;
6754

6755
    qemuDriverLock(driver);
6756
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
6757 6758
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
6759
        goto cleanup;
6760 6761
    }

6762 6763 6764 6765 6766 6767 6768
    if (nparams) {
        rc = qemuGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        else if (rc == 0)
            *nparams = 1;
        else
6769
            *nparams = 5;
6770
    }
6771 6772 6773

    ret = strdup("posix");
    if (!ret)
6774
        virReportOOMError();
6775 6776 6777

cleanup:
    qemuDriverUnlock(driver);
6778 6779 6780
    return ret;
}

6781 6782 6783 6784
/* 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
6785 6786
qemuDomainParseDeviceWeightStr(char *deviceWeightStr,
                               virBlkioDeviceWeightPtr *dw, size_t *size)
6787 6788 6789 6790 6791 6792 6793
{
    char *temp;
    int ndevices = 0;
    int nsep = 0;
    int i;
    virBlkioDeviceWeightPtr result = NULL;

6794 6795 6796 6797 6798 6799
    *dw = NULL;
    *size = 0;

    if (STREQ(deviceWeightStr, ""))
        return 0;

6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 6810 6811 6812 6813 6814 6815 6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 6859 6860
    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:
6861 6862
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unable to parse device weight '%s'"), deviceWeightStr);
6863 6864 6865 6866 6867 6868
cleanup:
    virBlkioDeviceWeightArrayClear(result, ndevices);
    VIR_FREE(result);
    return -1;
}

6869 6870
/* Modify dest_array to reflect all device weight changes described in
 * src_array.  */
6871
static int
6872 6873 6874 6875
qemuDomainMergeDeviceWeights(virBlkioDeviceWeightPtr *dest_array,
                             size_t *dest_size,
                             virBlkioDeviceWeightPtr src_array,
                             size_t src_size)
6876 6877
{
    int i, j;
6878
    virBlkioDeviceWeightPtr dest, src;
6879

6880
    for (i = 0; i < src_size; i++) {
6881 6882
        bool found = false;

6883 6884 6885 6886
        src = &src_array[i];
        for (j = 0; j < *dest_size; j++) {
            dest = &(*dest_array)[j];
            if (STREQ(src->path, dest->path)) {
6887
                found = true;
6888
                dest->weight = src->weight;
6889 6890 6891 6892
                break;
            }
        }
        if (!found) {
6893
            if (!src->weight)
6894
                continue;
6895
            if (VIR_EXPAND_N(*dest_array, *dest_size, 1) < 0) {
6896 6897 6898
                virReportOOMError();
                return -1;
            }
6899 6900 6901 6902
            dest = &(*dest_array)[*dest_size - 1];
            dest->path = src->path;
            dest->weight = src->weight;
            src->path = NULL;
6903 6904 6905 6906 6907 6908
        }
    }

    return 0;
}

6909 6910 6911 6912 6913
static int
qemuDomainSetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
6914
{
6915
    virQEMUDriverPtr driver = dom->conn->privateData;
6916 6917 6918
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
6919
    virDomainDefPtr persistentDef = NULL;
6920 6921
    int ret = -1;

6922 6923
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6924 6925 6926 6927 6928 6929 6930
    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;
6931

6932
    qemuDriverLock(driver);
6933 6934 6935
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
6936 6937
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
6938 6939 6940
        goto cleanup;
    }

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

6945 6946
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
6947 6948
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
6949 6950 6951 6952
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
6953 6954 6955
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
6956 6957 6958 6959
            goto cleanup;
        }
    }

6960
    ret = 0;
6961 6962
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        for (i = 0; i < nparams; i++) {
6963
            int rc;
6964 6965 6966 6967
            virTypedParameterPtr param = &params[i];

            if (STREQ(param->field, VIR_DOMAIN_BLKIO_WEIGHT)) {
                if (params[i].value.ui > 1000 || params[i].value.ui < 100) {
6968 6969
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
6970 6971 6972
                    ret = -1;
                    continue;
                }
6973

6974 6975 6976 6977 6978 6979
                rc = virCgroupSetBlkioWeight(group, params[i].value.ui);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set blkio weight tunable"));
                    ret = -1;
                }
6980
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
6981
                size_t ndevices;
6982
                virBlkioDeviceWeightPtr devices = NULL;
6983 6984
                int j;

6985 6986 6987
                if (qemuDomainParseDeviceWeightStr(params[i].value.s,
                                                   &devices,
                                                   &ndevices) < 0) {
6988 6989 6990
                    ret = -1;
                    continue;
                }
6991
                for (j = 0; j < ndevices; j++) {
6992
                    rc = virCgroupSetBlkioDeviceWeight(group,
6993 6994
                                                       devices[j].path,
                                                       devices[j].weight);
6995 6996 6997 6998
                    if (rc < 0) {
                        virReportSystemError(-rc,
                                             _("Unable to set io device weight "
                                               "for path %s"),
6999
                                             devices[j].path);
7000 7001 7002
                        break;
                    }
                }
7003 7004
                if (j != ndevices ||
                    qemuDomainMergeDeviceWeights(&vm->def->blkio.devices,
7005 7006 7007 7008 7009
                                                 &vm->def->blkio.ndevices,
                                                 devices, ndevices) < 0)
                    ret = -1;
                virBlkioDeviceWeightArrayClear(devices, ndevices);
                VIR_FREE(devices);
7010
            }
7011
        }
E
Eric Blake 已提交
7012 7013 7014 7015
    }
    if (ret < 0)
        goto cleanup;
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
7016 7017 7018
        /* Clang can't see that if we get here, persistentDef was set.  */
        sa_assert(persistentDef);

7019 7020 7021 7022 7023
        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) {
7024 7025
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
7026 7027 7028 7029 7030
                    ret = -1;
                    continue;
                }

                persistentDef->blkio.weight = params[i].value.ui;
7031 7032
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
                virBlkioDeviceWeightPtr devices = NULL;
7033
                size_t ndevices;
7034

7035 7036 7037
                if (qemuDomainParseDeviceWeightStr(params[i].value.s,
                                                   &devices,
                                                   &ndevices) < 0) {
7038 7039 7040
                    ret = -1;
                    continue;
                }
7041 7042
                if (qemuDomainMergeDeviceWeights(&persistentDef->blkio.devices,
                                                 &persistentDef->blkio.ndevices,
7043 7044 7045 7046
                                                 devices, ndevices) < 0)
                    ret = -1;
                virBlkioDeviceWeightArrayClear(devices, ndevices);
                VIR_FREE(devices);
7047 7048
            }
        }
A
Alex Jia 已提交
7049 7050 7051

        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            ret = -1;
7052 7053 7054 7055 7056
    }

cleanup:
    virCgroupFree(&group);
    if (vm)
7057
        virObjectUnlock(vm);
7058 7059 7060 7061
    qemuDriverUnlock(driver);
    return ret;
}

7062 7063 7064 7065 7066
static int
qemuDomainGetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
7067
{
7068
    virQEMUDriverPtr driver = dom->conn->privateData;
7069
    int i, j;
7070 7071
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7072
    virDomainDefPtr persistentDef = NULL;
7073 7074 7075 7076
    unsigned int val;
    int ret = -1;
    int rc;

7077
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
7078 7079
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
7080 7081
    qemuDriverLock(driver);

7082 7083 7084
    /* 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.  */
7085 7086
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

7087 7088 7089
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
7090 7091
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7092 7093 7094 7095 7096 7097 7098 7099 7100 7101
        goto cleanup;
    }

    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = QEMU_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
    }

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

7106 7107
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_BLKIO)) {
7108 7109
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
7110 7111 7112 7113
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7114 7115
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
7116 7117 7118 7119 7120
            goto cleanup;
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7121
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132
            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;
                }
7133 7134
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT, val) < 0)
7135 7136
                    goto cleanup;
                break;
7137 7138 7139 7140
            case 1: /* blkiotune.device_weight */
                if (vm->def->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;
7141

7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158
                    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);
                }
7159 7160 7161 7162
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                                            VIR_TYPED_PARAM_STRING,
                                            param->value.s) < 0)
7163 7164
                    goto cleanup;
                break;
7165 7166 7167 7168

            default:
                break;
                /* should not hit here */
7169
            }
7170 7171
        }
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7172
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
7173 7174 7175 7176 7177 7178 7179 7180
            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) {
7181 7182 7183
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_WEIGHT);
7184 7185 7186 7187
                    goto cleanup;
                }
                param->value.ui = persistentDef->blkio.weight;
                break;
7188

7189 7190 7191
            case 1: /* blkiotune.device_weight */
                if (persistentDef->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
7192 7193
                    bool comma = false;

7194
                    for (j = 0; j < persistentDef->blkio.ndevices; j++) {
7195 7196 7197
                        if (!persistentDef->blkio.devices[j].weight)
                            continue;
                        if (comma)
7198
                            virBufferAddChar(&buf, ',');
7199 7200
                        else
                            comma = true;
7201 7202 7203 7204 7205 7206 7207 7208 7209
                        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);
7210 7211
                }
                if (!param->value.s) {
7212 7213 7214 7215 7216 7217 7218 7219 7220
                    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) {
7221 7222 7223
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_DEVICE_WEIGHT);
7224 7225 7226 7227
                    goto cleanup;
                }
                break;

7228 7229 7230 7231
            default:
                break;
                /* should not hit here */
            }
7232 7233 7234
        }
    }

7235 7236
    if (QEMU_NB_BLKIO_PARAM < *nparams)
        *nparams = QEMU_NB_BLKIO_PARAM;
7237 7238 7239 7240 7241 7242
    ret = 0;

cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
7243
        virObjectUnlock(vm);
7244 7245 7246
    qemuDriverUnlock(driver);
    return ret;
}
7247

7248 7249 7250 7251 7252
static int
qemuDomainSetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int nparams,
                              unsigned int flags)
7253
{
7254
    virQEMUDriverPtr driver = dom->conn->privateData;
7255
    int i;
7256
    virDomainDefPtr persistentDef = NULL;
7257 7258
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7259 7260 7261 7262 7263 7264
    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;

7265
    int ret = -1;
7266
    int rc;
7267

7268 7269
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7270

7271 7272 7273 7274 7275 7276 7277 7278 7279
    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;
7280 7281 7282 7283 7284 7285

    qemuDriverLock(driver);

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

    if (vm == NULL) {
7286 7287
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7288 7289 7290
        goto cleanup;
    }

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

7295
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7296
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
7297 7298
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
7299 7300 7301 7302
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7303 7304
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
7305 7306 7307 7308
            goto cleanup;
        }
    }

7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321 7322 7323 7324 7325 7326 7327
    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;
    }

7328 7329 7330 7331 7332 7333 7334 7335
    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;
        }
7336

7337 7338 7339 7340 7341 7342 7343 7344 7345 7346 7347 7348 7349 7350 7351 7352 7353 7354 7355
        /* 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;
                }
            }
7356 7357 7358
        }
    }

7359 7360
    ret = 0;
    for (i = 0; i < nparams; i++) {
7361
        virTypedParameterPtr param = &params[i];
7362 7363

        if (STREQ(param->field, VIR_DOMAIN_MEMORY_HARD_LIMIT)) {
7364
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7365
                rc = virCgroupSetMemoryHardLimit(group, param->value.ul);
7366 7367 7368 7369 7370 7371 7372
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set memory hard_limit tunable"));
                    ret = -1;
                }
            }

7373
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7374
                persistentDef->mem.hard_limit = param->value.ul;
7375 7376
            }
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SOFT_LIMIT)) {
7377
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7378
                rc = virCgroupSetMemorySoftLimit(group, param->value.ul);
7379 7380 7381 7382 7383 7384 7385
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set memory soft_limit tunable"));
                    ret = -1;
                }
            }

7386
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7387
                persistentDef->mem.soft_limit = param->value.ul;
7388
            }
7389
        } else if (STREQ(param->field, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT)) {
7390
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7391
                rc = virCgroupSetMemSwapHardLimit(group, param->value.ul);
7392 7393 7394 7395 7396 7397
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to set swap_hard_limit tunable"));
                    ret = -1;
                }
            }
7398
            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7399
                persistentDef->mem.swap_hard_limit = param->value.ul;
7400 7401 7402 7403
            }
        }
    }

7404
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7405 7406
        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            ret = -1;
7407 7408
    }

7409 7410 7411
cleanup:
    virCgroupFree(&group);
    if (vm)
7412
        virObjectUnlock(vm);
7413 7414 7415 7416
    qemuDriverUnlock(driver);
    return ret;
}

7417 7418 7419 7420 7421
static int
qemuDomainGetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int *nparams,
                              unsigned int flags)
7422
{
7423
    virQEMUDriverPtr driver = dom->conn->privateData;
7424 7425 7426
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7427
    virDomainDefPtr persistentDef = NULL;
7428 7429 7430
    int ret = -1;
    int rc;

7431
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
7432 7433
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
7434

7435
    qemuDriverLock(driver);
7436

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

7440 7441 7442
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
7443 7444
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7445 7446 7447
        goto cleanup;
    }

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

7452
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7453
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_MEMORY)) {
7454 7455
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
7456 7457 7458 7459
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7460 7461
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"), vm->def->name);
7462 7463 7464 7465
            goto cleanup;
        }
    }

7466 7467 7468 7469 7470 7471 7472
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = QEMU_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

7473
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7474
        for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
7475 7476 7477 7478
            virMemoryParameterPtr param = &params[i];

            switch (i) {
            case 0: /* fill memory hard limit here */
7479 7480 7481 7482
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.hard_limit) < 0)
7483 7484 7485 7486
                    goto cleanup;
                break;

            case 1: /* fill memory soft limit here */
7487 7488 7489 7490
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.soft_limit) < 0)
7491 7492 7493 7494
                    goto cleanup;
                break;

            case 2: /* fill swap hard limit here */
7495 7496 7497 7498
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG,
                                            persistentDef->mem.swap_hard_limit) < 0)
7499 7500 7501 7502 7503 7504 7505 7506 7507
                    goto cleanup;
                break;

            default:
                break;
                /* should not hit here */
            }
        }
        goto out;
7508 7509
    }

7510
    for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
7511
        virTypedParameterPtr param = &params[i];
7512
        unsigned long long val = 0;
7513

7514 7515 7516
        /* Coverity does not realize that if we get here, group is set.  */
        sa_assert(group);

7517
        switch (i) {
7518 7519 7520 7521 7522
        case 0: /* fill memory hard limit here */
            rc = virCgroupGetMemoryHardLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory hard limit"));
7523
                goto cleanup;
7524
            }
7525 7526 7527
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
7528
                goto cleanup;
7529 7530 7531 7532 7533 7534 7535
            break;

        case 1: /* fill memory soft limit here */
            rc = virCgroupGetMemorySoftLimit(group, &val);
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get memory soft limit"));
7536
                goto cleanup;
7537
            }
7538 7539 7540
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
7541
                goto cleanup;
7542 7543 7544
            break;

        case 2: /* fill swap hard limit here */
7545
            rc = virCgroupGetMemSwapHardLimit(group, &val);
7546 7547 7548
            if (rc != 0) {
                virReportSystemError(-rc, "%s",
                                     _("unable to get swap hard limit"));
7549
                goto cleanup;
7550
            }
7551 7552 7553
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
7554
                goto cleanup;
7555 7556 7557 7558 7559 7560 7561 7562
            break;

        default:
            break;
            /* should not hit here */
        }
    }

7563
out:
7564 7565
    if (QEMU_NB_MEM_PARAM < *nparams)
        *nparams = QEMU_NB_MEM_PARAM;
7566 7567
    ret = 0;

7568 7569 7570 7571
cleanup:
    if (group)
        virCgroupFree(&group);
    if (vm)
7572
        virObjectUnlock(vm);
7573 7574 7575 7576
    qemuDriverUnlock(driver);
    return ret;
}

7577 7578 7579 7580 7581 7582
static int
qemuDomainSetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
{
7583
    virQEMUDriverPtr driver = dom->conn->privateData;
7584 7585 7586 7587 7588 7589 7590 7591
    int i;
    virDomainDefPtr persistentDef = NULL;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7592 7593 7594 7595 7596 7597 7598
    if (virTypedParameterArrayValidate(params, nparams,
                                       VIR_DOMAIN_NUMA_MODE,
                                       VIR_TYPED_PARAM_INT,
                                       VIR_DOMAIN_NUMA_NODESET,
                                       VIR_TYPED_PARAM_STRING,
                                       NULL) < 0)
        return -1;
7599 7600 7601 7602 7603 7604

    qemuDriverLock(driver);

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

    if (vm == NULL) {
7605 7606
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7607 7608 7609 7610 7611 7612 7613 7614 7615
        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)) {
7616 7617
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup cpuset controller is not mounted"));
7618 7619 7620 7621
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7622 7623 7624
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635
            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) {
7636 7637
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("can't change numa mode for running domain"));
7638 7639 7640 7641 7642 7643 7644 7645 7646
                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;
7647
            virBitmapPtr nodeset = NULL;
7648 7649
            char *nodeset_str = NULL;

7650 7651 7652
            if (virBitmapParse(params[i].value.s,
                               0, &nodeset,
                               VIR_DOMAIN_CPUMASK_LEN) < 0) {
7653 7654 7655 7656 7657
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to parse nodeset"));
                ret = -1;
                continue;
            }
7658 7659 7660 7661

            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
                if (vm->def->numatune.memory.mode !=
                    VIR_DOMAIN_NUMATUNE_MEM_STRICT) {
7662 7663 7664
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("change of nodeset for running domain "
                                     "requires strict numa mode"));
7665
                    virBitmapFree(nodeset);
7666 7667 7668
                    ret = -1;
                    continue;
                }
7669 7670

                /* Ensure the cpuset string is formated before passing to cgroup */
7671
                if (!(nodeset_str = virBitmapFormat(nodeset))) {
7672 7673
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("Failed to format nodeset"));
7674
                    virBitmapFree(nodeset);
7675 7676 7677 7678 7679
                    ret = -1;
                    continue;
                }

                if ((rc = virCgroupSetCpusetMems(group, nodeset_str) != 0)) {
7680 7681
                    virReportSystemError(-rc, "%s",
                                         _("unable to set numa tunable"));
7682
                    virBitmapFree(nodeset);
7683
                    VIR_FREE(nodeset_str);
7684 7685 7686
                    ret = -1;
                    continue;
                }
7687
                VIR_FREE(nodeset_str);
7688 7689 7690

                /* update vm->def here so that dumpxml can read the new
                 * values from vm->def. */
7691
                virBitmapFree(vm->def->numatune.memory.nodemask);
7692

7693 7694
                vm->def->numatune.memory.placement_mode =
                    VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_STATIC;
7695
                vm->def->numatune.memory.nodemask = virBitmapNewCopy(nodeset);
7696 7697 7698
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7699
                virBitmapFree(persistentDef->numatune.memory.nodemask);
7700 7701

                persistentDef->numatune.memory.nodemask = nodeset;
7702 7703
                persistentDef->numatune.memory.placement_mode =
                    VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_STATIC;
7704
                nodeset = NULL;
7705
            }
7706
            virBitmapFree(nodeset);
7707 7708 7709 7710
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7711 7712 7713
        if (!persistentDef->numatune.memory.placement_mode)
            persistentDef->numatune.memory.placement_mode =
                VIR_DOMAIN_NUMATUNE_MEM_PLACEMENT_MODE_AUTO;
7714 7715 7716 7717 7718 7719 7720
        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            ret = -1;
    }

cleanup:
    virCgroupFree(&group);
    if (vm)
7721
        virObjectUnlock(vm);
7722 7723 7724 7725 7726 7727 7728 7729 7730 7731
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainGetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
{
7732
    virQEMUDriverPtr driver = dom->conn->privateData;
7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754
    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) {
7755 7756
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771
        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)) {
7772 7773
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
7774 7775 7776 7777
            goto cleanup;
        }

        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7778 7779 7780
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
7781 7782 7783 7784 7785 7786 7787 7788 7789
            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 */
7790 7791
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_MODE,
                                        VIR_TYPED_PARAM_INT, 0) < 0)
7792 7793 7794 7795 7796 7797 7798 7799 7800
                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) {
7801 7802
                nodeset = virBitmapFormat(persistentDef->numatune.memory.nodemask);
                if (!nodeset)
7803 7804 7805 7806 7807 7808 7809 7810 7811
                    nodeset = strdup("");
            } else {
                rc = virCgroupGetCpusetMems(group, &nodeset);
                if (rc != 0) {
                    virReportSystemError(-rc, "%s",
                                         _("unable to get numa nodeset"));
                    goto cleanup;
                }
            }
7812 7813
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_NODESET,
                                        VIR_TYPED_PARAM_STRING, nodeset) < 0)
7814
                goto cleanup;
S
Stefan Berger 已提交
7815 7816 7817

            nodeset = NULL;

7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830
            break;

        default:
            break;
            /* should not hit here */
        }
    }

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

cleanup:
S
Stefan Berger 已提交
7831
    VIR_FREE(nodeset);
7832 7833
    virCgroupFree(&group);
    if (vm)
7834
        virObjectUnlock(vm);
7835 7836 7837 7838
    qemuDriverUnlock(driver);
    return ret;
}

7839 7840 7841 7842 7843 7844 7845 7846 7847 7848 7849 7850
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 已提交
7851 7852 7853 7854 7855 7856 7857 7858 7859 7860 7861 7862 7863 7864 7865 7866 7867 7868 7869 7870
    /* 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);
        }
7871 7872 7873 7874 7875 7876 7877 7878 7879
    }

    return 0;

cleanup:
    virCgroupFree(&cgroup_vcpu);
    return -1;
}

7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898 7899 7900 7901 7902 7903 7904 7905 7906 7907 7908 7909 7910 7911 7912 7913
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;
}

7914 7915 7916 7917 7918 7919 7920 7921 7922
#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;                                                       \
    }

7923 7924 7925 7926 7927
static int
qemuSetSchedulerParametersFlags(virDomainPtr dom,
                                virTypedParameterPtr params,
                                int nparams,
                                unsigned int flags)
7928
{
7929
    virQEMUDriverPtr driver = dom->conn->privateData;
7930 7931 7932
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
7933
    virDomainDefPtr vmdef = NULL;
7934 7935
    unsigned long long value_ul;
    long long value_l;
7936
    int ret = -1;
7937
    int rc;
7938

7939 7940
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7941 7942 7943 7944 7945 7946 7947
    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,
7948 7949 7950 7951
                                       VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
                                       VIR_TYPED_PARAM_ULLONG,
                                       VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
                                       VIR_TYPED_PARAM_LLONG,
7952 7953
                                       NULL) < 0)
        return -1;
7954

7955
    qemuDriverLock(driver);
7956 7957 7958 7959

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

    if (vm == NULL) {
7960 7961
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
7962 7963 7964
        goto cleanup;
    }

7965 7966 7967
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &vmdef) < 0)
        goto cleanup;
7968

7969 7970 7971 7972 7973
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
        vmdef = virDomainObjCopyPersistentDef(driver->caps, vm);
        if (!vmdef)
            goto cleanup;
7974 7975
    }

7976
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7977
        if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
7978 7979
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup CPU controller is not mounted"));
7980 7981 7982
            goto cleanup;
        }
        if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
7983 7984 7985
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot find cgroup for domain %s"),
                           vm->def->name);
7986 7987 7988 7989
            goto cleanup;
        }
    }

7990
    for (i = 0; i < nparams; i++) {
7991
        virTypedParameterPtr param = &params[i];
7992 7993
        value_ul = param->value.ul;
        value_l = param->value.l;
7994

7995
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
7996
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7997
                if ((rc = virCgroupSetCpuShares(group, value_ul))) {
7998 7999 8000 8001
                    virReportSystemError(-rc, "%s",
                                         _("unable to set cpu shares tunable"));
                    goto cleanup;
                }
8002
                vm->def->cputune.shares = value_ul;
8003
            }
8004

8005 8006 8007
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.shares = value_ul;

8008
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
8009 8010 8011
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

8012 8013
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
                if ((rc = qemuSetVcpusBWLive(vm, group, value_ul, 0)))
8014
                    goto cleanup;
8015

8016
                vm->def->cputune.period = value_ul;
8017 8018
            }

8019
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
8020
                vmdef->cputune.period = params[i].value.ul;
8021

8022
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
8023 8024 8025
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

8026 8027
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
                if ((rc = qemuSetVcpusBWLive(vm, group, 0, value_l)))
8028
                    goto cleanup;
8029

8030
                vm->def->cputune.quota = value_l;
8031 8032
            }

8033 8034 8035
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.quota = value_l;

8036
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD)) {
8037 8038 8039
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

8040 8041
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
                if ((rc = qemuSetEmulatorBandwidthLive(vm, group, value_ul, 0)))
8042 8043
                    goto cleanup;

8044
                vm->def->cputune.emulator_period = value_ul;
8045 8046
            }

8047 8048 8049
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_period = value_ul;

8050
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA)) {
8051 8052 8053
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

8054 8055
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
                if ((rc = qemuSetEmulatorBandwidthLive(vm, group, 0, value_l)))
8056 8057
                    goto cleanup;

8058
                vm->def->cputune.emulator_quota = value_l;
8059 8060
            }

8061 8062
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_quota = value_l;
8063 8064
        }
    }
8065

8066 8067 8068 8069 8070 8071 8072 8073 8074 8075 8076 8077 8078
    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;
    }

8079 8080 8081
    ret = 0;

cleanup:
8082
    virDomainDefFree(vmdef);
8083 8084
    virCgroupFree(&group);
    if (vm)
8085
        virObjectUnlock(vm);
8086
    qemuDriverUnlock(driver);
8087 8088
    return ret;
}
8089
#undef SCHED_RANGE_CHECK
8090

8091 8092 8093 8094
static int
qemuSetSchedulerParameters(virDomainPtr dom,
                           virTypedParameterPtr params,
                           int nparams)
8095 8096 8097 8098
{
    return qemuSetSchedulerParametersFlags(dom,
                                           params,
                                           nparams,
8099
                                           VIR_DOMAIN_AFFECT_CURRENT);
8100 8101
}

8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166
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;
}

8167 8168 8169 8170 8171 8172 8173 8174 8175 8176 8177 8178 8179 8180 8181 8182 8183 8184 8185 8186 8187 8188 8189 8190 8191 8192 8193 8194 8195 8196 8197 8198 8199 8200 8201 8202 8203
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;
}

8204 8205 8206 8207 8208
static int
qemuGetSchedulerParametersFlags(virDomainPtr dom,
                                virTypedParameterPtr params,
                                int *nparams,
                                unsigned int flags)
8209
{
8210
    virQEMUDriverPtr driver = dom->conn->privateData;
8211 8212
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
8213 8214 8215
    unsigned long long shares;
    unsigned long long period;
    long long quota;
8216 8217
    unsigned long long emulator_period;
    long long emulator_quota;
8218 8219
    int ret = -1;
    int rc;
8220
    bool cpu_bw_status = false;
8221
    int saved_nparams = 0;
8222
    virDomainDefPtr persistentDef;
8223

8224
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
8225 8226
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
8227

8228 8229
    qemuDriverLock(driver);

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

8233 8234 8235 8236 8237 8238 8239
    if (*nparams > 1) {
        rc = qemuGetCpuBWStatus(driver->cgroup);
        if (rc < 0)
            goto cleanup;
        cpu_bw_status = !!rc;
    }

8240 8241 8242
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
8243 8244
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
8245 8246 8247
        goto cleanup;
    }

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

8252
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8253 8254 8255 8256
        shares = persistentDef->cputune.shares;
        if (*nparams > 1 && cpu_bw_status) {
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
8257 8258
            emulator_period = persistentDef->cputune.emulator_period;
            emulator_quota = persistentDef->cputune.emulator_quota;
8259
        }
8260
        goto out;
8261 8262
    }

8263
    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPU)) {
8264 8265
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
8266 8267 8268
        goto cleanup;
    }

8269
    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
8270 8271
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find cgroup for domain %s"), vm->def->name);
8272 8273 8274
        goto cleanup;
    }

8275
    rc = virCgroupGetCpuShares(group, &shares);
8276
    if (rc != 0) {
8277
        virReportSystemError(-rc, "%s",
8278 8279 8280
                             _("unable to get cpu shares tunable"));
        goto cleanup;
    }
8281 8282 8283 8284 8285 8286

    if (*nparams > 1 && cpu_bw_status) {
        rc = qemuGetVcpusBWLive(vm, group, &period, &quota);
        if (rc != 0)
            goto cleanup;
    }
8287 8288 8289 8290 8291 8292 8293 8294

    if (*nparams > 3 && cpu_bw_status) {
        rc = qemuGetEmulatorBandwidthLive(vm, group, &emulator_period,
                                          &emulator_quota);
        if (rc != 0)
            goto cleanup;
    }

8295
out:
8296 8297
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
8298
        goto cleanup;
8299 8300 8301 8302
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
8303 8304 8305
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
8306 8307 8308 8309 8310
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
8311 8312 8313
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
8314 8315 8316
                goto cleanup;
            saved_nparams++;
        }
8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334

        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++;
        }
8335 8336 8337 8338
    }

    *nparams = saved_nparams;

8339 8340 8341 8342 8343
    ret = 0;

cleanup:
    virCgroupFree(&group);
    if (vm)
8344
        virObjectUnlock(vm);
8345
    qemuDriverUnlock(driver);
8346 8347 8348
    return ret;
}

8349 8350 8351 8352 8353 8354
static int
qemuGetSchedulerParameters(virDomainPtr dom,
                           virTypedParameterPtr params,
                           int *nparams)
{
    return qemuGetSchedulerParametersFlags(dom, params, nparams,
8355
                                           VIR_DOMAIN_AFFECT_CURRENT);
8356
}
8357

8358 8359 8360 8361 8362 8363 8364
/**
 * 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 已提交
8365 8366 8367 8368
qemuDomainBlockResize(virDomainPtr dom,
                      const char *path,
                      unsigned long long size,
                      unsigned int flags)
8369
{
8370
    virQEMUDriverPtr driver = dom->conn->privateData;
8371 8372 8373 8374 8375 8376
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1, i;
    char *device = NULL;
    virDomainDiskDefPtr disk = NULL;

E
Eric Blake 已提交
8377
    virCheckFlags(VIR_DOMAIN_BLOCK_RESIZE_BYTES, -1);
8378 8379

    if (path[0] == '\0') {
8380 8381
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("empty path"));
8382 8383 8384
        return -1;
    }

E
Eric Blake 已提交
8385 8386 8387
    /* We prefer operating on bytes.  */
    if ((flags & VIR_DOMAIN_BLOCK_RESIZE_BYTES) == 0) {
        if (size > ULLONG_MAX / 1024) {
8388 8389 8390
            virReportError(VIR_ERR_OVERFLOW,
                           _("size must be less than %llu"),
                           ULLONG_MAX / 1024);
E
Eric Blake 已提交
8391 8392 8393
            return -1;
        }
        size *= 1024;
8394 8395
    }

8396
    if (!(vm = qemuDomObjFromDomain(dom)))
8397 8398 8399 8400 8401 8402 8403 8404
        goto cleanup;

    priv = vm->privateData;

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

    if (!virDomainObjIsActive(vm)) {
8405 8406
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8407 8408 8409 8410
        goto endjob;
    }

    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
8411 8412
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
8413
        goto endjob;
8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438
    }
    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)
8439
        virObjectUnlock(vm);
8440 8441 8442
    return ret;
}

8443 8444 8445 8446 8447
/* 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
8448 8449 8450
qemuDomainBlockStats(virDomainPtr dom,
                     const char *path,
                     struct _virDomainBlockStats *stats)
8451
{
8452
    virQEMUDriverPtr driver = dom->conn->privateData;
8453
    int i, ret = -1;
8454
    virDomainObjPtr vm;
8455
    virDomainDiskDefPtr disk = NULL;
8456
    qemuDomainObjPrivatePtr priv;
8457

8458
    if (!(vm = qemuDomObjFromDomain(dom)))
8459
        goto cleanup;
8460

8461
    if (!virDomainObjIsActive(vm)) {
8462 8463
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8464 8465 8466
        goto cleanup;
    }

8467
    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
8468 8469
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
8470
        goto cleanup;
8471
    }
8472
    disk = vm->def->disks[i];
8473

8474
    if (!disk->info.alias) {
8475 8476
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing disk device alias name for %s"), disk->dst);
8477
        goto cleanup;
8478
    }
8479

8480
    priv = vm->privateData;
8481 8482
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;
8483

8484
    if (!virDomainObjIsActive(vm)) {
8485 8486
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8487 8488
        goto endjob;
    }
8489

8490
    qemuDomainObjEnterMonitor(driver, vm);
8491 8492 8493 8494
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
                                       disk->info.alias,
                                       &stats->rd_req,
                                       &stats->rd_bytes,
8495
                                       NULL,
8496 8497
                                       &stats->wr_req,
                                       &stats->wr_bytes,
8498 8499 8500
                                       NULL,
                                       NULL,
                                       NULL,
8501 8502
                                       &stats->errs);
    qemuDomainObjExitMonitor(driver, vm);
8503

8504
endjob:
8505 8506
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;
8507

8508
cleanup:
8509
    if (vm)
8510
        virObjectUnlock(vm);
8511
    return ret;
8512 8513
}

8514
static int
8515 8516 8517 8518 8519
qemuDomainBlockStatsFlags(virDomainPtr dom,
                          const char *path,
                          virTypedParameterPtr params,
                          int *nparams,
                          unsigned int flags)
8520
{
8521
    virQEMUDriverPtr driver = dom->conn->privateData;
8522 8523 8524 8525 8526 8527
    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;
8528
    virTypedParameterPtr param;
8529

8530 8531 8532 8533
    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

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

8535
    if (!(vm = qemuDomObjFromDomain(dom)))
8536 8537 8538
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
8539 8540
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8541 8542 8543 8544
        goto cleanup;
    }

    if (*nparams != 0) {
8545
        if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
8546 8547
            virReportError(VIR_ERR_INVALID_ARG,
                           _("invalid path: %s"), path);
8548 8549
            goto cleanup;
        }
8550
        disk = vm->def->disks[i];
8551 8552

        if (!disk->info.alias) {
8553 8554 8555
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("missing disk device alias name for %s"),
                            disk->dst);
8556 8557 8558 8559 8560 8561 8562 8563 8564 8565
             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;

8566
    if (!virDomainObjIsActive(vm)) {
8567 8568
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8569 8570 8571
        goto endjob;
    }

8572 8573 8574 8575
    qemuDomainObjEnterMonitor(driver, vm);
    tmp = *nparams;
    ret = qemuMonitorGetBlockStatsParamsNumber(priv->mon, nparams);

8576
    if (tmp == 0 || ret < 0) {
8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597
        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;

8598 8599
    tmp = 0;
    ret = -1;
8600

8601 8602
    if (tmp < *nparams && wr_bytes != -1) {
        param = &params[tmp];
8603 8604
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES,
                                    VIR_TYPED_PARAM_LLONG, wr_bytes) < 0)
8605 8606 8607
            goto endjob;
        tmp++;
    }
8608

8609
    if (tmp < *nparams && wr_req != -1) {
8610
        param = &params[tmp];
8611 8612
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ,
                                    VIR_TYPED_PARAM_LLONG, wr_req) < 0)
8613 8614 8615
            goto endjob;
        tmp++;
    }
8616

8617
    if (tmp < *nparams && rd_bytes != -1) {
8618
        param = &params[tmp];
8619 8620
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_BYTES,
                                    VIR_TYPED_PARAM_LLONG, rd_bytes) < 0)
8621 8622 8623
            goto endjob;
        tmp++;
    }
8624

8625
    if (tmp < *nparams && rd_req != -1) {
8626
        param = &params[tmp];
8627 8628
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_REQ,
                                    VIR_TYPED_PARAM_LLONG, rd_req) < 0)
8629 8630 8631
            goto endjob;
        tmp++;
    }
8632

8633
    if (tmp < *nparams && flush_req != -1) {
8634
        param = &params[tmp];
8635 8636
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ,
                                    VIR_TYPED_PARAM_LLONG, flush_req) < 0)
8637 8638 8639
            goto endjob;
        tmp++;
    }
8640

8641
    if (tmp < *nparams && wr_total_times != -1) {
8642
        param = &params[tmp];
8643 8644 8645
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, wr_total_times) < 0)
8646 8647 8648
            goto endjob;
        tmp++;
    }
8649

8650
    if (tmp < *nparams && rd_total_times != -1) {
8651
        param = &params[tmp];
8652 8653 8654
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, rd_total_times) < 0)
8655 8656 8657
            goto endjob;
        tmp++;
    }
8658

8659
    if (tmp < *nparams && flush_total_times != -1) {
8660
        param = &params[tmp];
8661 8662 8663 8664
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_FLUSH_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG,
                                    flush_total_times) < 0)
8665 8666
            goto endjob;
        tmp++;
8667 8668
    }

8669 8670 8671 8672 8673
    /* Field 'errs' is meaningless for QEMU, won't set it. */

    ret = 0;
    *nparams = tmp;

8674 8675 8676 8677 8678 8679
endjob:
    if (qemuDomainObjEndJob(driver, vm) == 0)
        vm = NULL;

cleanup:
    if (vm)
8680
        virObjectUnlock(vm);
8681 8682 8683
    return ret;
}

8684
#ifdef __linux__
8685
static int
8686 8687 8688
qemuDomainInterfaceStats(virDomainPtr dom,
                         const char *path,
                         struct _virDomainInterfaceStats *stats)
8689
{
8690
    virDomainObjPtr vm;
8691
    int i;
8692
    int ret = -1;
8693

8694
    if (!(vm = qemuDomObjFromDomain(dom)))
8695
        goto cleanup;
8696

D
Daniel P. Berrange 已提交
8697
    if (!virDomainObjIsActive(vm)) {
8698 8699
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
8700
        goto cleanup;
8701 8702 8703
    }

    /* Check the path is one of the domain's network interfaces. */
8704 8705
    for (i = 0 ; i < vm->def->nnets ; i++) {
        if (vm->def->nets[i]->ifname &&
8706
            STREQ(vm->def->nets[i]->ifname, path)) {
8707 8708 8709
            ret = 0;
            break;
        }
8710 8711
    }

8712
    if (ret == 0)
8713
        ret = linuxDomainInterfaceStats(path, stats);
8714
    else
8715 8716
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path, '%s' is not a known interface"), path);
8717

8718
cleanup:
8719
    if (vm)
8720
        virObjectUnlock(vm);
8721 8722
    return ret;
}
8723
#else
8724
static int
E
Eric Blake 已提交
8725
qemuDomainInterfaceStats(virDomainPtr dom ATTRIBUTE_UNUSED,
8726 8727
                         const char *path ATTRIBUTE_UNUSED,
                         struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
8728
{
8729 8730
    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("interface stats not implemented on this platform"));
8731 8732
    return -1;
}
8733
#endif
8734

8735 8736 8737 8738 8739 8740 8741
static int
qemuDomainSetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 unsigned int flags)
{
8742
    virQEMUDriverPtr driver = dom->conn->privateData;
8743 8744 8745 8746 8747 8748
    int i;
    virCgroupPtr group = NULL;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    virDomainNetDefPtr net = NULL, persistentNet = NULL;
8749
    virNetDevBandwidthPtr bandwidth = NULL, newBandwidth = NULL;
8750 8751 8752

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
8753 8754 8755 8756 8757 8758 8759 8760 8761 8762 8763 8764 8765 8766 8767
    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;
8768

8769
    qemuDriverLock(driver);
8770 8771 8772
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);

    if (vm == NULL) {
8773 8774
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
8775 8776 8777 8778 8779 8780 8781 8782 8783 8784
        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) {
8785 8786
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
8787 8788 8789 8790 8791 8792
            goto cleanup;
        }
    }
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        persistentNet = virDomainNetFind(persistentDef, device);
        if (!persistentNet) {
8793 8794
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
8795 8796 8797 8798
            goto cleanup;
        }
    }

8799 8800 8801
    if ((VIR_ALLOC(bandwidth) < 0) ||
        (VIR_ALLOC(bandwidth->in) < 0) ||
        (VIR_ALLOC(bandwidth->out) < 0)) {
8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812 8813 8814 8815 8816 8817 8818 8819 8820 8821 8822 8823
        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;
        }
    }

8824
    /* average is mandatory, peak and burst are optional. So if no
8825
     * average is given, we free inbound/outbound here which causes
8826
     * inbound/outbound to not be set. */
8827 8828 8829 8830 8831 8832 8833 8834 8835 8836 8837 8838 8839 8840 8841
    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
8842
         * here to prevent them from being lost. */
8843 8844
        if (bandwidth->in ||
            (net->bandwidth && net->bandwidth->in)) {
8845 8846 8847 8848
            if (VIR_ALLOC(newBandwidth->in) < 0) {
                virReportOOMError();
                goto cleanup;
            }
8849 8850 8851 8852 8853 8854 8855

            memcpy(newBandwidth->in,
                   bandwidth->in ? bandwidth->in : net->bandwidth->in,
                   sizeof(*newBandwidth->in));
        }
        if (bandwidth->out ||
            (net->bandwidth && net->bandwidth->out)) {
8856 8857 8858 8859
            if (VIR_ALLOC(newBandwidth->out) < 0) {
                virReportOOMError();
                goto cleanup;
            }
8860 8861 8862 8863

            memcpy(newBandwidth->out,
                   bandwidth->out ? bandwidth->out : net->bandwidth->out,
                   sizeof(*newBandwidth->out));
8864 8865
        }

8866
        if (virNetDevBandwidthSet(net->ifname, newBandwidth, false) < 0) {
8867 8868 8869
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot set bandwidth limits on %s"),
                           device);
8870 8871 8872 8873 8874
            goto cleanup;
        }

        virNetDevBandwidthFree(net->bandwidth);
        net->bandwidth = newBandwidth;
E
Eric Blake 已提交
8875
        newBandwidth = NULL;
8876 8877 8878 8879 8880 8881 8882 8883 8884 8885 8886 8887 8888 8889 8890 8891 8892 8893 8894 8895 8896 8897 8898 8899 8900
    }
    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);
8901
    virNetDevBandwidthFree(newBandwidth);
8902 8903
    virCgroupFree(&group);
    if (vm)
8904
        virObjectUnlock(vm);
8905 8906 8907 8908 8909 8910 8911 8912 8913 8914 8915
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainGetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int *nparams,
                                 unsigned int flags)
{
8916
    virQEMUDriverPtr driver = dom->conn->privateData;
8917 8918 8919 8920 8921 8922 8923 8924 8925 8926 8927 8928 8929 8930 8931 8932 8933 8934 8935
    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) {
8936 8937
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), dom->uuid);
8938 8939 8940 8941 8942 8943 8944 8945 8946 8947 8948 8949 8950 8951 8952 8953 8954 8955 8956
        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) {
8957 8958
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Can't find device %s"), device);
8959 8960 8961 8962
        goto cleanup;
    }

    for (i = 0; i < *nparams && i < QEMU_NB_BANDWIDTH_PARAM; i++) {
8963
        switch (i) {
8964
        case 0: /* inbound.average */
8965 8966 8967
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8968 8969 8970 8971 8972
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->average;
            break;
        case 1: /* inbound.peak */
8973 8974 8975
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8976 8977 8978 8979 8980
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->peak;
            break;
        case 2: /* inbound.burst */
8981 8982 8983
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8984 8985 8986 8987 8988
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->burst;
            break;
        case 3: /* outbound.average */
8989 8990 8991
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
8992 8993 8994 8995 8996
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->average;
            break;
        case 4: /* outbound.peak */
8997 8998 8999
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9000 9001 9002 9003 9004
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->peak;
            break;
        case 5: /* outbound.burst */
9005 9006 9007
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9008 9009 9010 9011 9012 9013 9014 9015 9016 9017 9018 9019 9020 9021 9022 9023 9024 9025
                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)
9026
        virObjectUnlock(vm);
9027 9028 9029 9030
    qemuDriverUnlock(driver);
    return ret;
}

9031
static int
9032 9033 9034 9035
qemuDomainMemoryStats(virDomainPtr dom,
                      struct _virDomainMemoryStat *stats,
                      unsigned int nr_stats,
                      unsigned int flags)
9036
{
9037
    virQEMUDriverPtr driver = dom->conn->privateData;
9038
    virDomainObjPtr vm;
M
Martin Kletzander 已提交
9039
    int ret = -1;
9040

9041 9042
    virCheckFlags(0, -1);

9043
    if (!(vm = qemuDomObjFromDomain(dom)))
9044 9045
        goto cleanup;

9046
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
9047 9048
        goto cleanup;

M
Martin Kletzander 已提交
9049
    if (!virDomainObjIsActive(vm)) {
9050 9051
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
M
Martin Kletzander 已提交
9052
    } else {
9053
        qemuDomainObjPrivatePtr priv = vm->privateData;
9054
        qemuDomainObjEnterMonitor(driver, vm);
9055
        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
9056
        qemuDomainObjExitMonitor(driver, vm);
M
Martin Kletzander 已提交
9057 9058 9059

        if (ret >= 0 && ret < nr_stats) {
            long rss;
9060
            if (qemuGetProcessInfo(NULL, NULL, &rss, vm->pid, 0) < 0) {
9061 9062
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("cannot get RSS for domain"));
M
Martin Kletzander 已提交
9063 9064 9065 9066 9067 9068 9069
            } else {
                stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_RSS;
                stats[ret].val = rss;
                ret++;
            }

        }
9070 9071
    }

9072
    if (qemuDomainObjEndJob(driver, vm) == 0)
9073 9074
        vm = NULL;

9075 9076
cleanup:
    if (vm)
9077
        virObjectUnlock(vm);
9078 9079 9080
    return ret;
}

9081
static int
9082 9083 9084 9085 9086
qemuDomainBlockPeek(virDomainPtr dom,
                    const char *path,
                    unsigned long long offset, size_t size,
                    void *buffer,
                    unsigned int flags)
9087
{
9088
    virDomainObjPtr vm;
9089 9090
    int fd = -1, ret = -1;
    const char *actual;
9091

E
Eric Blake 已提交
9092 9093
    virCheckFlags(0, -1);

9094
    if (!(vm = qemuDomObjFromDomain(dom)))
9095
        goto cleanup;
9096 9097

    if (!path || path[0] == '\0') {
9098 9099
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("NULL or empty path"));
9100
        goto cleanup;
9101 9102
    }

9103 9104
    /* Check the path belongs to this domain.  */
    if (!(actual = virDomainDiskPathByName(vm->def, path))) {
9105 9106
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path '%s'"), path);
9107
        goto cleanup;
9108
    }
9109
    path = actual;
9110

9111 9112 9113 9114 9115 9116 9117
    /* 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;
    }
9118

9119 9120 9121 9122 9123 9124 9125 9126 9127
    /* 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;
9128 9129
    }

9130 9131
    ret = 0;

9132
cleanup:
9133
    VIR_FORCE_CLOSE(fd);
9134
    if (vm)
9135
        virObjectUnlock(vm);
9136 9137 9138
    return ret;
}

R
Richard W.M. Jones 已提交
9139
static int
9140 9141 9142 9143
qemuDomainMemoryPeek(virDomainPtr dom,
                     unsigned long long offset, size_t size,
                     void *buffer,
                     unsigned int flags)
R
Richard W.M. Jones 已提交
9144
{
9145
    virQEMUDriverPtr driver = dom->conn->privateData;
9146
    virDomainObjPtr vm;
9147
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
9148
    int fd = -1, ret = -1;
9149
    qemuDomainObjPrivatePtr priv;
R
Richard W.M. Jones 已提交
9150

9151 9152
    virCheckFlags(VIR_MEMORY_VIRTUAL | VIR_MEMORY_PHYSICAL, -1);

9153
    if (!(vm = qemuDomObjFromDomain(dom)))
9154 9155
        goto cleanup;

9156
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
9157 9158
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
9159
        goto cleanup;
R
Richard W.M. Jones 已提交
9160 9161
    }

9162
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
9163 9164
        goto cleanup;

D
Daniel P. Berrange 已提交
9165
    if (!virDomainObjIsActive(vm)) {
9166 9167
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9168
        goto endjob;
R
Richard W.M. Jones 已提交
9169 9170
    }

9171
    if (virAsprintf(&tmp, "%s/qemu.mem.XXXXXX", driver->cacheDir) < 0) {
9172
        virReportOOMError();
9173
        goto endjob;
9174 9175
    }

R
Richard W.M. Jones 已提交
9176
    /* Create a temporary filename. */
9177
    if ((fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
9178
        virReportSystemError(errno,
9179
                             _("mkostemp(\"%s\") failed"), tmp);
9180
        goto endjob;
R
Richard W.M. Jones 已提交
9181 9182
    }

9183
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
9184

9185
    priv = vm->privateData;
9186
    qemuDomainObjEnterMonitor(driver, vm);
9187
    if (flags == VIR_MEMORY_VIRTUAL) {
9188
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
9189
            qemuDomainObjExitMonitor(driver, vm);
9190
            goto endjob;
9191
        }
9192
    } else {
9193
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
9194
            qemuDomainObjExitMonitor(driver, vm);
9195
            goto endjob;
9196
        }
R
Richard W.M. Jones 已提交
9197
    }
9198
    qemuDomainObjExitMonitor(driver, vm);
R
Richard W.M. Jones 已提交
9199 9200

    /* Read the memory file into buffer. */
9201
    if (saferead(fd, buffer, size) == (ssize_t) -1) {
9202 9203 9204
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
9205
        goto endjob;
R
Richard W.M. Jones 已提交
9206 9207 9208
    }

    ret = 0;
9209

9210
endjob:
9211
    if (qemuDomainObjEndJob(driver, vm) == 0)
9212
        vm = NULL;
9213

9214
cleanup:
9215
    VIR_FORCE_CLOSE(fd);
9216 9217
    if (tmp)
        unlink(tmp);
W
Wen Congyang 已提交
9218
    VIR_FREE(tmp);
9219
    if (vm)
9220
        virObjectUnlock(vm);
R
Richard W.M. Jones 已提交
9221 9222 9223
    return ret;
}

9224

9225 9226 9227 9228
static int qemuDomainGetBlockInfo(virDomainPtr dom,
                                  const char *path,
                                  virDomainBlockInfoPtr info,
                                  unsigned int flags) {
9229
    virQEMUDriverPtr driver = dom->conn->privateData;
9230 9231 9232 9233
    virDomainObjPtr vm;
    int ret = -1;
    int fd = -1;
    off_t end;
9234
    virStorageFileMetadata *meta = NULL;
9235
    virDomainDiskDefPtr disk = NULL;
9236
    struct stat sb;
9237
    int i;
9238
    int format;
9239 9240 9241

    virCheckFlags(0, -1);

9242
    if (!(vm = qemuDomObjFromDomain(dom)))
9243 9244 9245
        goto cleanup;

    if (!path || path[0] == '\0') {
9246 9247
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("NULL or empty path"));
9248 9249 9250 9251
        goto cleanup;
    }

    /* Check the path belongs to this domain. */
9252
    if ((i = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
9253 9254
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path %s not assigned to domain"), path);
9255 9256
        goto cleanup;
    }
9257 9258
    disk = vm->def->disks[i];
    if (!disk->src) {
9259 9260 9261
        virReportError(VIR_ERR_INVALID_ARG,
                       _("disk %s does not currently have a source assigned"),
                       path);
9262 9263 9264
        goto cleanup;
    }
    path = disk->src;
9265 9266

    /* The path is correct, now try to open it and get its size. */
9267
    fd = open(path, O_RDONLY);
9268 9269 9270 9271 9272 9273 9274
    if (fd == -1) {
        virReportSystemError(errno,
                             _("failed to open path '%s'"), path);
        goto cleanup;
    }

    /* Probe for magic formats */
9275 9276
    if (disk->format) {
        format = disk->format;
9277
    } else {
9278
        if (driver->allowDiskFormatProbing) {
9279 9280
            if ((format = virStorageFileProbeFormat(disk->src, driver->user,
                                                    driver->group)) < 0)
9281 9282
                goto cleanup;
        } else {
9283 9284 9285
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no disk format for %s and probing is disabled"),
                           disk->src);
9286
            goto cleanup;
9287
        }
9288 9289
    }

9290
    if (!(meta = virStorageFileGetMetadataFromFD(path, fd, format)))
9291 9292 9293 9294 9295 9296 9297 9298 9299 9300
        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)) {
9301
#ifndef WIN32
9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312 9313 9314
        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.
         */
9315
        end = lseek(fd, 0, SEEK_END);
9316 9317 9318 9319 9320 9321 9322 9323 9324 9325 9326
        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 */
9327 9328
    if (meta->capacity)
        info->capacity = meta->capacity;
9329

9330
    /* Set default value .. */
9331 9332
    info->allocation = info->physical;

9333 9334 9335
    /* ..but if guest is running & not using raw
       disk format and on a block device, then query
       highest allocated extent from QEMU */
9336
    if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
9337
        format != VIR_STORAGE_FILE_RAW &&
9338 9339
        S_ISBLK(sb.st_mode) &&
        virDomainObjIsActive(vm)) {
9340
        qemuDomainObjPrivatePtr priv = vm->privateData;
9341

9342 9343
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
            goto cleanup;
9344

9345
        if (virDomainObjIsActive(vm)) {
9346
            qemuDomainObjEnterMonitor(driver, vm);
9347 9348 9349 9350
            ret = qemuMonitorGetBlockExtent(priv->mon,
                                            disk->info.alias,
                                            &info->allocation);
            qemuDomainObjExitMonitor(driver, vm);
9351
        } else {
9352
            ret = 0;
9353
        }
9354 9355 9356

        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
9357 9358 9359
    } else {
        ret = 0;
    }
9360 9361

cleanup:
9362
    virStorageFileFreeMetadata(meta);
9363
    VIR_FORCE_CLOSE(fd);
9364
    if (vm)
9365
        virObjectUnlock(vm);
9366 9367 9368 9369
    return ret;
}


9370
static int
9371 9372 9373 9374
qemuDomainEventRegister(virConnectPtr conn,
                        virConnectDomainEventCallback callback,
                        void *opaque,
                        virFreeCallback freecb)
9375
{
9376
    virQEMUDriverPtr driver = conn->privateData;
9377 9378
    int ret;

9379
    qemuDriverLock(driver);
9380 9381 9382
    ret = virDomainEventStateRegister(conn,
                                      driver->domainEventState,
                                      callback, opaque, freecb);
9383
    qemuDriverUnlock(driver);
9384

9385
    return ret;
9386 9387
}

9388

9389
static int
9390 9391
qemuDomainEventDeregister(virConnectPtr conn,
                          virConnectDomainEventCallback callback)
9392
{
9393
    virQEMUDriverPtr driver = conn->privateData;
9394 9395
    int ret;

9396
    qemuDriverLock(driver);
9397 9398 9399
    ret = virDomainEventStateDeregister(conn,
                                        driver->domainEventState,
                                        callback);
9400
    qemuDriverUnlock(driver);
9401

9402
    return ret;
9403 9404
}

9405 9406 9407 9408 9409 9410 9411 9412 9413

static int
qemuDomainEventRegisterAny(virConnectPtr conn,
                           virDomainPtr dom,
                           int eventID,
                           virConnectDomainEventGenericCallback callback,
                           void *opaque,
                           virFreeCallback freecb)
{
9414
    virQEMUDriverPtr driver = conn->privateData;
9415 9416 9417
    int ret;

    qemuDriverLock(driver);
9418 9419 9420 9421
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
9422
        ret = -1;
9423 9424 9425 9426 9427 9428 9429 9430 9431 9432
    qemuDriverUnlock(driver);

    return ret;
}


static int
qemuDomainEventDeregisterAny(virConnectPtr conn,
                             int callbackID)
{
9433
    virQEMUDriverPtr driver = conn->privateData;
9434 9435 9436
    int ret;

    qemuDriverLock(driver);
9437 9438 9439
    ret = virDomainEventStateDeregisterID(conn,
                                          driver->domainEventState,
                                          callbackID);
9440 9441 9442 9443 9444 9445
    qemuDriverUnlock(driver);

    return ret;
}


9446 9447 9448
/*******************************************************************
 * Migration Protocol Version 2
 *******************************************************************/
D
Daniel Veillard 已提交
9449

C
Chris Lalancette 已提交
9450 9451 9452 9453 9454 9455
/* 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
9456 9457 9458 9459 9460 9461
qemuDomainMigratePrepareTunnel(virConnectPtr dconn,
                               virStreamPtr st,
                               unsigned long flags,
                               const char *dname,
                               unsigned long resource ATTRIBUTE_UNUSED,
                               const char *dom_xml)
C
Chris Lalancette 已提交
9462
{
9463
    virQEMUDriverPtr driver = dconn->privateData;
C
Chris Lalancette 已提交
9464
    int ret = -1;
9465

9466
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9467

9468 9469
    qemuDriverLock(driver);

C
Chris Lalancette 已提交
9470
    if (!dom_xml) {
9471 9472
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
C
Chris Lalancette 已提交
9473 9474 9475
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
9476 9477
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
C
Chris Lalancette 已提交
9478 9479 9480
        goto cleanup;
    }
    if (st == NULL) {
9481 9482
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("tunnelled migration requested but NULL stream passed"));
C
Chris Lalancette 已提交
9483 9484 9485
        goto cleanup;
    }

9486
    if (virLockManagerPluginUsesState(driver->lockManager)) {
9487 9488 9489
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
9490 9491 9492
        goto cleanup;
    }

9493 9494
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     NULL, 0, NULL, NULL, /* No cookies in v2 */
L
liguang 已提交
9495
                                     st, dname, dom_xml, flags);
9496

C
Chris Lalancette 已提交
9497
cleanup:
9498
    qemuDriverUnlock(driver);
C
Chris Lalancette 已提交
9499 9500 9501
    return ret;
}

D
Daniel Veillard 已提交
9502 9503 9504 9505
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
9506
static int ATTRIBUTE_NONNULL(5)
9507 9508 9509 9510 9511 9512 9513 9514 9515
qemuDomainMigratePrepare2(virConnectPtr dconn,
                          char **cookie ATTRIBUTE_UNUSED,
                          int *cookielen ATTRIBUTE_UNUSED,
                          const char *uri_in,
                          char **uri_out,
                          unsigned long flags,
                          const char *dname,
                          unsigned long resource ATTRIBUTE_UNUSED,
                          const char *dom_xml)
D
Daniel Veillard 已提交
9516
{
9517
    virQEMUDriverPtr driver = dconn->privateData;
9518
    int ret = -1;
9519

9520
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
9521

9522
    *uri_out = NULL;
D
Daniel Veillard 已提交
9523

9524
    qemuDriverLock(driver);
9525 9526

    if (virLockManagerPluginUsesState(driver->lockManager)) {
9527 9528 9529
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
9530 9531 9532
        goto cleanup;
    }

C
Chris Lalancette 已提交
9533 9534 9535 9536
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
9537 9538
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Tunnelled migration requested but invalid RPC method called"));
C
Chris Lalancette 已提交
9539 9540 9541
        goto cleanup;
    }

D
Daniel Veillard 已提交
9542
    if (!dom_xml) {
9543 9544
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
9545
        goto cleanup;
D
Daniel Veillard 已提交
9546 9547
    }

9548 9549 9550 9551
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
9552
    ret = qemuMigrationPrepareDirect(driver, dconn,
9553
                                     NULL, 0, NULL, NULL, /* No cookies */
9554
                                     uri_in, uri_out,
L
liguang 已提交
9555
                                     dname, dom_xml, flags);
D
Daniel Veillard 已提交
9556

9557 9558 9559 9560
cleanup:
    qemuDriverUnlock(driver);
    return ret;
}
C
Chris Lalancette 已提交
9561

D
Daniel Veillard 已提交
9562

9563 9564
/* Perform is the second step, and it runs on the source host. */
static int
9565 9566 9567 9568 9569 9570 9571
qemuDomainMigratePerform(virDomainPtr dom,
                         const char *cookie,
                         int cookielen,
                         const char *uri,
                         unsigned long flags,
                         const char *dname,
                         unsigned long resource)
9572
{
9573
    virQEMUDriverPtr driver = dom->conn->privateData;
9574 9575
    virDomainObjPtr vm;
    int ret = -1;
9576
    const char *dconnuri = NULL;
9577

9578
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
9579

9580
    qemuDriverLock(driver);
9581
    if (virLockManagerPluginUsesState(driver->lockManager)) {
9582 9583 9584
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
9585 9586 9587
        goto cleanup;
    }

9588
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
D
Daniel Veillard 已提交
9589
    if (!vm) {
9590 9591
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9592 9593
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9594
        goto cleanup;
D
Daniel Veillard 已提交
9595 9596
    }

9597 9598 9599 9600 9601
    if (flags & VIR_MIGRATE_PEER2PEER) {
        dconnuri = uri;
        uri = NULL;
    }

9602 9603 9604 9605 9606 9607
    /* 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
     */
9608
    ret = qemuMigrationPerform(driver, dom->conn, vm,
9609
                               NULL, dconnuri, uri, cookie, cookielen,
9610
                               NULL, NULL, /* No output cookies in v2 */
9611
                               flags, dname, resource, false);
9612

9613
cleanup:
9614
    qemuDriverUnlock(driver);
9615
    return ret;
D
Daniel Veillard 已提交
9616 9617
}

9618

D
Daniel Veillard 已提交
9619 9620
/* Finish is the third and final step, and it runs on the destination host. */
static virDomainPtr
9621 9622 9623 9624 9625 9626 9627
qemuDomainMigrateFinish2(virConnectPtr dconn,
                         const char *dname,
                         const char *cookie ATTRIBUTE_UNUSED,
                         int cookielen ATTRIBUTE_UNUSED,
                         const char *uri ATTRIBUTE_UNUSED,
                         unsigned long flags,
                         int retcode)
D
Daniel Veillard 已提交
9628
{
9629
    virQEMUDriverPtr driver = dconn->privateData;
9630 9631
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
9632

9633
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
C
Chris Lalancette 已提交
9634

9635
    qemuDriverLock(driver);
9636
    vm = virDomainFindByName(&driver->domains, dname);
D
Daniel Veillard 已提交
9637
    if (!vm) {
9638 9639
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), dname);
9640
        goto cleanup;
D
Daniel Veillard 已提交
9641 9642
    }

9643 9644 9645 9646
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
9647
    dom = qemuMigrationFinish(driver, dconn, vm,
9648
                              NULL, 0, NULL, NULL, /* No cookies */
9649
                              flags, retcode, false);
9650

9651
cleanup:
9652
    qemuDriverUnlock(driver);
9653
    return dom;
D
Daniel Veillard 已提交
9654 9655
}

9656

9657 9658 9659 9660 9661 9662
/*******************************************************************
 * Migration Protocol Version 3
 *******************************************************************/

static char *
qemuDomainMigrateBegin3(virDomainPtr domain,
9663
                        const char *xmlin,
9664 9665 9666
                        char **cookieout,
                        int *cookieoutlen,
                        unsigned long flags,
9667
                        const char *dname,
9668 9669
                        unsigned long resource ATTRIBUTE_UNUSED)
{
9670
    virQEMUDriverPtr driver = domain->conn->privateData;
9671 9672
    virDomainObjPtr vm;
    char *xml = NULL;
9673
    enum qemuDomainAsyncJob asyncJob;
9674

9675
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
9676 9677 9678 9679 9680 9681

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
9682 9683
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9684 9685 9686
        goto cleanup;
    }

9687 9688 9689
    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobStart(driver, vm, QEMU_ASYNC_JOB_MIGRATION_OUT) < 0)
            goto cleanup;
9690
        asyncJob = QEMU_ASYNC_JOB_MIGRATION_OUT;
9691
    } else {
W
Wen Congyang 已提交
9692
        if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
9693
            goto cleanup;
9694
        asyncJob = QEMU_ASYNC_JOB_NONE;
9695 9696
    }

L
liguang 已提交
9697
    if (!virDomainObjIsActive(vm) && !(flags & VIR_MIGRATE_OFFLINE)) {
9698 9699
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9700 9701 9702
        goto endjob;
    }

9703 9704 9705
    /* Check if there is any ejected media.
     * We don't want to require them on the destination.
     */
L
liguang 已提交
9706 9707
    if (!(flags & VIR_MIGRATE_OFFLINE) &&
        qemuDomainCheckEjectableMedia(driver, vm, asyncJob) < 0)
9708 9709
        goto endjob;

9710
    if (!(xml = qemuMigrationBegin(driver, vm, xmlin, dname,
9711 9712
                                   cookieout, cookieoutlen,
                                   flags)))
9713 9714 9715 9716 9717 9718 9719
        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.
         */
9720 9721 9722
        if (qemuDriverCloseCallbackSet(driver, vm, domain->conn,
                                       qemuMigrationCleanup) < 0)
            goto endjob;
9723 9724
        if (qemuMigrationJobContinue(vm) == 0) {
            vm = NULL;
9725 9726
            virReportError(VIR_ERR_OPERATION_FAILED,
                           "%s", _("domain disappeared"));
9727 9728 9729 9730 9731 9732 9733
            VIR_FREE(xml);
            if (cookieout)
                VIR_FREE(*cookieout);
        }
    } else {
        goto endjob;
    }
9734 9735

cleanup:
9736
    if (vm)
9737
        virObjectUnlock(vm);
9738 9739
    qemuDriverUnlock(driver);
    return xml;
9740 9741 9742 9743 9744 9745 9746 9747 9748 9749

endjob:
    if ((flags & VIR_MIGRATE_CHANGE_PROTECTION)) {
        if (qemuMigrationJobFinish(driver, vm) == 0)
            vm = NULL;
    } else {
        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
    }
    goto cleanup;
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)
{
9765
    virQEMUDriverPtr driver = dconn->privateData;
9766 9767
    int ret = -1;

9768
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9769 9770 9771 9772 9773 9774 9775 9776

    *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
         */
9777 9778
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("Tunnelled migration requested but invalid RPC method called"));
9779 9780 9781 9782
        goto cleanup;
    }

    if (!dom_xml) {
9783 9784
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
9785 9786 9787 9788 9789 9790 9791
        goto cleanup;
    }

    ret = qemuMigrationPrepareDirect(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
                                     uri_in, uri_out,
L
liguang 已提交
9792
                                     dname, dom_xml, flags);
9793 9794 9795 9796 9797 9798 9799 9800 9801 9802 9803 9804 9805 9806 9807 9808 9809 9810 9811

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)
{
9812
    virQEMUDriverPtr driver = dconn->privateData;
9813 9814
    int ret = -1;

9815
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9816 9817

    if (!dom_xml) {
9818 9819
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("no domain XML passed"));
9820 9821 9822
        goto cleanup;
    }
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
9823 9824
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("PrepareTunnel called but no TUNNELLED flag set"));
9825 9826 9827
        goto cleanup;
    }
    if (st == NULL) {
9828 9829
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("tunnelled migration requested but NULL stream passed"));
9830 9831 9832 9833 9834 9835 9836
        goto cleanup;
    }

    qemuDriverLock(driver);
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
L
liguang 已提交
9837
                                     st, dname, dom_xml, flags);
9838 9839 9840 9841 9842 9843 9844 9845 9846
    qemuDriverUnlock(driver);

cleanup:
    return ret;
}


static int
qemuDomainMigratePerform3(virDomainPtr dom,
9847
                          const char *xmlin,
9848 9849 9850 9851
                          const char *cookiein,
                          int cookieinlen,
                          char **cookieout,
                          int *cookieoutlen,
9852
                          const char *dconnuri,
9853 9854 9855 9856 9857
                          const char *uri,
                          unsigned long flags,
                          const char *dname,
                          unsigned long resource)
{
9858
    virQEMUDriverPtr driver = dom->conn->privateData;
9859 9860 9861
    virDomainObjPtr vm;
    int ret = -1;

9862
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9863 9864 9865 9866 9867 9868

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(dom->uuid, uuidstr);
9869 9870
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9871 9872 9873
        goto cleanup;
    }

9874
    ret = qemuMigrationPerform(driver, dom->conn, vm, xmlin,
9875
                               dconnuri, uri, cookiein, cookieinlen,
9876
                               cookieout, cookieoutlen,
9877
                               flags, dname, resource, true);
9878 9879 9880 9881 9882 9883 9884

cleanup:
    qemuDriverUnlock(driver);
    return ret;
}


9885
static virDomainPtr
9886 9887 9888 9889 9890 9891
qemuDomainMigrateFinish3(virConnectPtr dconn,
                         const char *dname,
                         const char *cookiein,
                         int cookieinlen,
                         char **cookieout,
                         int *cookieoutlen,
9892
                         const char *dconnuri ATTRIBUTE_UNUSED,
9893 9894
                         const char *uri ATTRIBUTE_UNUSED,
                         unsigned long flags,
9895
                         int cancelled)
9896
{
9897
    virQEMUDriverPtr driver = dconn->privateData;
9898
    virDomainObjPtr vm;
9899
    virDomainPtr dom = NULL;
9900

9901
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
9902 9903 9904 9905

    qemuDriverLock(driver);
    vm = virDomainFindByName(&driver->domains, dname);
    if (!vm) {
9906 9907
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), dname);
9908 9909 9910
        goto cleanup;
    }

9911 9912 9913 9914
    dom = qemuMigrationFinish(driver, dconn, vm,
                              cookiein, cookieinlen,
                              cookieout, cookieoutlen,
                              flags, cancelled, true);
9915 9916 9917

cleanup:
    qemuDriverUnlock(driver);
9918
    return dom;
9919 9920 9921 9922 9923 9924 9925 9926 9927
}

static int
qemuDomainMigrateConfirm3(virDomainPtr domain,
                          const char *cookiein,
                          int cookieinlen,
                          unsigned long flags,
                          int cancelled)
{
9928
    virQEMUDriverPtr driver = domain->conn->privateData;
9929 9930
    virDomainObjPtr vm;
    int ret = -1;
9931
    enum qemuMigrationJobPhase phase;
9932

9933
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
9934 9935 9936 9937 9938 9939

    qemuDriverLock(driver);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(domain->uuid, uuidstr);
9940 9941
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
9942 9943 9944
        goto cleanup;
    }

9945
    if (!qemuMigrationJobIsActive(vm, QEMU_ASYNC_JOB_MIGRATION_OUT))
9946 9947
        goto cleanup;

9948 9949 9950 9951 9952 9953
    if (cancelled)
        phase = QEMU_MIGRATION_PHASE_CONFIRM3_CANCELLED;
    else
        phase = QEMU_MIGRATION_PHASE_CONFIRM3;

    qemuMigrationJobStartPhase(driver, vm, phase);
9954
    qemuDriverCloseCallbackUnset(driver, vm, qemuMigrationCleanup);
9955

9956 9957
    ret = qemuMigrationConfirm(driver, domain->conn, vm,
                               cookiein, cookieinlen,
9958 9959
                               flags, cancelled);

9960
    if (qemuMigrationJobFinish(driver, vm) == 0) {
9961 9962 9963 9964 9965
        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);
9966
        qemuDomainRemoveInactive(driver, vm);
9967 9968 9969
        vm = NULL;
    }

9970
cleanup:
9971
    if (vm)
9972
        virObjectUnlock(vm);
9973 9974 9975 9976 9977
    qemuDriverUnlock(driver);
    return ret;
}


9978
static int
9979 9980 9981 9982 9983
qemuNodeDeviceGetPciInfo(virNodeDevicePtr dev,
                         unsigned *domain,
                         unsigned *bus,
                         unsigned *slot,
                         unsigned *function)
9984 9985 9986 9987 9988 9989 9990 9991 9992 9993
{
    virNodeDeviceDefPtr def = NULL;
    virNodeDevCapsDefPtr cap;
    char *xml = NULL;
    int ret = -1;

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

9994
    def = virNodeDeviceDefParseString(xml, EXISTING_DEVICE, NULL);
9995 9996 9997 9998 9999 10000 10001 10002 10003 10004 10005 10006 10007 10008 10009 10010 10011
    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) {
10012 10013
        virReportError(VIR_ERR_INVALID_ARG,
                       _("device %s is not a PCI device"), dev->name);
10014 10015 10016 10017 10018 10019 10020 10021 10022 10023 10024
        goto out;
    }

    ret = 0;
out:
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
    return ret;
}

static int
10025
qemuNodeDeviceDettach(virNodeDevicePtr dev)
10026
{
10027
    virQEMUDriverPtr driver = dev->conn->privateData;
10028 10029 10030
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;
10031
    bool in_inactive_list = false;
10032

10033
    if (qemuNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
10034 10035
        return -1;

10036
    pci = pciGetDevice(domain, bus, slot, function);
10037 10038 10039
    if (!pci)
        return -1;

10040
    qemuDriverLock(driver);
10041 10042 10043
    in_inactive_list = pciDeviceListFind(driver->inactivePciHostdevs, pci);

    if (pciDettachDevice(pci, driver->activePciHostdevs,
10044
                         driver->inactivePciHostdevs, "pci-stub") < 0)
10045 10046 10047 10048
        goto out;

    ret = 0;
out:
10049
    qemuDriverUnlock(driver);
10050 10051
    if (in_inactive_list)
        pciFreeDevice(pci);
10052 10053 10054 10055
    return ret;
}

static int
10056
qemuNodeDeviceReAttach(virNodeDevicePtr dev)
10057
{
10058
    virQEMUDriverPtr driver = dev->conn->privateData;
10059
    pciDevice *pci;
10060
    pciDevice *other;
10061 10062 10063
    unsigned domain, bus, slot, function;
    int ret = -1;

10064
    if (qemuNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
10065 10066
        return -1;

10067
    pci = pciGetDevice(domain, bus, slot, function);
10068 10069 10070
    if (!pci)
        return -1;

10071 10072 10073 10074 10075
    other = pciDeviceListFind(driver->activePciHostdevs, pci);
    if (other) {
        const char *other_name = pciDeviceGetUsedBy(other);

        if (other_name)
10076 10077 10078
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is still in use by domain %s"),
                           pciDeviceGetName(pci), other_name);
10079
        else
10080 10081 10082
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is still in use"),
                           pciDeviceGetName(pci));
10083 10084
    }

10085 10086
    pciDeviceReAttachInit(pci);

10087
    qemuDriverLock(driver);
10088
    if (pciReAttachDevice(pci, driver->activePciHostdevs,
10089
                          driver->inactivePciHostdevs, "pci-stub") < 0)
10090 10091 10092 10093
        goto out;

    ret = 0;
out:
10094
    qemuDriverUnlock(driver);
10095
    pciFreeDevice(pci);
10096 10097 10098 10099
    return ret;
}

static int
10100
qemuNodeDeviceReset(virNodeDevicePtr dev)
10101
{
10102
    virQEMUDriverPtr driver = dev->conn->privateData;
10103 10104 10105 10106
    pciDevice *pci;
    unsigned domain, bus, slot, function;
    int ret = -1;

10107
    if (qemuNodeDeviceGetPciInfo(dev, &domain, &bus, &slot, &function) < 0)
10108 10109
        return -1;

10110
    pci = pciGetDevice(domain, bus, slot, function);
10111 10112 10113
    if (!pci)
        return -1;

10114 10115
    qemuDriverLock(driver);

10116 10117
    if (pciResetDevice(pci, driver->activePciHostdevs,
                       driver->inactivePciHostdevs) < 0)
10118 10119 10120 10121
        goto out;

    ret = 0;
out:
10122
    qemuDriverUnlock(driver);
10123
    pciFreeDevice(pci);
10124 10125 10126
    return ret;
}

10127 10128 10129
static int
qemuCPUCompare(virConnectPtr conn,
               const char *xmlDesc,
E
Eric Blake 已提交
10130
               unsigned int flags)
10131
{
10132
    virQEMUDriverPtr driver = conn->privateData;
10133 10134
    int ret = VIR_CPU_COMPARE_ERROR;

E
Eric Blake 已提交
10135 10136
    virCheckFlags(0, VIR_CPU_COMPARE_ERROR);

10137 10138
    qemuDriverLock(driver);

10139
    if (!driver->caps) {
10140 10141
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       "%s", _("cannot get host capabilities"));
J
Jiri Denemark 已提交
10142 10143
    } else if (!driver->caps->host.cpu ||
               !driver->caps->host.cpu->model) {
10144 10145
        VIR_WARN("cannot get host CPU capabilities");
        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
E
Eric Blake 已提交
10146
    } else {
10147
        ret = cpuCompareXML(driver->caps->host.cpu, xmlDesc);
E
Eric Blake 已提交
10148
    }
10149 10150 10151 10152 10153 10154

    qemuDriverUnlock(driver);

    return ret;
}

10155

10156 10157 10158 10159
static char *
qemuCPUBaseline(virConnectPtr conn ATTRIBUTE_UNUSED,
                const char **xmlCPUs,
                unsigned int ncpus,
E
Eric Blake 已提交
10160
                unsigned int flags)
10161 10162 10163
{
    char *cpu;

E
Eric Blake 已提交
10164 10165
    virCheckFlags(0, NULL);

10166 10167 10168 10169 10170
    cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0);

    return cpu;
}

10171 10172 10173 10174 10175 10176 10177

static int qemuDomainGetJobInfo(virDomainPtr dom,
                                virDomainJobInfoPtr info) {
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

10178
    if (!(vm = qemuDomObjFromDomain(dom)))
10179 10180 10181 10182 10183
        goto cleanup;

    priv = vm->privateData;

    if (virDomainObjIsActive(vm)) {
10184
        if (priv->job.asyncJob && !priv->job.dump_memory_only) {
10185
            memcpy(info, &priv->job.info, sizeof(*info));
10186 10187 10188 10189 10190 10191

            /* 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
             */
10192
            if (virTimeMillisNow(&info->timeElapsed) < 0)
10193
                goto cleanup;
10194
            info->timeElapsed -= priv->job.start;
10195 10196 10197 10198 10199
        } else {
            memset(info, 0, sizeof(*info));
            info->type = VIR_DOMAIN_JOB_NONE;
        }
    } else {
10200 10201
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10202 10203 10204 10205 10206 10207 10208
        goto cleanup;
    }

    ret = 0;

cleanup:
    if (vm)
10209
        virObjectUnlock(vm);
10210 10211 10212 10213
    return ret;
}


10214
static int qemuDomainAbortJob(virDomainPtr dom) {
10215
    virQEMUDriverPtr driver = dom->conn->privateData;
10216 10217 10218 10219
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

10220
    if (!(vm = qemuDomObjFromDomain(dom)))
10221 10222
        goto cleanup;

10223 10224
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_ABORT) < 0)
        goto cleanup;
10225

10226
    if (!virDomainObjIsActive(vm)) {
10227 10228
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10229
        goto endjob;
10230 10231
    }

10232 10233
    priv = vm->privateData;

10234
    if (!priv->job.asyncJob || priv->job.dump_memory_only) {
10235 10236
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("no job is active on the domain"));
10237 10238
        goto endjob;
    } else if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) {
10239 10240 10241
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot abort incoming migration;"
                         " use virDomainDestroy instead"));
10242 10243 10244 10245
        goto endjob;
    }

    VIR_DEBUG("Cancelling job at client request");
10246
    qemuDomainObjAbortAsyncJob(vm);
10247
    qemuDomainObjEnterMonitor(driver, vm);
10248 10249 10250 10251 10252 10253
    ret = qemuMonitorMigrateCancel(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);

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

cleanup:
    if (vm)
10257
        virObjectUnlock(vm);
10258 10259 10260 10261
    return ret;
}


10262 10263 10264 10265 10266
static int
qemuDomainMigrateSetMaxDowntime(virDomainPtr dom,
                                unsigned long long downtime,
                                unsigned int flags)
{
10267
    virQEMUDriverPtr driver = dom->conn->privateData;
10268 10269 10270 10271
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

10272
    virCheckFlags(0, -1);
10273

10274 10275
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
10276

10277 10278 10279
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
        goto cleanup;

10280
    if (!virDomainObjIsActive(vm)) {
10281 10282
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10283
        goto endjob;
10284 10285 10286 10287
    }

    priv = vm->privateData;

10288
    if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
10289 10290
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not being migrated"));
10291
        goto endjob;
10292 10293
    }

10294
    VIR_DEBUG("Setting migration downtime to %llums", downtime);
10295
    qemuDomainObjEnterMonitor(driver, vm);
10296 10297 10298 10299 10300 10301
    ret = qemuMonitorSetMigrationDowntime(priv->mon, downtime);
    qemuDomainObjExitMonitor(driver, vm);

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

cleanup:
    if (vm)
10305
        virObjectUnlock(vm);
10306 10307 10308
    return ret;
}

10309 10310 10311 10312 10313
static int
qemuDomainMigrateSetMaxSpeed(virDomainPtr dom,
                             unsigned long bandwidth,
                             unsigned int flags)
{
10314
    virQEMUDriverPtr driver = dom->conn->privateData;
10315 10316 10317 10318 10319 10320
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

10321 10322
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
10323 10324

    priv = vm->privateData;
10325 10326 10327
    if (virDomainObjIsActive(vm)) {
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
            goto cleanup;
10328

10329
        if (!virDomainObjIsActive(vm)) {
10330 10331
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("domain is not running"));
10332 10333 10334
            goto endjob;
        }

10335 10336 10337 10338
        VIR_DEBUG("Setting migration bandwidth to %luMbs", bandwidth);
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSetMigrationSpeed(priv->mon, bandwidth);
        qemuDomainObjExitMonitor(driver, vm);
10339

10340 10341
        if (ret == 0)
            priv->migMaxBandwidth = bandwidth;
10342

10343
endjob:
10344 10345 10346 10347 10348 10349
        if (qemuDomainObjEndJob(driver, vm) == 0)
            vm = NULL;
    } else {
        priv->migMaxBandwidth = bandwidth;
        ret = 0;
    }
10350 10351 10352

cleanup:
    if (vm)
10353
        virObjectUnlock(vm);
10354 10355 10356
    return ret;
}

10357 10358 10359 10360 10361 10362
static int
qemuDomainMigrateGetMaxSpeed(virDomainPtr dom,
                             unsigned long *bandwidth,
                             unsigned int flags)
{
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
10363
    qemuDomainObjPrivatePtr priv;
10364 10365 10366 10367
    int ret = -1;

    virCheckFlags(0, -1);

10368
    if (!(vm = qemuDomObjFromDomain(dom)))
10369 10370
        goto cleanup;

J
Jim Fehlig 已提交
10371 10372
    priv = vm->privateData;
    *bandwidth = priv->migMaxBandwidth;
10373 10374 10375 10376
    ret = 0;

cleanup:
    if (vm)
10377
        virObjectUnlock(vm);
10378 10379 10380
    return ret;
}

10381 10382 10383 10384 10385 10386 10387 10388 10389 10390 10391 10392
typedef enum {
    VIR_DISK_CHAIN_NO_ACCESS,
    VIR_DISK_CHAIN_READ_ONLY,
    VIR_DISK_CHAIN_READ_WRITE,
} qemuDomainDiskChainMode;

/* Several operations end up adding or removing a single element of a
 * disk backing file chain; this helper function ensures that the lock
 * manager, cgroup device controller, and security manager labelling
 * are all aware of each new file before it is added to a chain, and
 * can revoke access to a file no longer needed in a chain.  */
static int
10393
qemuDomainPrepareDiskChainElement(virQEMUDriverPtr driver,
10394 10395 10396
                                  virDomainObjPtr vm,
                                  virCgroupPtr cgroup,
                                  virDomainDiskDefPtr disk,
10397
                                  const char *file,
10398 10399 10400 10401 10402 10403 10404 10405 10406 10407 10408
                                  qemuDomainDiskChainMode mode)
{
    /* The easiest way to label a single file with the same
     * permissions it would have as if part of the disk chain is to
     * temporarily modify the disk in place.  */
    char *origsrc = disk->src;
    int origformat = disk->format;
    virStorageFileMetadataPtr origchain = disk->backingChain;
    bool origreadonly = disk->readonly;
    int ret = -1;

10409
    disk->src = (char *) file; /* casting away const is safe here */
10410 10411 10412 10413 10414 10415 10416 10417 10418 10419 10420 10421 10422 10423 10424 10425 10426 10427 10428 10429 10430 10431 10432 10433 10434 10435 10436 10437 10438 10439 10440
    disk->format = VIR_STORAGE_FILE_RAW;
    disk->backingChain = NULL;
    disk->readonly = mode == VIR_DISK_CHAIN_READ_ONLY;

    if (mode == VIR_DISK_CHAIN_NO_ACCESS) {
        if (virSecurityManagerRestoreImageLabel(driver->securityManager,
                                                vm->def, disk) < 0)
            VIR_WARN("Unable to restore security label on %s", disk->src);
        if (cgroup && qemuTeardownDiskCgroup(vm, cgroup, disk) < 0)
            VIR_WARN("Failed to teardown cgroup for disk path %s", disk->src);
        if (virDomainLockDiskDetach(driver->lockManager, vm, disk) < 0)
            VIR_WARN("Unable to release lock on %s", disk->src);
    } else if (virDomainLockDiskAttach(driver->lockManager, driver->uri,
                                       vm, disk) < 0 ||
               (cgroup && qemuSetupDiskCgroup(vm, cgroup, disk) < 0) ||
               virSecurityManagerSetImageLabel(driver->securityManager,
                                               vm->def, disk) < 0) {
        goto cleanup;
    }

    ret = 0;

cleanup:
    disk->src = origsrc;
    disk->format = origformat;
    disk->backingChain = origchain;
    disk->readonly = origreadonly;
    return ret;
}


C
Chris Lalancette 已提交
10441

10442
/* this function expects the driver lock to be held by the caller */
10443
static int
10444
qemuDomainSnapshotFSFreeze(virQEMUDriverPtr driver,
10445 10446 10447 10448 10449
                           virDomainObjPtr vm) {
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int freezed;

    if (priv->agentError) {
10450
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
10451 10452
                       _("QEMU guest agent is not "
                         "available due to an error"));
10453 10454 10455
        return -1;
    }
    if (!priv->agent) {
10456 10457
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("QEMU guest agent is not configured"));
10458 10459 10460
        return -1;
    }

10461
    qemuDomainObjEnterAgentWithDriver(driver, vm);
10462
    freezed = qemuAgentFSFreeze(priv->agent);
10463
    qemuDomainObjExitAgentWithDriver(driver, vm);
10464 10465 10466 10467 10468

    return freezed;
}

static int
10469
qemuDomainSnapshotFSThaw(virQEMUDriverPtr driver,
E
Eric Blake 已提交
10470 10471
                         virDomainObjPtr vm, bool report)
{
10472 10473
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int thawed;
E
Eric Blake 已提交
10474
    virErrorPtr err = NULL;
10475 10476

    if (priv->agentError) {
E
Eric Blake 已提交
10477
        if (report)
10478
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
10479 10480
                           _("QEMU guest agent is not "
                             "available due to an error"));
10481 10482 10483
        return -1;
    }
    if (!priv->agent) {
E
Eric Blake 已提交
10484
        if (report)
10485 10486
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
10487 10488 10489 10490
        return -1;
    }

    qemuDomainObjEnterAgent(driver, vm);
E
Eric Blake 已提交
10491
    if (!report)
10492
        err = virSaveLastError();
10493
    thawed = qemuAgentFSThaw(priv->agent);
10494 10495
    if (!report)
        virSetError(err);
10496 10497
    qemuDomainObjExitAgent(driver, vm);

10498
    virFreeError(err);
10499 10500 10501
    return thawed;
}

10502 10503
/* The domain is expected to be locked and inactive. */
static int
10504
qemuDomainSnapshotCreateInactiveInternal(virQEMUDriverPtr driver,
10505 10506
                                         virDomainObjPtr vm,
                                         virDomainSnapshotObjPtr snap)
10507
{
E
Eric Blake 已提交
10508
    return qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-c", false);
10509 10510
}

10511 10512
/* The domain is expected to be locked and inactive. */
static int
10513
qemuDomainSnapshotCreateInactiveExternal(virQEMUDriverPtr driver,
10514 10515 10516 10517 10518 10519 10520 10521 10522 10523 10524 10525 10526 10527 10528 10529 10530 10531 10532 10533 10534 10535 10536 10537 10538 10539 10540 10541 10542 10543 10544 10545 10546 10547 10548 10549 10550 10551 10552 10553 10554 10555 10556 10557 10558 10559 10560 10561 10562 10563 10564 10565 10566 10567 10568 10569 10570 10571 10572 10573 10574 10575 10576 10577 10578 10579 10580 10581 10582 10583 10584 10585 10586 10587 10588 10589 10590 10591 10592 10593 10594 10595 10596 10597 10598 10599 10600 10601 10602 10603 10604 10605 10606 10607 10608 10609 10610 10611 10612 10613 10614 10615 10616 10617 10618 10619 10620 10621 10622 10623
                                         virDomainObjPtr vm,
                                         virDomainSnapshotObjPtr snap,
                                         bool reuse)
{
    int i;
    virDomainSnapshotDiskDefPtr snapdisk;
    virDomainDiskDefPtr defdisk;
    virCommandPtr cmd = NULL;
    const char *qemuImgPath;
    virBitmapPtr created;

    int ret = -1;

    if (!(qemuImgPath = qemuFindQemuImgBinary(driver)))
        return -1;

    if (!(created = virBitmapNew(snap->def->ndisks))) {
        virReportOOMError();
        return -1;
    }

    /* If reuse is true, then qemuDomainSnapshotPrepare already
     * ensured that the new files exist, and it was up to the user to
     * create them correctly.  */
    for (i = 0; i < snap->def->ndisks && !reuse; i++) {
        snapdisk = &(snap->def->disks[i]);
        defdisk = snap->def->dom->disks[snapdisk->index];
        if (snapdisk->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL)
            continue;

        if (!snapdisk->format)
            snapdisk->format = VIR_STORAGE_FILE_QCOW2;

        /* creates cmd line args: qemu-img create -f qcow2 -o */
        if (!(cmd = virCommandNewArgList(qemuImgPath,
                                         "create",
                                         "-f",
                                         virStorageFileFormatTypeToString(snapdisk->format),
                                         "-o",
                                         NULL)))
            goto cleanup;

        if (defdisk->format > 0) {
            /* adds cmd line arg: backing_file=/path/to/backing/file,backing_fmd=format */
            virCommandAddArgFormat(cmd, "backing_file=%s,backing_fmt=%s",
                                   defdisk->src,
                                   virStorageFileFormatTypeToString(defdisk->format));
        } else {
            if (!driver->allowDiskFormatProbing) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("unknown image format of '%s' and "
                                 "format probing is disabled"),
                               defdisk->src);
                goto cleanup;
            }

            /* adds cmd line arg: backing_file=/path/to/backing/file */
            virCommandAddArgFormat(cmd, "backing_file=%s", defdisk->src);
        }

        /* adds cmd line args: /path/to/target/file */
        virCommandAddArg(cmd, snapdisk->file);

        /* If the target does not exist, we're going to create it possibly */
        if (!virFileExists(snapdisk->file))
            ignore_value(virBitmapSetBit(created, i));

        if (virCommandRun(cmd, NULL) < 0)
            goto cleanup;

        virCommandFree(cmd);
        cmd = NULL;
    }

    /* update disk definitions */
    for (i = 0; i < snap->def->ndisks; i++) {
        snapdisk = &(snap->def->disks[i]);
        defdisk = vm->def->disks[snapdisk->index];

        if (snapdisk->snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
            VIR_FREE(defdisk->src);
            if (!(defdisk->src = strdup(snapdisk->file))) {
                /* we cannot rollback here in a sane way */
                virReportOOMError();
                goto cleanup;
            }
            defdisk->format = snapdisk->format;
        }
    }

    ret = 0;

cleanup:
    virCommandFree(cmd);

    /* unlink images if creation has failed */
    if (ret < 0) {
        ssize_t bit = -1;
        while ((bit = virBitmapNextSetBit(created, bit)) >= 0) {
            snapdisk = &(snap->def->disks[bit]);
            if (unlink(snapdisk->file) < 0)
                VIR_WARN("Failed to remove snapshot image '%s'",
                         snapdisk->file);
        }
    }
    virBitmapFree(created);

    return ret;
}

10624

10625 10626
/* The domain is expected to be locked and active. */
static int
10627
qemuDomainSnapshotCreateActiveInternal(virConnectPtr conn,
10628
                                       virQEMUDriverPtr driver,
10629 10630 10631
                                       virDomainObjPtr *vmptr,
                                       virDomainSnapshotObjPtr snap,
                                       unsigned int flags)
10632 10633 10634
{
    virDomainObjPtr vm = *vmptr;
    qemuDomainObjPrivatePtr priv = vm->privateData;
10635
    virDomainEventPtr event = NULL;
10636 10637
    bool resume = false;
    int ret = -1;
10638

10639
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
10640 10641
        return -1;

10642
    if (!virDomainObjIsActive(vm)) {
10643 10644
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10645 10646 10647
        goto endjob;
    }

J
Jiri Denemark 已提交
10648
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
10649 10650 10651 10652
        /* 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.
         */
10653 10654
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_NONE) < 0)
10655 10656 10657 10658
            goto cleanup;

        resume = true;
        if (!virDomainObjIsActive(vm)) {
10659 10660
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
10661 10662 10663 10664
            goto cleanup;
        }
    }

10665
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
10666 10667
    ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name);
    qemuDomainObjExitMonitorWithDriver(driver, vm);
10668 10669 10670 10671 10672 10673
    if (ret < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
        event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
10674
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
10675 10676 10677 10678 10679 10680 10681
        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;
    }
10682

10683 10684
cleanup:
    if (resume && virDomainObjIsActive(vm) &&
J
Jiri Denemark 已提交
10685
        qemuProcessStartCPUs(driver, vm, conn,
10686
                             VIR_DOMAIN_RUNNING_UNPAUSED,
10687 10688 10689 10690 10691 10692 10693 10694
                             QEMU_ASYNC_JOB_NONE) < 0) {
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
        if (virGetLastError() == NULL) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("resuming after snapshot failed"));
        }
10695 10696
    }

10697
endjob:
10698
    if (vm && qemuDomainObjEndJob(driver, vm) == 0) {
10699 10700
        /* Only possible if a transient vm quit while our locks were down,
         * in which case we don't want to save snapshot metadata.  */
10701
        *vmptr = NULL;
10702 10703
        ret = -1;
    }
10704

10705 10706 10707
    if (event)
        qemuDomainEventQueue(driver, event);

10708 10709 10710
    return ret;
}

10711
static int
E
Eric Blake 已提交
10712 10713
qemuDomainSnapshotPrepare(virDomainObjPtr vm, virDomainSnapshotDefPtr def,
                          unsigned int *flags)
10714 10715 10716 10717 10718
{
    int ret = -1;
    int i;
    bool active = virDomainObjIsActive(vm);
    struct stat st;
10719
    bool reuse = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
10720
    bool atomic = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC) != 0;
10721
    bool found_internal = false;
10722 10723
    int external = 0;
    qemuDomainObjPrivatePtr priv = vm->privateData;
10724

E
Eric Blake 已提交
10725 10726
    if (def->state == VIR_DOMAIN_DISK_SNAPSHOT &&
        reuse && !qemuCapsGet(priv->caps, QEMU_CAPS_TRANSACTION)) {
10727 10728
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("reuse is not supported with this QEMU binary"));
10729 10730 10731
        goto cleanup;
    }

10732 10733
    for (i = 0; i < def->ndisks; i++) {
        virDomainSnapshotDiskDefPtr disk = &def->disks[i];
E
Eric Blake 已提交
10734
        virDomainDiskDefPtr dom_disk = vm->def->disks[i];
10735 10736

        switch (disk->snapshot) {
E
Eric Blake 已提交
10737
        case VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL:
E
Eric Blake 已提交
10738 10739 10740 10741 10742
            if (def->state != VIR_DOMAIN_DISK_SNAPSHOT &&
                dom_disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
                (dom_disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG ||
                 dom_disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD)) {
                break;
10743
            }
10744 10745
            if (vm->def->disks[i]->format > 0 &&
                vm->def->disks[i]->format != VIR_STORAGE_FILE_QCOW2) {
10746 10747 10748 10749
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("internal snapshot for disk %s unsupported "
                                 "for storage type %s"),
                               disk->name,
10750 10751
                               virStorageFileFormatTypeToString(
                                   vm->def->disks[i]->format));
10752 10753
                goto cleanup;
            }
E
Eric Blake 已提交
10754 10755 10756 10757 10758 10759 10760
            if (def->state == VIR_DOMAIN_DISK_SNAPSHOT && active) {
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("active qemu domains require external disk "
                                 "snapshots; disk %s requested internal"),
                               disk->name);
                goto cleanup;
            }
10761
            found_internal = true;
10762 10763
            break;

E
Eric Blake 已提交
10764
        case VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL:
10765 10766 10767 10768
            if (!disk->format) {
                disk->format = VIR_STORAGE_FILE_QCOW2;
            } else if (disk->format != VIR_STORAGE_FILE_QCOW2 &&
                       disk->format != VIR_STORAGE_FILE_QED) {
10769 10770 10771
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("external snapshot format for disk %s "
                                 "is unsupported: %s"),
10772 10773
                               disk->name,
                               virStorageFileFormatTypeToString(disk->format));
10774 10775 10776 10777 10778 10779 10780 10781
                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;
10782 10783 10784 10785 10786
                } else if (reuse) {
                    virReportSystemError(errno,
                                         _("missing existing file for disk %s: %s"),
                                         disk->name, disk->file);
                    goto cleanup;
10787
                }
10788
            } else if (!S_ISBLK(st.st_mode) && st.st_size && !reuse) {
10789 10790 10791 10792
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("external snapshot file for disk %s already "
                                 "exists and is not a block device: %s"),
                               disk->name, disk->file);
10793 10794
                goto cleanup;
            }
10795
            external++;
10796 10797
            break;

E
Eric Blake 已提交
10798
        case VIR_DOMAIN_SNAPSHOT_LOCATION_NONE:
10799 10800
            break;

E
Eric Blake 已提交
10801
        case VIR_DOMAIN_SNAPSHOT_LOCATION_DEFAULT:
10802
        default:
10803 10804
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("unexpected code path"));
10805 10806 10807 10808
            goto cleanup;
        }
    }

10809 10810 10811
    /* internal snapshot requires a disk image to store the memory image to */
    if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL &&
        !found_internal) {
10812
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
10813
                       _("internal checkpoints require at least "
10814
                         "one disk to be selected for snapshot"));
10815 10816
        goto cleanup;
    }
10817

10818 10819 10820 10821 10822 10823 10824 10825 10826 10827 10828 10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839
    /* disk snapshot requires at least one disk */
    if (def->state == VIR_DOMAIN_DISK_SNAPSHOT && !external) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("disk-only snapshots require at least "
                         "one disk to be selected for snapshot"));
        goto cleanup;
    }

    /* For now, we don't allow mixing internal and external disks.
     * XXX technically, we could mix internal and external disks for
     * offline snapshots */
    if (found_internal && external) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("mixing internal and external snapshots is not "
                         "supported yet"));
        goto cleanup;
    }

    /* Alter flags to let later users know what we learned.  */
    if (external && !active)
        *flags |= VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY;

E
Eric Blake 已提交
10840
    if (def->state != VIR_DOMAIN_DISK_SNAPSHOT && active) {
10841
        if (external == 1 ||
10842
            qemuCapsGet(priv->caps, QEMU_CAPS_TRANSACTION)) {
10843 10844
            *flags |= VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC;
        } else if (atomic && external > 1) {
10845 10846 10847
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("atomic live snapshot of multiple disks "
                             "is unsupported"));
10848 10849 10850
            goto cleanup;
        }
    }
10851 10852 10853 10854 10855 10856 10857 10858 10859

    ret = 0;

cleanup:
    return ret;
}

/* The domain is expected to hold monitor lock.  */
static int
10860
qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver,
10861
                                         virDomainObjPtr vm,
10862
                                         virCgroupPtr cgroup,
10863
                                         virDomainSnapshotDiskDefPtr snap,
10864
                                         virDomainDiskDefPtr disk,
10865
                                         virDomainDiskDefPtr persistDisk,
10866 10867
                                         virJSONValuePtr actions,
                                         bool reuse)
10868 10869 10870 10871
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *device = NULL;
    char *source = NULL;
10872 10873
    int format = snap->format;
    const char *formatStr = NULL;
10874
    char *persistSource = NULL;
10875
    int ret = -1;
10876 10877
    int fd = -1;
    bool need_unlink = false;
10878

E
Eric Blake 已提交
10879
    if (snap->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
10880 10881
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected code path"));
10882 10883 10884 10885 10886
        return -1;
    }

    if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0 ||
        !(source = strdup(snap->file)) ||
10887
        (persistDisk &&
10888
         !(persistSource = strdup(source)))) {
10889 10890 10891 10892
        virReportOOMError();
        goto cleanup;
    }

10893 10894
    /* create the stub file and set selinux labels; manipulate disk in
     * place, in a way that can be reverted on failure. */
10895 10896 10897 10898 10899 10900 10901
    if (!reuse) {
        fd = qemuOpenFile(driver, source, O_WRONLY | O_TRUNC | O_CREAT,
                          &need_unlink, NULL);
        if (fd < 0)
            goto cleanup;
        VIR_FORCE_CLOSE(fd);
    }
10902

10903 10904 10905 10906 10907 10908 10909 10910
    /* XXX Here, we know we are about to alter disk->backingChain if
     * successful, so we nuke the existing chain so that future
     * commands will recompute it.  Better would be storing the chain
     * ourselves rather than reprobing, but this requires modifying
     * domain_conf and our XML to fully track the chain across
     * libvirtd restarts.  */
    virStorageFileFreeMetadata(disk->backingChain);
    disk->backingChain = NULL;
10911

10912 10913 10914 10915
    if (qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, source,
                                          VIR_DISK_CHAIN_READ_WRITE) < 0) {
        qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, source,
                                          VIR_DISK_CHAIN_NO_ACCESS);
10916 10917 10918 10919
        goto cleanup;
    }

    /* create the actual snapshot */
10920 10921
    if (snap->format)
        formatStr = virStorageFileFormatTypeToString(snap->format);
10922
    ret = qemuMonitorDiskSnapshot(priv->mon, actions, device, source,
10923
                                  formatStr, reuse);
10924 10925 10926 10927 10928
    virDomainAuditDisk(vm, disk->src, source, "snapshot", ret >= 0);
    if (ret < 0)
        goto cleanup;

    /* Update vm in place to match changes.  */
10929
    need_unlink = false;
10930 10931 10932
    VIR_FREE(disk->src);
    disk->src = source;
    source = NULL;
10933
    disk->format = format;
10934 10935 10936 10937
    if (persistDisk) {
        VIR_FREE(persistDisk->src);
        persistDisk->src = persistSource;
        persistSource = NULL;
10938
        persistDisk->format = format;
10939
    }
10940 10941

cleanup:
10942 10943
    if (need_unlink && unlink(source))
        VIR_WARN("unable to unlink just-created %s", source);
10944 10945
    VIR_FREE(device);
    VIR_FREE(source);
10946
    VIR_FREE(persistSource);
10947 10948 10949
    return ret;
}

10950 10951 10952 10953
/* The domain is expected to hold monitor lock.  This is the
 * counterpart to qemuDomainSnapshotCreateSingleDiskActive, called
 * only on a failed transaction. */
static void
10954
qemuDomainSnapshotUndoSingleDiskActive(virQEMUDriverPtr driver,
10955
                                       virDomainObjPtr vm,
10956
                                       virCgroupPtr cgroup,
10957 10958 10959 10960 10961 10962 10963 10964 10965 10966 10967
                                       virDomainDiskDefPtr origdisk,
                                       virDomainDiskDefPtr disk,
                                       virDomainDiskDefPtr persistDisk,
                                       bool need_unlink)
{
    char *source = NULL;
    char *persistSource = NULL;
    struct stat st;

    if (!(source = strdup(origdisk->src)) ||
        (persistDisk &&
10968
         !(persistSource = strdup(source)))) {
10969 10970 10971 10972
        virReportOOMError();
        goto cleanup;
    }

10973 10974
    qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, origdisk->src,
                                      VIR_DISK_CHAIN_NO_ACCESS);
10975
    if (need_unlink && stat(disk->src, &st) == 0 &&
10976
        S_ISREG(st.st_mode) && unlink(disk->src) < 0)
10977 10978 10979 10980 10981 10982
        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;
10983
    disk->format = origdisk->format;
10984 10985 10986 10987
    if (persistDisk) {
        VIR_FREE(persistDisk->src);
        persistDisk->src = persistSource;
        persistSource = NULL;
10988
        persistDisk->format = origdisk->format;
10989 10990 10991 10992 10993 10994 10995
    }

cleanup:
    VIR_FREE(source);
    VIR_FREE(persistSource);
}

10996 10997
/* The domain is expected to be locked and active. */
static int
10998
qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver,
10999
                                   virDomainObjPtr vm,
11000
                                   virDomainSnapshotObjPtr snap,
11001 11002
                                   unsigned int flags,
                                   enum qemuDomainAsyncJob asyncJob)
11003
{
11004 11005
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virJSONValuePtr actions = NULL;
11006 11007
    int ret = -1;
    int i;
11008
    bool persist = false;
11009
    bool reuse = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
11010
    virCgroupPtr cgroup = NULL;
11011

11012
    if (!virDomainObjIsActive(vm)) {
11013 11014
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
11015
        goto cleanup;
11016 11017
    }

11018 11019
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0)) {
11020 11021 11022
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to find cgroup for %s"),
                       vm->def->name);
11023
        goto cleanup;
11024 11025 11026
    }
    /* 'cgroup' is still NULL if cgroups are disabled.  */

11027
    if (qemuCapsGet(priv->caps, QEMU_CAPS_TRANSACTION)) {
11028
        if (!(actions = virJSONValueNewArray())) {
11029 11030 11031
            virReportOOMError();
            goto cleanup;
        }
11032 11033 11034 11035 11036
    } else if (!qemuCapsGet(priv->caps, QEMU_CAPS_DISK_SNAPSHOT)) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("live disk snapshot not supported with this "
                         "QEMU binary"));
        goto cleanup;
11037
    }
11038 11039

    /* No way to roll back if first disk succeeds but later disks
11040
     * fail, unless we have transaction support.
E
Eric Blake 已提交
11041
     * Based on earlier qemuDomainSnapshotPrepare, all
11042 11043
     * disks in this list are now either SNAPSHOT_NO, or
     * SNAPSHOT_EXTERNAL with a valid file name and qcow2 format.  */
11044 11045 11046
    if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        goto cleanup;

11047
    for (i = 0; i < snap->def->ndisks; i++) {
11048 11049
        virDomainDiskDefPtr persistDisk = NULL;

E
Eric Blake 已提交
11050
        if (snap->def->disks[i].snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
11051
            continue;
11052 11053 11054 11055 11056 11057 11058 11059 11060
        if (vm->newDef) {
            int indx = virDomainDiskIndexByName(vm->newDef,
                                                vm->def->disks[i]->dst,
                                                false);
            if (indx >= 0) {
                persistDisk = vm->newDef->disks[indx];
                persist = true;
            }
        }
11061

11062
        ret = qemuDomainSnapshotCreateSingleDiskActive(driver, vm, cgroup,
11063
                                                       &snap->def->disks[i],
11064
                                                       vm->def->disks[i],
11065 11066
                                                       persistDisk, actions,
                                                       reuse);
11067 11068 11069
        if (ret < 0)
            break;
    }
11070 11071 11072
    if (actions) {
        if (ret == 0)
            ret = qemuMonitorTransaction(priv->mon, actions);
E
Eric Blake 已提交
11073
        virJSONValueFree(actions);
11074 11075 11076 11077 11078 11079
        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 已提交
11080 11081
                if (snap->def->disks[i].snapshot ==
                    VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
11082 11083 11084 11085 11086 11087 11088 11089 11090
                    continue;
                if (vm->newDef) {
                    int indx = virDomainDiskIndexByName(vm->newDef,
                                                        vm->def->disks[i]->dst,
                                                        false);
                    if (indx >= 0)
                        persistDisk = vm->newDef->disks[indx];
                }

11091
                qemuDomainSnapshotUndoSingleDiskActive(driver, vm, cgroup,
11092 11093 11094 11095 11096 11097 11098
                                                       snap->def->dom->disks[i],
                                                       vm->def->disks[i],
                                                       persistDisk,
                                                       need_unlink);
            }
        }
    }
11099
    qemuDomainObjExitMonitorWithDriver(driver, vm);
11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112 11113 11114 11115

cleanup:
    virCgroupFree(&cgroup);

    if (ret == 0 || !qemuCapsGet(priv->caps, QEMU_CAPS_TRANSACTION)) {
        if (virDomainSaveStatus(driver->caps, driver->stateDir, vm) < 0 ||
            (persist && virDomainSaveConfig(driver->configDir, vm->newDef) < 0))
            ret = -1;
    }

    return ret;
}


static int
qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
11116
                                       virQEMUDriverPtr driver,
11117 11118 11119 11120 11121 11122 11123 11124 11125 11126
                                       virDomainObjPtr *vmptr,
                                       virDomainSnapshotObjPtr snap,
                                       unsigned int flags)
{
    bool resume = false;
    int ret = -1;
    virDomainObjPtr vm = *vmptr;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *xml = NULL;
    bool memory = snap->def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
11127
    bool memory_unlink = false;
11128 11129 11130
    bool atomic = !!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC);
    bool transaction = qemuCapsGet(priv->caps, QEMU_CAPS_TRANSACTION);
    int thaw = 0; /* 1 if freeze succeeded, -1 if freeze failed */
11131
    bool pmsuspended = false;
11132 11133 11134

    if (qemuDomainObjBeginAsyncJobWithDriver(driver, vm,
                                             QEMU_ASYNC_JOB_SNAPSHOT) < 0)
11135 11136
        goto cleanup;

11137 11138 11139 11140 11141 11142 11143 11144 11145 11146 11147 11148 11149 11150
    /* 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) {
            /* helper reported the error */
            thaw = -1;
            goto endjob;
        } else {
            thaw = 1;
        }
    }

11151 11152 11153 11154 11155
    /* We need to track what state the guest is in, since taking the
     * snapshot may alter that state and we must restore it later.  */
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_PMSUSPENDED) {
        pmsuspended = true;
    } else if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178 11179 11180 11181 11182 11183 11184
        resume = true;

        /* For external checkpoints (those with memory), the guest
         * must pause (either by libvirt up front, or by qemu after
         * _LIVE converges).  For disk-only snapshots with 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
         * qemuDomainSnapshotPrepare, 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 ((memory && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_LIVE)) ||
            (!memory && atomic && !transaction)) {
            if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SNAPSHOT,
                                    QEMU_ASYNC_JOB_SNAPSHOT) < 0)
                goto endjob;

            if (!virDomainObjIsActive(vm)) {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("guest unexpectedly quit"));
                goto endjob;
            }
        }
    }

    /* do the memory snapshot if necessary */
    if (memory) {
11185 11186 11187 11188
        /* check if migration is possible */
        if (!qemuMigrationIsAllowed(driver, vm, vm->def, false))
            goto endjob;

11189 11190 11191 11192 11193 11194 11195 11196 11197
        /* allow the migration job to be cancelled or the domain to be paused */
        qemuDomainObjSetAsyncJobMask(vm, DEFAULT_JOB_MASK |
                                     JOB_MASK(QEMU_JOB_SUSPEND) |
                                     JOB_MASK(QEMU_JOB_MIGRATION_OP));

        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, false)))
            goto endjob;

        if ((ret = qemuDomainSaveMemory(driver, vm, snap->def->file,
11198
                                        xml, QEMU_SAVE_FORMAT_RAW,
11199 11200 11201 11202
                                        resume, 0,
                                        QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
            goto endjob;

11203 11204 11205
        /* the memory image was created, remove it on errors */
        memory_unlink = true;

11206 11207 11208 11209 11210 11211 11212 11213 11214 11215 11216 11217 11218 11219 11220 11221
        /* forbid any further manipulation */
        qemuDomainObjSetAsyncJobMask(vm, DEFAULT_JOB_MASK);
    }

    /* now the domain is now paused if:
     * - if a memory snapshot was requested
     * - an atomic snapshot was requested AND
     *   qemu does not support transactions
     *
     * Next we snapshot the disks.
     */
    if ((ret = qemuDomainSnapshotCreateDiskActive(driver, vm, snap, flags,
                                                  QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
        goto endjob;

    /* the snapshot is complete now */
11222 11223 11224 11225 11226
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
        virDomainEventPtr event;

        event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
11227
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
11228 11229 11230
        virDomainAuditStop(vm, "from-snapshot");
        /* We already filtered the _HALT flag for persistent domains
         * only, so this end job never drops the last reference.  */
11231
        ignore_value(qemuDomainObjEndAsyncJob(driver, vm));
11232
        resume = false;
E
Eric Blake 已提交
11233
        thaw = 0;
11234 11235 11236
        vm = NULL;
        if (event)
            qemuDomainEventQueue(driver, event);
11237 11238 11239 11240 11241 11242 11243 11244 11245 11246 11247 11248
    } else if (memory && pmsuspended) {
        /* qemu 1.3 is unable to save a domain in pm-suspended (S3)
         * state; so we must emit an event stating that it was
         * converted to paused.  */
        virDomainEventPtr event;

        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
                             VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
        event = virDomainEventNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
        if (event)
            qemuDomainEventQueue(driver, event);
11249 11250
    }

11251
    ret = 0;
11252 11253

endjob:
11254 11255 11256
    if (resume && vm && virDomainObjIsActive(vm) &&
        qemuProcessStartCPUs(driver, vm, conn,
                             VIR_DOMAIN_RUNNING_UNPAUSED,
11257
                             QEMU_ASYNC_JOB_SNAPSHOT) < 0) {
11258 11259 11260 11261 11262 11263 11264 11265 11266 11267
        virDomainEventPtr event = NULL;
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
        if (event)
            qemuDomainEventQueue(driver, event);
        if (virGetLastError() == NULL) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("resuming after snapshot failed"));
        }
11268

11269 11270
        ret = -1;
        goto cleanup;
11271
    }
E
Eric Blake 已提交
11272 11273 11274 11275 11276 11277
    if (vm && thaw != 0 &&
        qemuDomainSnapshotFSThaw(driver, vm, thaw > 0) < 0) {
        /* helper reported the error, if it was needed */
        if (thaw > 0)
            ret = -1;
    }
11278
    if (vm && !qemuDomainObjEndAsyncJob(driver, vm)) {
11279
        /* Only possible if a transient vm quit while our locks were down,
11280 11281
         * in which case we don't want to save snapshot metadata.
         */
11282 11283
        *vmptr = NULL;
        ret = -1;
11284 11285
    }

11286 11287
cleanup:
    VIR_FREE(xml);
11288 11289
    if (memory_unlink && ret < 0)
        unlink(snap->def->file);
11290

11291 11292 11293
    return ret;
}

11294

11295 11296 11297 11298
static virDomainSnapshotPtr
qemuDomainSnapshotCreateXML(virDomainPtr domain,
                            const char *xmlDesc,
                            unsigned int flags)
C
Chris Lalancette 已提交
11299
{
11300
    virQEMUDriverPtr driver = domain->conn->privateData;
C
Chris Lalancette 已提交
11301
    virDomainObjPtr vm = NULL;
11302
    char *xml = NULL;
C
Chris Lalancette 已提交
11303 11304 11305
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
11306
    virDomainSnapshotDefPtr def = NULL;
11307
    bool update_current = true;
11308
    unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
11309
    virDomainSnapshotObjPtr other = NULL;
11310 11311
    int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
    int align_match = true;
C
Chris Lalancette 已提交
11312

11313 11314
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
11315
                  VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
11316
                  VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
11317
                  VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
11318
                  VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT |
11319
                  VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
11320 11321
                  VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
                  VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, NULL);
11322 11323 11324

    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) &&
        !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)) {
11325 11326
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("quiesce requires disk-only"));
11327 11328
        return NULL;
    }
11329 11330 11331 11332 11333 11334 11335

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

C
Chris Lalancette 已提交
11337 11338 11339 11340
    qemuDriverLock(driver);
    virUUIDFormat(domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, domain->uuid);
    if (!vm) {
11341 11342
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
C
Chris Lalancette 已提交
11343 11344 11345
        goto cleanup;
    }

11346
    if (qemuProcessAutoDestroyActive(driver, vm)) {
11347 11348
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is marked for auto destroy"));
11349 11350
        goto cleanup;
    }
E
Eric Blake 已提交
11351 11352 11353 11354 11355 11356
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
        goto cleanup;
    }

11357
    if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
11358 11359
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot halt after transient domain snapshot"));
11360 11361
        goto cleanup;
    }
11362 11363 11364
    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) ||
        !virDomainObjIsActive(vm))
        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_OFFLINE;
11365

11366 11367 11368
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, driver->caps,
                                                QEMU_EXPECTED_VIRT_TYPES,
                                                parse_flags)))
C
Chris Lalancette 已提交
11369 11370
        goto cleanup;

11371 11372 11373 11374 11375 11376 11377 11378 11379 11380 11381 11382 11383 11384 11385 11386 11387 11388
    /* reject snapshot names containing slashes or starting with dot as
     * snapshot definitions are saved in files named by the snapshot name */
    if (!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
        if (strchr(def->name, '/')) {
            virReportError(VIR_ERR_XML_DETAIL,
                           _("invalid snapshot name '%s': "
                             "name can't contain '/'"),
                           def->name);
            goto cleanup;
        }

        if (def->name[0] == '.') {
            virReportError(VIR_ERR_XML_DETAIL,
                           _("invalid snapshot name '%s': "
                             "name can't start with '.'"),
                           def->name);
            goto cleanup;
        }
11389 11390
    }

11391 11392 11393 11394 11395 11396 11397 11398 11399 11400 11401 11402 11403 11404 11405 11406 11407 11408 11409
    /* reject the VIR_DOMAIN_SNAPSHOT_CREATE_LIVE flag where not supported */
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_LIVE &&
        (!virDomainObjIsActive(vm) ||
         def->memory != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL ||
         flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("live snapshot creation is supported only "
                         "with external checkpoints"));
        goto cleanup;
    }
    if ((def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL ||
         def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL) &&
        flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("disk-only snapshot creation is not compatible with "
                         "memory snapshot"));
        goto cleanup;
    }

11410 11411 11412 11413
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
        /* Prevent circular chains */
        if (def->parent) {
            if (STREQ(def->name, def->parent)) {
11414 11415 11416
                virReportError(VIR_ERR_INVALID_ARG,
                               _("cannot set snapshot %s as its own parent"),
                               def->name);
11417 11418
                goto cleanup;
            }
11419
            other = virDomainSnapshotFindByName(vm->snapshots, def->parent);
11420
            if (!other) {
11421 11422 11423
                virReportError(VIR_ERR_INVALID_ARG,
                               _("parent %s for snapshot %s not found"),
                               def->parent, def->name);
11424 11425 11426 11427
                goto cleanup;
            }
            while (other->def->parent) {
                if (STREQ(other->def->parent, def->name)) {
11428 11429 11430
                    virReportError(VIR_ERR_INVALID_ARG,
                                   _("parent %s would create cycle to %s"),
                                   other->def->name, def->name);
11431 11432
                    goto cleanup;
                }
11433
                other = virDomainSnapshotFindByName(vm->snapshots,
11434 11435 11436 11437 11438 11439 11440 11441 11442 11443
                                                    other->def->parent);
                if (!other) {
                    VIR_WARN("snapshots are inconsistent for %s",
                             vm->def->name);
                    break;
                }
            }
        }

        /* Check that any replacement is compatible */
11444 11445 11446 11447 11448 11449 11450 11451 11452
        if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) &&
            def->state != VIR_DOMAIN_DISK_SNAPSHOT) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("disk-only flag for snapshot %s requires "
                             "disk-snapshot state"),
                           def->name);
            goto cleanup;

        }
11453

11454 11455
        if (def->dom &&
            memcmp(def->dom->uuid, domain->uuid, VIR_UUID_BUFLEN)) {
11456 11457 11458
            virReportError(VIR_ERR_INVALID_ARG,
                           _("definition for snapshot %s must use uuid %s"),
                           def->name, uuidstr);
11459 11460
            goto cleanup;
        }
11461

11462
        other = virDomainSnapshotFindByName(vm->snapshots, def->name);
11463 11464 11465 11466 11467
        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)) {
11468 11469 11470 11471
                virReportError(VIR_ERR_INVALID_ARG,
                               _("cannot change between online and offline "
                                 "snapshot state in snapshot %s"),
                               def->name);
11472 11473
                goto cleanup;
            }
11474

11475 11476
            if ((other->def->state == VIR_DOMAIN_DISK_SNAPSHOT) !=
                (def->state == VIR_DOMAIN_DISK_SNAPSHOT)) {
11477 11478 11479 11480
                virReportError(VIR_ERR_INVALID_ARG,
                               _("cannot change between disk snapshot and "
                                 "system checkpoint in snapshot %s"),
                               def->name);
11481 11482
                goto cleanup;
            }
11483

11484 11485 11486 11487 11488 11489 11490 11491 11492 11493 11494
            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;
                }
            }
11495

11496 11497
            if (def->dom) {
                if (def->state == VIR_DOMAIN_DISK_SNAPSHOT ||
11498
                    virDomainSnapshotDefIsExternal(def)) {
11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509 11510 11511 11512 11513
                    align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
                    align_match = false;
                }

                if (virDomainSnapshotAlignDisks(def, align_location,
                                                align_match) < 0) {
                    /* revert stealing of the snapshot domain definition */
                    if (def->dom && !other->def->dom) {
                        other->def->dom = def->dom;
                        def->dom = NULL;
                    }
                    goto cleanup;
                }
            }

11514 11515 11516 11517
            if (other == vm->current_snapshot) {
                update_current = true;
                vm->current_snapshot = NULL;
            }
11518

11519 11520
            /* Drop and rebuild the parent relationship, but keep all
             * child relations by reusing snap.  */
11521
            virDomainSnapshotDropParent(other);
11522
            virDomainSnapshotDefFree(other->def);
11523 11524
            other->def = def;
            def = NULL;
11525
            snap = other;
11526 11527 11528 11529 11530 11531 11532 11533 11534 11535
        } else {
            if (def->dom) {
                if (def->state == VIR_DOMAIN_DISK_SNAPSHOT ||
                    def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
                    align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
                    align_match = false;
                }
                if (virDomainSnapshotAlignDisks(def, align_location,
                                                align_match) < 0)
                    goto cleanup;
11536
            }
11537
        }
11538 11539 11540
    } else {
        /* Easiest way to clone inactive portion of vm->def is via
         * conversion in and back out of xml.  */
11541
        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)) ||
11542 11543 11544 11545 11546
            !(def->dom = virDomainDefParseString(driver->caps, xml,
                                                 QEMU_EXPECTED_VIRT_TYPES,
                                                 VIR_DOMAIN_XML_INACTIVE)))
            goto cleanup;

11547
        if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
11548 11549
            align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
            align_match = false;
11550 11551 11552 11553
            if (virDomainObjIsActive(vm))
                def->state = VIR_DOMAIN_DISK_SNAPSHOT;
            else
                def->state = VIR_DOMAIN_SHUTOFF;
11554
            def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
11555 11556 11557 11558
        } else if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
            def->state = virDomainObjGetState(vm, NULL);
            align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
            align_match = false;
11559 11560
        } else {
            def->state = virDomainObjGetState(vm, NULL);
11561 11562 11563
            def->memory = (def->state == VIR_DOMAIN_SHUTOFF ?
                           VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
                           VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL);
11564
        }
E
Eric Blake 已提交
11565 11566 11567 11568
        if (virDomainSnapshotAlignDisks(def, align_location,
                                        align_match) < 0 ||
            qemuDomainSnapshotPrepare(vm, def, &flags) < 0)
            goto cleanup;
11569 11570
    }

11571 11572 11573 11574 11575 11576
    if (!snap) {
        if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
            goto cleanup;

        def = NULL;
    }
C
Chris Lalancette 已提交
11577

11578 11579
    if (update_current)
        snap->def->current = true;
11580
    if (vm->current_snapshot) {
11581 11582 11583 11584 11585 11586
        if (!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE)) {
            snap->def->parent = strdup(vm->current_snapshot->def->name);
            if (snap->def->parent == NULL) {
                virReportOOMError();
                goto cleanup;
            }
11587
        }
11588
        if (update_current) {
11589 11590 11591 11592 11593 11594
            vm->current_snapshot->def->current = false;
            if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
                                                driver->snapshotDir) < 0)
                goto cleanup;
            vm->current_snapshot = NULL;
        }
11595
    }
11596

C
Chris Lalancette 已提交
11597
    /* actually do the snapshot */
11598 11599
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE) {
        /* XXX Should we validate that the redefined snapshot even
11600 11601
         * makes sense, such as checking that qemu-img recognizes the
         * snapshot name in at least one of the domain's disks?  */
11602 11603 11604 11605 11606 11607 11608 11609 11610 11611 11612 11613 11614
    } else if (virDomainObjIsActive(vm)) {
        if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY ||
            snap->def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
            /* external checkpoint or disk snapshot */
            if (qemuDomainSnapshotCreateActiveExternal(domain->conn, driver,
                                                       &vm, snap, flags) < 0)
                goto cleanup;
        } else {
            /* internal checkpoint */
            if (qemuDomainSnapshotCreateActiveInternal(domain->conn, driver,
                                                       &vm, snap, flags) < 0)
                goto cleanup;
        }
E
Eric Blake 已提交
11615
    } else {
11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627 11628
        /* inactive; qemuDomainSnapshotPrepare guaranteed that we
         * aren't mixing internal and external, and altered flags to
         * contain DISK_ONLY if there is an external disk.  */
        if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
            bool reuse = !!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT);

            if (qemuDomainSnapshotCreateInactiveExternal(driver, vm, snap,
                                                         reuse) < 0)
                goto cleanup;
        } else {
            if (qemuDomainSnapshotCreateInactiveInternal(driver, vm, snap) < 0)
                goto cleanup;
        }
C
Chris Lalancette 已提交
11629 11630
    }

11631
    /* If we fail after this point, there's not a whole lot we can
C
Chris Lalancette 已提交
11632 11633 11634 11635 11636 11637
     * 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:
11638
    if (vm) {
11639
        if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
11640
            if (qemuDomainSnapshotWriteMetadata(vm, snap,
11641
                                                driver->snapshotDir) < 0) {
11642 11643 11644 11645 11646 11647 11648 11649
                /* if writing of metadata fails, error out rather than trying
                 * to silently carry on  without completing the snapshot */
                virDomainSnapshotFree(snapshot);
                snapshot = NULL;
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unable to save metadata for snapshot %s"),
                               snap->def->name);
                virDomainSnapshotObjListRemove(vm->snapshots, snap);
11650 11651 11652
            } else {
                if (update_current)
                    vm->current_snapshot = snap;
11653
                other = virDomainSnapshotFindByName(vm->snapshots,
11654 11655 11656 11657 11658
                                                    snap->def->parent);
                snap->parent = other;
                other->nchildren++;
                snap->sibling = other->first_child;
                other->first_child = snap;
11659
            }
11660
        } else if (snap) {
11661
            virDomainSnapshotObjListRemove(vm->snapshots, snap);
11662
        }
11663
        virObjectUnlock(vm);
11664 11665
    }
    virDomainSnapshotDefFree(def);
11666
    VIR_FREE(xml);
C
Chris Lalancette 已提交
11667 11668 11669 11670 11671 11672
    qemuDriverUnlock(driver);
    return snapshot;
}

static int qemuDomainSnapshotListNames(virDomainPtr domain, char **names,
                                       int nameslen,
11673
                                       unsigned int flags)
C
Chris Lalancette 已提交
11674 11675 11676 11677
{
    virDomainObjPtr vm = NULL;
    int n = -1;

11678
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
11679
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11680

11681
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11682 11683
        goto cleanup;

11684
    n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen,
11685
                                         flags);
C
Chris Lalancette 已提交
11686 11687 11688

cleanup:
    if (vm)
11689
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
11690 11691 11692 11693
    return n;
}

static int qemuDomainSnapshotNum(virDomainPtr domain,
11694
                                 unsigned int flags)
C
Chris Lalancette 已提交
11695 11696 11697 11698
{
    virDomainObjPtr vm = NULL;
    int n = -1;

11699
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
11700
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11701

11702
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11703 11704
        goto cleanup;

11705
    n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags);
C
Chris Lalancette 已提交
11706 11707 11708

cleanup:
    if (vm)
11709
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
11710 11711 11712
    return n;
}

11713 11714 11715 11716 11717 11718 11719 11720 11721 11722
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);

11723
    if (!(vm = qemuDomObjFromDomain(domain)))
11724 11725
        goto cleanup;

11726
    n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags);
11727 11728 11729

cleanup:
    if (vm)
11730
        virObjectUnlock(vm);
11731 11732 11733
    return n;
}

11734 11735 11736 11737 11738 11739 11740 11741 11742 11743 11744
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 |
11745
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11746

11747
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11748 11749
        goto cleanup;

11750
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11751 11752
        goto cleanup;

11753
    n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen,
11754
                                         flags);
11755 11756 11757

cleanup:
    if (vm)
11758
        virObjectUnlock(vm);
11759 11760 11761 11762 11763 11764 11765 11766 11767 11768 11769 11770
    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 |
11771
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
11772

11773
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11774 11775
        goto cleanup;

11776
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11777 11778
        goto cleanup;

11779
    n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags);
11780 11781 11782

cleanup:
    if (vm)
11783
        virObjectUnlock(vm);
11784 11785 11786
    return n;
}

11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 11798
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);

11799
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11800 11801
        goto cleanup;

11802
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11803 11804
        goto cleanup;

11805
    n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps,
11806 11807 11808 11809
                               flags);

cleanup:
    if (vm)
11810
        virObjectUnlock(vm);
11811 11812 11813
    return n;
}

C
Chris Lalancette 已提交
11814 11815
static virDomainSnapshotPtr qemuDomainSnapshotLookupByName(virDomainPtr domain,
                                                           const char *name,
11816
                                                           unsigned int flags)
C
Chris Lalancette 已提交
11817 11818 11819 11820 11821
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

11822 11823
    virCheckFlags(0, NULL);

11824
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11825 11826
        goto cleanup;

11827
    if (!(snap = qemuSnapObjFromName(vm, name)))
C
Chris Lalancette 已提交
11828 11829 11830 11831 11832 11833
        goto cleanup;

    snapshot = virGetDomainSnapshot(domain, snap->def->name);

cleanup:
    if (vm)
11834
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
11835 11836 11837 11838
    return snapshot;
}

static int qemuDomainHasCurrentSnapshot(virDomainPtr domain,
11839
                                        unsigned int flags)
C
Chris Lalancette 已提交
11840 11841 11842 11843
{
    virDomainObjPtr vm;
    int ret = -1;

11844 11845
    virCheckFlags(0, -1);

11846
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11847 11848 11849 11850 11851 11852
        goto cleanup;

    ret = (vm->current_snapshot != NULL);

cleanup:
    if (vm)
11853
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
11854 11855 11856
    return ret;
}

11857 11858 11859 11860 11861 11862 11863 11864 11865 11866
static virDomainSnapshotPtr
qemuDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr parent = NULL;

    virCheckFlags(0, NULL);

11867
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11868 11869
        goto cleanup;

11870
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11871 11872 11873
        goto cleanup;

    if (!snap->def->parent) {
11874 11875 11876
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snap->def->name);
11877 11878 11879 11880 11881 11882 11883
        goto cleanup;
    }

    parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);

cleanup:
    if (vm)
11884
        virObjectUnlock(vm);
11885 11886 11887
    return parent;
}

C
Chris Lalancette 已提交
11888
static virDomainSnapshotPtr qemuDomainSnapshotCurrent(virDomainPtr domain,
11889
                                                      unsigned int flags)
C
Chris Lalancette 已提交
11890 11891 11892 11893
{
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

11894 11895
    virCheckFlags(0, NULL);

11896
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
11897 11898 11899
        goto cleanup;

    if (!vm->current_snapshot) {
11900 11901
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
                       _("the domain does not have a current snapshot"));
C
Chris Lalancette 已提交
11902 11903 11904 11905 11906 11907 11908
        goto cleanup;
    }

    snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);

cleanup:
    if (vm)
11909
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
11910 11911 11912
    return snapshot;
}

11913 11914
static char *qemuDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                                          unsigned int flags)
C
Chris Lalancette 已提交
11915 11916 11917 11918 11919 11920
{
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

11921
    virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
11922

11923
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
C
Chris Lalancette 已提交
11924 11925
        goto cleanup;

11926
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
11927
        goto cleanup;
11928 11929

    virUUIDFormat(snapshot->domain->uuid, uuidstr);
C
Chris Lalancette 已提交
11930

11931
    xml = virDomainSnapshotDefFormat(uuidstr, snap->def, flags, 0);
C
Chris Lalancette 已提交
11932 11933 11934

cleanup:
    if (vm)
11935
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
11936 11937 11938
    return xml;
}

11939 11940 11941 11942 11943 11944 11945 11946 11947 11948
static int
qemuDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

11949
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11950 11951
        goto cleanup;

11952
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11953 11954 11955 11956 11957 11958 11959
        goto cleanup;

    ret = (vm->current_snapshot &&
           STREQ(snapshot->name, vm->current_snapshot->def->name));

cleanup:
    if (vm)
11960
        virObjectUnlock(vm);
11961 11962 11963 11964 11965 11966 11967 11968 11969 11970 11971 11972 11973 11974
    return ret;
}


static int
qemuDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
                              unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

11975
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
11976 11977
        goto cleanup;

11978
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
11979 11980 11981 11982 11983 11984 11985 11986 11987
        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)
11988
        virObjectUnlock(vm);
11989 11990 11991
    return ret;
}

11992 11993
/* The domain is expected to be locked and inactive. */
static int
11994
qemuDomainSnapshotRevertInactive(virQEMUDriverPtr driver,
E
Eric Blake 已提交
11995
                                 virDomainObjPtr vm,
11996 11997 11998
                                 virDomainSnapshotObjPtr snap)
{
    /* Try all disks, but report failure if we skipped any.  */
E
Eric Blake 已提交
11999
    int ret = qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-a", true);
12000 12001 12002
    return ret > 0 ? -1 : ret;
}

C
Chris Lalancette 已提交
12003
static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
12004
                                      unsigned int flags)
C
Chris Lalancette 已提交
12005
{
12006
    virQEMUDriverPtr driver = snapshot->domain->conn->privateData;
C
Chris Lalancette 已提交
12007 12008 12009 12010 12011
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    virDomainEventPtr event = NULL;
12012
    virDomainEventPtr event2 = NULL;
12013
    int detail;
C
Chris Lalancette 已提交
12014 12015
    qemuDomainObjPrivatePtr priv;
    int rc;
12016
    virDomainDefPtr config = NULL;
C
Chris Lalancette 已提交
12017

12018
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
12019 12020
                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
                  VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
12021

12022 12023 12024 12025 12026 12027 12028 12029 12030 12031
    /* 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
12032 12033
     * Also, several transitions occur even if we fail partway through,
     * and use of FORCE can cause multiple transitions.
12034 12035
     */

C
Chris Lalancette 已提交
12036 12037 12038 12039
    qemuDriverLock(driver);
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, snapshot->domain->uuid);
    if (!vm) {
12040 12041
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
C
Chris Lalancette 已提交
12042 12043
        goto cleanup;
    }
E
Eric Blake 已提交
12044 12045 12046 12047 12048
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
        goto cleanup;
    }
C
Chris Lalancette 已提交
12049

12050
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
12051 12052
        goto cleanup;

12053 12054 12055 12056 12057
    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) {
12058 12059 12060
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("transient domain needs to request run or pause "
                         "to revert to inactive snapshot"));
12061 12062
        goto cleanup;
    }
12063
    if (snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT) {
12064 12065 12066
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("revert to external disk snapshot not supported "
                         "yet"));
12067 12068
        goto cleanup;
    }
12069 12070
    if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
        if (!snap->def->dom) {
12071 12072 12073
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
                           _("snapshot '%s' lacks domain '%s' rollback info"),
                           snap->def->name, vm->def->name);
12074 12075 12076 12077 12078 12079 12080
            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))) {
12081 12082
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                           _("must respawn qemu to start inactive snapshot"));
12083 12084 12085 12086
            goto cleanup;
        }
    }

12087

12088 12089 12090 12091 12092 12093 12094 12095 12096 12097
    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?  */
    }

12098
    /* Prepare to copy the snapshot inactive xml as the config of this
12099
     * domain.
12100 12101 12102
     *
     * XXX Should domain snapshots track live xml rather
     * than inactive xml?  */
12103
    snap->def->current = true;
12104
    if (snap->def->dom) {
12105
        config = virDomainDefCopy(driver->caps, snap->def->dom, true);
12106 12107 12108
        if (!config)
            goto cleanup;
    }
C
Chris Lalancette 已提交
12109

12110
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
C
Chris Lalancette 已提交
12111 12112 12113 12114
        goto cleanup;

    if (snap->def->state == VIR_DOMAIN_RUNNING
        || snap->def->state == VIR_DOMAIN_PAUSED) {
12115 12116 12117 12118 12119 12120 12121 12122 12123
        /* 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 已提交
12124
        if (virDomainObjIsActive(vm)) {
12125
            /* Transitions 5, 6, 8, 9 */
12126 12127
            /* Check for ABI compatibility.  */
            if (config && !virDomainDefCheckABIStability(vm->def, config)) {
12128 12129 12130 12131 12132
                virErrorPtr err = virGetLastError();

                if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
                    /* Re-spawn error using correct category. */
                    if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
12133 12134
                        virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                                       err->str2);
12135 12136 12137
                    goto endjob;
                }
                virResetError(err);
12138 12139
                qemuProcessStop(driver, vm,
                                VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
12140 12141 12142 12143 12144 12145 12146 12147
                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;
12148 12149
            }

C
Chris Lalancette 已提交
12150
            priv = vm->privateData;
12151 12152 12153 12154 12155 12156 12157 12158 12159 12160 12161 12162 12163 12164 12165
            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)) {
12166 12167
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("guest unexpectedly quit"));
12168 12169 12170
                    goto endjob;
                }
            }
12171
            qemuDomainObjEnterMonitorWithDriver(driver, vm);
C
Chris Lalancette 已提交
12172 12173
            rc = qemuMonitorLoadSnapshot(priv->mon, snap->def->name);
            qemuDomainObjExitMonitorWithDriver(driver, vm);
12174 12175 12176
            if (rc < 0) {
                /* XXX resume domain if it was running before the
                 * failed loadvm attempt? */
12177
                goto endjob;
12178
            }
12179 12180
            if (config)
                virDomainObjAssignDef(vm, config, false);
E
Eric Blake 已提交
12181
        } else {
12182
            /* Transitions 2, 3 */
12183
        load:
12184
            was_stopped = true;
12185 12186 12187
            if (config)
                virDomainObjAssignDef(vm, config, false);

12188 12189 12190 12191
            rc = qemuProcessStart(snapshot->domain->conn,
                                  driver, vm, NULL, -1, NULL, snap,
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  VIR_QEMU_PROCESS_START_PAUSED);
12192
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
12193 12194 12195 12196
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
C
Chris Lalancette 已提交
12197
            if (rc < 0)
12198
                goto endjob;
C
Chris Lalancette 已提交
12199 12200
        }

12201
        /* Touch up domain state.  */
12202 12203 12204
        if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
            (snap->def->state == VIR_DOMAIN_PAUSED ||
             (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
12205 12206 12207 12208 12209 12210 12211 12212 12213 12214 12215 12216 12217
            /* 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)) {
12218 12219
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("guest unexpectedly quit"));
12220 12221 12222 12223 12224
                goto endjob;
            }
            rc = qemuProcessStartCPUs(driver, vm, snapshot->domain->conn,
                                      VIR_DOMAIN_RUNNING_FROM_SNAPSHOT,
                                      QEMU_ASYNC_JOB_NONE);
H
Hu Tao 已提交
12225
            if (rc < 0)
12226
                goto endjob;
12227 12228 12229 12230 12231 12232 12233 12234 12235 12236 12237 12238 12239 12240 12241
            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 已提交
12242
        }
E
Eric Blake 已提交
12243
    } else {
12244
        /* Transitions 1, 4, 7 */
12245 12246 12247
        /* 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 已提交
12248 12249 12250
         */

        if (virDomainObjIsActive(vm)) {
12251
            /* Transitions 4, 7 */
12252
            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
12253
            virDomainAuditStop(vm, "from-snapshot");
12254
            detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
C
Chris Lalancette 已提交
12255 12256
            event = virDomainEventNewFromObj(vm,
                                             VIR_DOMAIN_EVENT_STOPPED,
12257
                                             detail);
12258 12259
        }

E
Eric Blake 已提交
12260
        if (qemuDomainSnapshotRevertInactive(driver, vm, snap) < 0) {
12261
            if (!vm->persistent) {
12262
                if (qemuDomainObjEndJob(driver, vm) > 0)
12263
                    qemuDomainRemoveInactive(driver, vm);
12264
                vm = NULL;
12265
                goto cleanup;
12266
            }
12267
            goto endjob;
C
Chris Lalancette 已提交
12268
        }
12269 12270
        if (config)
            virDomainObjAssignDef(vm, config, false);
12271

12272 12273 12274 12275
        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;
12276 12277 12278
            unsigned int start_flags = 0;

            start_flags |= paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
12279 12280 12281

            if (event)
                qemuDomainEventQueue(driver, event);
12282 12283 12284 12285
            rc = qemuProcessStart(snapshot->domain->conn,
                                  driver, vm, NULL, -1, NULL, NULL,
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  start_flags);
12286 12287 12288 12289
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
            if (rc < 0) {
                if (!vm->persistent) {
                    if (qemuDomainObjEndJob(driver, vm) > 0)
12290
                        qemuDomainRemoveInactive(driver, vm);
12291 12292 12293 12294 12295 12296 12297 12298 12299 12300 12301 12302 12303 12304 12305 12306
                    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 已提交
12307 12308 12309 12310
    }

    ret = 0;

12311
endjob:
12312
    if (vm && qemuDomainObjEndJob(driver, vm) == 0)
C
Chris Lalancette 已提交
12313 12314
        vm = NULL;

12315
cleanup:
12316 12317 12318 12319 12320 12321 12322 12323 12324
    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;
    }
12325
    if (event) {
C
Chris Lalancette 已提交
12326
        qemuDomainEventQueue(driver, event);
12327 12328 12329
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
C
Chris Lalancette 已提交
12330
    if (vm)
12331
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
12332 12333 12334 12335 12336
    qemuDriverUnlock(driver);

    return ret;
}

12337 12338 12339 12340

typedef struct _virQEMUSnapReparent virQEMUSnapReparent;
typedef virQEMUSnapReparent *virQEMUSnapReparentPtr;
struct _virQEMUSnapReparent {
12341
    virQEMUDriverPtr driver;
12342
    virDomainSnapshotObjPtr parent;
12343 12344
    virDomainObjPtr vm;
    int err;
12345
    virDomainSnapshotObjPtr last;
12346 12347 12348 12349
};

static void
qemuDomainSnapshotReparentChildren(void *payload,
12350
                                   const void *name ATTRIBUTE_UNUSED,
12351 12352 12353
                                   void *data)
{
    virDomainSnapshotObjPtr snap = payload;
12354
    virQEMUSnapReparentPtr rep = data;
12355 12356 12357 12358 12359

    if (rep->err < 0) {
        return;
    }

12360
    VIR_FREE(snap->def->parent);
12361
    snap->parent = rep->parent;
12362

12363
    if (rep->parent->def) {
12364
        snap->def->parent = strdup(rep->parent->def->name);
12365

12366 12367 12368 12369
        if (snap->def->parent == NULL) {
            virReportOOMError();
            rep->err = -1;
            return;
12370 12371
        }
    }
12372

12373 12374 12375
    if (!snap->sibling)
        rep->last = snap;

12376 12377
    rep->err = qemuDomainSnapshotWriteMetadata(rep->vm, snap,
                                               rep->driver->snapshotDir);
12378 12379
}

C
Chris Lalancette 已提交
12380 12381 12382
static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                                    unsigned int flags)
{
12383
    virQEMUDriverPtr driver = snapshot->domain->conn->privateData;
C
Chris Lalancette 已提交
12384 12385 12386 12387
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
12388 12389
    virQEMUSnapRemove rem;
    virQEMUSnapReparent rep;
12390
    bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);
12391
    int external = 0;
C
Chris Lalancette 已提交
12392

12393
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
12394 12395
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY |
                  VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
12396

C
Chris Lalancette 已提交
12397 12398 12399 12400
    qemuDriverLock(driver);
    virUUIDFormat(snapshot->domain->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, snapshot->domain->uuid);
    if (!vm) {
12401 12402
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
C
Chris Lalancette 已提交
12403 12404 12405
        goto cleanup;
    }

12406
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
12407 12408
        goto cleanup;

12409
    if (!metadata_only) {
12410
        if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) &&
12411
            virDomainSnapshotIsExternal(snap))
12412 12413
            external++;
        if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
E
Eric Blake 已提交
12414
            virDomainSnapshotForEachDescendant(snap,
12415 12416 12417
                                               qemuDomainSnapshotCountExternal,
                                               &external);
        if (external) {
12418 12419 12420
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("deletion of %d external disk snapshots not "
                             "supported yet"), external);
12421 12422 12423 12424
            goto cleanup;
        }
    }

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

12428 12429
    if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                 VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
C
Chris Lalancette 已提交
12430 12431
        rem.driver = driver;
        rem.vm = vm;
12432
        rem.metadata_only = metadata_only;
C
Chris Lalancette 已提交
12433
        rem.err = 0;
12434
        rem.current = false;
E
Eric Blake 已提交
12435
        virDomainSnapshotForEachDescendant(snap,
E
Eric Blake 已提交
12436
                                           qemuDomainSnapshotDiscardAll,
12437
                                           &rem);
C
Chris Lalancette 已提交
12438
        if (rem.err < 0)
12439
            goto endjob;
12440 12441 12442 12443 12444
        if (rem.current) {
            if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
                snap->def->current = true;
                if (qemuDomainSnapshotWriteMetadata(vm, snap,
                                                    driver->snapshotDir) < 0) {
12445 12446 12447
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("failed to set snapshot '%s' as current"),
                                   snap->def->name);
12448 12449 12450 12451
                    snap->def->current = false;
                    goto endjob;
                }
            }
12452
            vm->current_snapshot = snap;
12453
        }
12454
    } else if (snap->nchildren) {
12455
        rep.driver = driver;
12456
        rep.parent = snap->parent;
12457 12458
        rep.vm = vm;
        rep.err = 0;
12459
        rep.last = NULL;
E
Eric Blake 已提交
12460
        virDomainSnapshotForEachChild(snap,
12461 12462
                                      qemuDomainSnapshotReparentChildren,
                                      &rep);
12463 12464
        if (rep.err < 0)
            goto endjob;
12465
        /* Can't modify siblings during ForEachChild, so do it now.  */
12466 12467 12468
        snap->parent->nchildren += snap->nchildren;
        rep.last->sibling = snap->parent->first_child;
        snap->parent->first_child = snap->first_child;
C
Chris Lalancette 已提交
12469 12470
    }

12471 12472 12473
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
        snap->nchildren = 0;
        snap->first_child = NULL;
12474
        ret = 0;
12475
    } else {
12476
        virDomainSnapshotDropParent(snap);
12477
        ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only);
12478
    }
C
Chris Lalancette 已提交
12479

12480
endjob:
12481
    if (qemuDomainObjEndJob(driver, vm) == 0)
12482 12483
        vm = NULL;

C
Chris Lalancette 已提交
12484 12485
cleanup:
    if (vm)
12486
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
12487 12488 12489
    qemuDriverUnlock(driver);
    return ret;
}
12490

12491 12492 12493
static int qemuDomainMonitorCommand(virDomainPtr domain, const char *cmd,
                                    char **result, unsigned int flags)
{
12494
    virQEMUDriverPtr driver = domain->conn->privateData;
12495 12496 12497
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
12498
    bool hmp;
12499

12500
    virCheckFlags(VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP, -1);
12501

12502
    if (!(vm = qemuDomObjFromDomain(domain)))
12503 12504 12505
        goto cleanup;

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

12511
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
12512 12513 12514
        goto cleanup;

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

12520 12521
    priv = vm->privateData;

12522
    qemuDomainObjTaint(driver, vm, VIR_DOMAIN_TAINT_CUSTOM_MONITOR, -1);
12523

12524 12525
    hmp = !!(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP);

12526
    qemuDomainObjEnterMonitor(driver, vm);
12527
    ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result, hmp);
12528
    qemuDomainObjExitMonitor(driver, vm);
12529 12530

endjob:
12531
    if (qemuDomainObjEndJob(driver, vm) == 0) {
12532 12533 12534 12535 12536
        vm = NULL;
    }

cleanup:
    if (vm)
12537
        virObjectUnlock(vm);
12538 12539 12540
    return ret;
}

12541

12542
static virDomainPtr qemuDomainAttach(virConnectPtr conn,
12543
                                     unsigned int pid_value,
12544 12545
                                     unsigned int flags)
{
12546
    virQEMUDriverPtr driver = conn->privateData;
12547 12548 12549 12550 12551
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainPtr dom = NULL;
    virDomainChrSourceDefPtr monConfig = NULL;
    bool monJSON = false;
12552
    pid_t pid = pid_value;
12553
    char *pidfile = NULL;
12554
    qemuCapsPtr caps = NULL;
12555 12556 12557 12558 12559 12560 12561 12562 12563 12564

    virCheckFlags(0, NULL);

    qemuDriverLock(driver);

    if (!(def = qemuParseCommandLinePid(driver->caps, pid,
                                        &pidfile, &monConfig, &monJSON)))
        goto cleanup;

    if (!monConfig) {
12565 12566
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("No monitor connection for pid %u"), pid_value);
12567 12568 12569
        goto cleanup;
    }
    if (monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
12570 12571 12572 12573 12574
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Cannot connect to monitor connection of type '%s' "
                         "for pid %u"),
                       virDomainChrTypeToString(monConfig->type),
                       pid_value);
12575 12576 12577 12578
        goto cleanup;
    }

    if (!(def->name) &&
12579
        virAsprintf(&def->name, "attach-pid-%u", pid_value) < 0) {
12580 12581 12582 12583
        virReportOOMError();
        goto cleanup;
    }

12584 12585 12586
    if (!(caps = qemuCapsCacheLookup(driver->capsCache, def->emulator)))
        goto cleanup;

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

12590
    if (qemuCanonicalizeMachine(def, caps) < 0)
12591 12592
        goto cleanup;

12593
    if (qemuDomainAssignAddresses(def, caps, NULL) < 0)
12594 12595 12596 12597 12598 12599 12600 12601 12602
        goto cleanup;

    if (!(vm = virDomainAssignDef(driver->caps,
                                  &driver->domains,
                                  def, false)))
        goto cleanup;

    def = NULL;

12603
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
12604 12605 12606 12607 12608 12609 12610 12611 12612 12613 12614 12615 12616 12617
        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:
12618
    if (qemuDomainObjEndJob(driver, vm) == 0) {
12619 12620 12621 12622 12623 12624
        vm = NULL;
        goto cleanup;
    }

cleanup:
    virDomainDefFree(def);
12625
    virObjectUnref(caps);
12626 12627
    virDomainChrSourceDefFree(monConfig);
    if (vm)
12628
        virObjectUnlock(vm);
12629 12630 12631 12632 12633 12634
    qemuDriverUnlock(driver);
    VIR_FREE(pidfile);
    return dom;
}


12635 12636
static int
qemuDomainOpenConsole(virDomainPtr dom,
12637
                      const char *dev_name,
12638 12639 12640 12641 12642 12643 12644
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    int i;
    virDomainChrDefPtr chr = NULL;
12645
    qemuDomainObjPrivatePtr priv;
12646

12647 12648
    virCheckFlags(VIR_DOMAIN_CONSOLE_SAFE |
                  VIR_DOMAIN_CONSOLE_FORCE, -1);
12649

12650
    if (!(vm = qemuDomObjFromDomain(dom)))
12651 12652 12653
        goto cleanup;

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

12659 12660
    priv = vm->privateData;

12661
    if (dev_name) {
12662 12663 12664 12665 12666
        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];
        }
12667
        for (i = 0 ; !chr && i < vm->def->nserials ; i++) {
12668
            if (STREQ(dev_name, vm->def->serials[i]->info.alias))
12669 12670 12671
                chr = vm->def->serials[i];
        }
        for (i = 0 ; !chr && i < vm->def->nparallels ; i++) {
12672
            if (STREQ(dev_name, vm->def->parallels[i]->info.alias))
12673 12674 12675
                chr = vm->def->parallels[i];
        }
    } else {
12676 12677
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
12678 12679 12680 12681 12682
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
12683 12684 12685
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find character device %s"),
                       NULLSTR(dev_name));
12686 12687 12688
        goto cleanup;
    }

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

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

    if (ret == 1) {
12703 12704
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Active console session exists for this domain"));
12705 12706
        ret = -1;
    }
12707 12708 12709

cleanup:
    if (vm)
12710
        virObjectUnlock(vm);
12711 12712 12713
    return ret;
}

12714 12715 12716 12717 12718 12719 12720 12721 12722 12723 12724 12725 12726 12727 12728 12729 12730 12731 12732 12733 12734 12735 12736 12737 12738 12739 12740 12741 12742 12743 12744 12745 12746 12747 12748 12749 12750 12751 12752 12753 12754 12755 12756 12757 12758 12759 12760 12761 12762 12763 12764 12765 12766 12767 12768 12769 12770 12771 12772 12773 12774 12775 12776 12777 12778 12779 12780 12781
static int
qemuDomainOpenChannel(virDomainPtr dom,
                      const char *name,
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    int i;
    virDomainChrDefPtr chr = NULL;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(VIR_DOMAIN_CHANNEL_FORCE, -1);

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

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

    priv = vm->privateData;

    if (name) {
        for (i = 0 ; !chr && i < vm->def->nchannels ; i++) {
            if (STREQ(name, vm->def->channels[i]->info.alias))
                chr = vm->def->channels[i];

            if (vm->def->channels[i]->targetType == \
                VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_VIRTIO &&
                STREQ(name, vm->def->channels[i]->target.name))
                chr = vm->def->channels[i];
        }
    } else {
        if (vm->def->nchannels)
            chr = vm->def->channels[0];
    }

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

    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_UNIX) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("channel %s is not using a UNIX socket"),
                       NULLSTR(name));
        goto cleanup;
    }

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

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

cleanup:
    if (vm)
12782
        virObjectUnlock(vm);
12783 12784 12785
    return ret;
}

E
Eric Blake 已提交
12786
static char *
E
Eric Blake 已提交
12787
qemuDiskPathToAlias(virDomainObjPtr vm, const char *path, int *idx)
E
Eric Blake 已提交
12788
{
12789 12790
    int i;
    char *ret = NULL;
12791
    virDomainDiskDefPtr disk;
12792

12793 12794 12795
    i = virDomainDiskIndexByName(vm->def, path, true);
    if (i < 0)
        goto cleanup;
12796

12797
    disk = vm->def->disks[i];
E
Eric Blake 已提交
12798 12799
    if (idx)
        *idx = i;
12800

12801 12802 12803 12804 12805 12806 12807 12808
    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;
12809 12810 12811
        }
    }

12812
cleanup:
12813
    if (!ret) {
12814 12815
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("No device found for specified path"));
12816 12817 12818 12819
    }
    return ret;
}

12820 12821 12822 12823
/* Called while holding the VM job lock, to implement a block job
 * abort with pivot; this updates the VM definition as appropriate, on
 * either success or failure.  */
static int
E
Eric Blake 已提交
12824
qemuDomainBlockPivot(virConnectPtr conn,
12825
                     virQEMUDriverPtr driver, virDomainObjPtr vm,
12826 12827 12828 12829 12830 12831
                     const char *device, virDomainDiskDefPtr disk)
{
    int ret = -1;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainBlockJobInfo info;
    const char *format = virStorageFileFormatTypeToString(disk->mirrorFormat);
E
Eric Blake 已提交
12832
    bool resume = false;
12833 12834 12835 12836
    virCgroupPtr cgroup = NULL;
    char *oldsrc = NULL;
    int oldformat;
    virStorageFileMetadataPtr oldchain = NULL;
12837 12838 12839 12840 12841 12842 12843 12844 12845 12846 12847 12848 12849 12850 12851 12852 12853 12854 12855 12856 12857 12858 12859 12860 12861 12862

    /* Probe the status, if needed.  */
    if (!disk->mirroring) {
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
        ret = qemuMonitorBlockJob(priv->mon, device, NULL, 0, &info,
                                  BLOCK_JOB_INFO, true);
        qemuDomainObjExitMonitorWithDriver(driver, vm);
        if (ret < 0)
            goto cleanup;
        if (!virDomainObjIsActive(vm)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("domain is not running"));
            goto cleanup;
        }
        if (ret == 1 && info.cur == info.end &&
            info.type == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY)
            disk->mirroring = true;
    }

    if (!disk->mirroring) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
                       _("disk '%s' not ready for pivot yet"),
                       disk->dst);
        goto cleanup;
    }

E
Eric Blake 已提交
12863 12864 12865 12866 12867 12868 12869 12870 12871 12872 12873 12874 12875 12876 12877 12878 12879 12880 12881 12882 12883 12884 12885
    /* If we are using the older 'drive-reopen', we want to make sure
     * that management apps can tell whether the command succeeded,
     * even if libvirtd is restarted at the wrong time.  To accomplish
     * that, we pause the guest before drive-reopen, and resume it
     * only when we know the outcome; if libvirtd restarts, then
     * management will see the guest still paused, and know that no
     * guest I/O has caused the source and mirror to diverge.  XXX
     * With the newer 'block-job-complete', we need to use a
     * persistent bitmap to make things safe; so for now, we just
     * blindly pause the guest.  */
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_NONE) < 0)
            goto cleanup;

        resume = true;
        if (!virDomainObjIsActive(vm)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
            goto cleanup;
        }
    }

12886 12887 12888 12889 12890 12891 12892 12893 12894 12895 12896 12897 12898 12899 12900 12901 12902 12903 12904 12905 12906 12907 12908 12909 12910 12911 12912 12913 12914 12915 12916 12917 12918 12919 12920 12921 12922 12923
    /* We previously labeled only the top-level image; but if the
     * image includes a relative backing file, the pivot may result in
     * qemu needing to open the entire backing chain, so we need to
     * label the entire chain.  This action is safe even if the
     * backing chain has already been labeled; but only necessary when
     * we know for sure that there is a backing chain.  */
    if (disk->mirrorFormat && disk->mirrorFormat != VIR_STORAGE_FILE_RAW &&
        qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to find cgroup for %s"),
                       vm->def->name);
        goto cleanup;
    }
    oldsrc = disk->src;
    oldformat = disk->format;
    oldchain = disk->backingChain;
    disk->src = disk->mirror;
    disk->format = disk->mirrorFormat;
    disk->backingChain = NULL;
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0) {
        disk->src = oldsrc;
        disk->format = oldformat;
        disk->backingChain = oldchain;
        goto cleanup;
    }
    if (disk->mirrorFormat && disk->mirrorFormat != VIR_STORAGE_FILE_RAW &&
        (virDomainLockDiskAttach(driver->lockManager, driver->uri,
                                 vm, disk) < 0 ||
         (cgroup && qemuSetupDiskCgroup(vm, cgroup, disk) < 0) ||
         virSecurityManagerSetImageLabel(driver->securityManager, vm->def,
                                         disk) < 0)) {
        disk->src = oldsrc;
        disk->format = oldformat;
        disk->backingChain = oldchain;
        goto cleanup;
    }

12924 12925 12926 12927 12928 12929 12930 12931 12932 12933 12934 12935 12936
    /* Attempt the pivot.  */
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
    ret = qemuMonitorDrivePivot(priv->mon, device, disk->mirror, format);
    qemuDomainObjExitMonitorWithDriver(driver, vm);

    if (ret == 0) {
        /* XXX We want to revoke security labels and disk lease, as
         * well as audit that revocation, before dropping the original
         * source.  But it gets tricky if both source and mirror share
         * common backing files (we want to only revoke the non-shared
         * portion of the chain, and is made more difficult by the
         * fact that we aren't tracking the full chain ourselves; so
         * for now, we leak the access to the original.  */
12937 12938
        VIR_FREE(oldsrc);
        virStorageFileFreeMetadata(oldchain);
12939 12940 12941 12942 12943 12944 12945 12946 12947 12948
        disk->mirror = NULL;
    } else {
        /* On failure, qemu abandons the mirror, and reverts back to
         * the source disk (RHEL 6.3 has a bug where the revert could
         * cause catastrophic failure in qemu, but we don't need to
         * worry about it here as it is not an upstream qemu problem.  */
        /* XXX should we be parsing the exact qemu error, or calling
         * 'query-block', to see what state we really got left in
         * before killing the mirroring job?  And just as on the
         * success case, there's security labeling to worry about.  */
12949 12950 12951 12952
        disk->src = oldsrc;
        disk->format = oldformat;
        virStorageFileFreeMetadata(disk->backingChain);
        disk->backingChain = oldchain;
12953 12954
        VIR_FREE(disk->mirror);
    }
12955 12956
    disk->mirrorFormat = VIR_STORAGE_FILE_NONE;
    disk->mirroring = false;
12957 12958

cleanup:
12959 12960
    if (cgroup)
        virCgroupFree(&cgroup);
E
Eric Blake 已提交
12961 12962 12963
    if (resume && virDomainObjIsActive(vm) &&
        qemuProcessStartCPUs(driver, vm, conn,
                             VIR_DOMAIN_RUNNING_UNPAUSED,
12964 12965 12966 12967 12968 12969 12970 12971 12972 12973 12974
                             QEMU_ASYNC_JOB_NONE) < 0) {
        virDomainEventPtr event = NULL;
        event = virDomainEventNewFromObj(vm,
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
        if (event)
            qemuDomainEventQueue(driver, event);
        if (virGetLastError() == NULL) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("resuming after drive-reopen failed"));
        }
E
Eric Blake 已提交
12975
    }
12976 12977 12978
    return ret;
}

12979
static int
12980
qemuDomainBlockJobImpl(virDomainPtr dom, const char *path, const char *base,
12981
                       unsigned long bandwidth, virDomainBlockJobInfoPtr info,
12982
                       int mode, unsigned int flags)
12983
{
12984
    virQEMUDriverPtr driver = dom->conn->privateData;
12985 12986 12987
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    char uuidstr[VIR_UUID_STRING_BUFLEN];
E
Eric Blake 已提交
12988
    char *device = NULL;
12989
    int ret = -1;
12990
    bool async = false;
12991 12992 12993
    virDomainEventPtr event = NULL;
    int idx;
    virDomainDiskDefPtr disk;
12994 12995 12996 12997 12998

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
12999 13000
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
13001 13002
        goto cleanup;
    }
13003
    if (!virDomainObjIsActive(vm)) {
13004 13005
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
13006 13007 13008
        goto cleanup;
    }

13009
    priv = vm->privateData;
13010
    if (qemuCapsGet(priv->caps, QEMU_CAPS_BLOCKJOB_ASYNC)) {
13011
        async = true;
13012
    } else if (!qemuCapsGet(priv->caps, QEMU_CAPS_BLOCKJOB_SYNC)) {
13013 13014
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block jobs not supported with this QEMU binary"));
13015 13016
        goto cleanup;
    } else if (base) {
13017 13018 13019
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("partial block pull not supported with this "
                         "QEMU binary"));
13020
        goto cleanup;
13021
    } else if (mode == BLOCK_JOB_PULL && bandwidth) {
13022 13023 13024
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("setting bandwidth at start of block pull not "
                         "supported with this QEMU binary"));
13025
        goto cleanup;
13026
    }
13027

13028 13029
    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device)
13030
        goto cleanup;
13031
    disk = vm->def->disks[idx];
13032

E
Eric Blake 已提交
13033 13034 13035 13036 13037 13038
    if (mode == BLOCK_JOB_PULL && disk->mirror) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
                       _("disk '%s' already in active block copy job"),
                       disk->dst);
        goto cleanup;
    }
13039 13040 13041 13042 13043 13044 13045 13046
    if (mode == BLOCK_JOB_ABORT &&
        (flags & VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT) &&
        !(async && disk->mirror)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       _("pivot of disk '%s' requires an active copy job"),
                       disk->dst);
        goto cleanup;
    }
E
Eric Blake 已提交
13047

13048 13049
    if (qemuDomainObjBeginJobWithDriver(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;
13050 13051

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

13057 13058
    if (disk->mirror && mode == BLOCK_JOB_ABORT &&
        (flags & VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT)) {
E
Eric Blake 已提交
13059
        ret = qemuDomainBlockPivot(dom->conn, driver, vm, device, disk);
13060 13061 13062
        goto endjob;
    }

13063
    qemuDomainObjEnterMonitorWithDriver(driver, vm);
13064
    /* XXX - libvirt should really be tracking the backing file chain
13065 13066
     * itself, and validating that base is on the chain, rather than
     * relying on qemu to do this.  */
13067 13068
    ret = qemuMonitorBlockJob(priv->mon, device, base, bandwidth, info, mode,
                              async);
13069
    qemuDomainObjExitMonitorWithDriver(driver, vm);
13070 13071 13072
    if (ret < 0)
        goto endjob;

13073 13074 13075 13076 13077 13078
    /* Snoop block copy operations, so future cancel operations can
     * avoid checking if pivot is safe.  */
    if (mode == BLOCK_JOB_INFO && ret == 1 && disk->mirror &&
        info->cur == info->end && info->type == VIR_DOMAIN_BLOCK_JOB_TYPE_COPY)
        disk->mirroring = true;

13079 13080 13081 13082 13083 13084 13085 13086 13087
    /* A successful block job cancelation stops any mirroring.  */
    if (mode == BLOCK_JOB_ABORT && disk->mirror) {
        /* XXX We should also revoke security labels and disk lease on
         * the mirror, and audit that fact, before dropping things.  */
        VIR_FREE(disk->mirror);
        disk->mirrorFormat = VIR_STORAGE_FILE_NONE;
        disk->mirroring = false;
    }

13088 13089 13090 13091 13092 13093 13094 13095 13096 13097 13098 13099 13100 13101 13102 13103 13104 13105 13106 13107 13108 13109 13110 13111 13112 13113 13114
    /* 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;

13115
                virObjectUnlock(vm);
13116 13117 13118 13119 13120
                qemuDriverUnlock(driver);

                nanosleep(&ts, NULL);

                qemuDriverLock(driver);
13121
                virObjectLock(vm);
13122 13123

                if (!virDomainObjIsActive(vm)) {
13124 13125
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("domain is not running"));
13126 13127 13128 13129 13130 13131
                    ret = -1;
                    break;
                }
            }
        }
    }
13132 13133

endjob:
13134 13135 13136 13137 13138 13139 13140 13141
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

cleanup:
    VIR_FREE(device);
    if (vm)
13142
        virObjectUnlock(vm);
13143 13144
    if (event)
        qemuDomainEventQueue(driver, event);
13145 13146 13147 13148 13149 13150 13151
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainBlockJobAbort(virDomainPtr dom, const char *path, unsigned int flags)
{
13152 13153
    virCheckFlags(VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC |
                  VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT, -1);
13154 13155
    return qemuDomainBlockJobImpl(dom, path, NULL, 0, NULL, BLOCK_JOB_ABORT,
                                  flags);
13156 13157 13158 13159 13160 13161 13162
}

static int
qemuDomainGetBlockJobInfo(virDomainPtr dom, const char *path,
                           virDomainBlockJobInfoPtr info, unsigned int flags)
{
    virCheckFlags(0, -1);
13163 13164
    return qemuDomainBlockJobImpl(dom, path, NULL, 0, info, BLOCK_JOB_INFO,
                                  flags);
13165 13166 13167 13168 13169 13170 13171
}

static int
qemuDomainBlockJobSetSpeed(virDomainPtr dom, const char *path,
                           unsigned long bandwidth, unsigned int flags)
{
    virCheckFlags(0, -1);
13172
    return qemuDomainBlockJobImpl(dom, path, NULL, bandwidth, NULL,
13173
                                  BLOCK_JOB_SPEED, flags);
13174 13175
}

13176 13177 13178 13179 13180
static int
qemuDomainBlockCopy(virDomainPtr dom, const char *path,
                    const char *dest, const char *format,
                    unsigned long bandwidth, unsigned int flags)
{
13181
    virQEMUDriverPtr driver = dom->conn->privateData;
13182 13183 13184 13185 13186 13187
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    char *device = NULL;
    virDomainDiskDefPtr disk;
    int ret = -1;
    int idx;
13188
    struct stat st;
13189 13190 13191
    bool need_unlink = false;
    char *mirror = NULL;
    virCgroupPtr cgroup = NULL;
13192 13193

    /* Preliminaries: find the disk we are editing, sanity checks */
13194 13195
    virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
                  VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT, -1);
13196 13197 13198 13199 13200 13201 13202 13203 13204 13205

    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
    priv = vm->privateData;

    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
        goto cleanup;
    }
13206 13207 13208 13209 13210 13211 13212
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to find cgroup for %s"),
                       vm->def->name);
        goto cleanup;
    }
13213 13214 13215 13216 13217 13218 13219 13220 13221 13222 13223 13224 13225 13226 13227 13228 13229 13230 13231 13232 13233 13234 13235 13236 13237 13238 13239 13240 13241 13242 13243 13244 13245 13246 13247 13248 13249 13250 13251 13252 13253 13254 13255 13256 13257 13258 13259 13260 13261 13262 13263

    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device) {
        goto cleanup;
    }
    disk = vm->def->disks[idx];
    if (disk->mirror) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
                       _("disk '%s' already in active block copy job"),
                       disk->dst);
        goto cleanup;
    }

    if (!(qemuCapsGet(priv->caps, QEMU_CAPS_DRIVE_MIRROR) &&
          qemuCapsGet(priv->caps, QEMU_CAPS_BLOCKJOB_ASYNC))) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block copy is not supported with this QEMU binary"));
        goto cleanup;
    }
    if (vm->persistent) {
        /* XXX if qemu ever lets us start a new domain with mirroring
         * already active, we can relax this; but for now, the risk of
         * 'managedsave' due to libvirt-guests means we can't risk
         * this on persistent domains.  */
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not transient"));
        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;
    }
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
        goto endjob;

    if ((flags & VIR_DOMAIN_BLOCK_REBASE_SHALLOW) &&
        STREQ_NULLABLE(format, "raw") &&
        disk->backingChain->backingStore) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk '%s' has backing file, so raw shallow copy "
                         "is not possible"),
                       disk->dst);
        goto endjob;
    }

    /* Prepare the destination file.  */
13264 13265 13266 13267 13268 13269 13270 13271 13272 13273 13274 13275 13276 13277 13278 13279 13280 13281 13282 13283
    if (stat(dest, &st) < 0) {
        if (errno != ENOENT) {
            virReportSystemError(errno, _("unable to stat for disk %s: %s"),
                                 disk->dst, dest);
            goto endjob;
        } else if (flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT) {
            virReportSystemError(errno,
                                 _("missing destination file for disk %s: %s"),
                                 disk->dst, dest);
            goto endjob;
        }
    } else if (!S_ISBLK(st.st_mode) && st.st_size &&
               !(flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("external destination file for disk %s already "
                         "exists and is not a block device: %s"),
                       disk->dst, dest);
        goto endjob;
    }

13284 13285 13286 13287 13288 13289 13290
    if (!(flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT)) {
        int fd = qemuOpenFile(driver, dest, O_WRONLY | O_TRUNC | O_CREAT,
                              &need_unlink, NULL);
        if (fd < 0)
            goto endjob;
        VIR_FORCE_CLOSE(fd);
        if (!format)
13291
            disk->mirrorFormat = disk->format;
13292
    } else if (format) {
13293 13294 13295 13296 13297 13298
        disk->mirrorFormat = virStorageFileFormatTypeFromString(format);
        if (disk->mirrorFormat <= 0) {
            virReportError(VIR_ERR_INVALID_ARG, _("unrecognized format '%s'"),
                           format);
            goto endjob;
        }
13299 13300 13301 13302 13303 13304 13305 13306 13307 13308
    } else {
        /* If the user passed the REUSE_EXT flag, then either they
         * also passed the RAW flag (and format is non-NULL), or it is
         * safe for us to probe the format from the file that we will
         * be using.  */
        disk->mirrorFormat = virStorageFileProbeFormat(dest, driver->user,
                                                       driver->group);
    }
    if (!format && disk->mirrorFormat > 0)
        format = virStorageFileFormatTypeToString(disk->mirrorFormat);
13309
    if (!(mirror = strdup(dest))) {
13310 13311 13312 13313
        virReportOOMError();
        goto endjob;
    }

13314 13315 13316 13317 13318 13319 13320
    if (qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, dest,
                                          VIR_DISK_CHAIN_READ_WRITE) < 0) {
        qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, dest,
                                          VIR_DISK_CHAIN_NO_ACCESS);
        goto endjob;
    }

13321 13322 13323 13324
    /* Actually start the mirroring */
    qemuDomainObjEnterMonitor(driver, vm);
    ret = qemuMonitorDriveMirror(priv->mon, device, dest, format, bandwidth,
                                 flags);
13325
    virDomainAuditDisk(vm, NULL, dest, "mirror", ret >= 0);
13326
    qemuDomainObjExitMonitor(driver, vm);
13327 13328 13329 13330 13331 13332 13333 13334 13335 13336
    if (ret < 0) {
        qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, dest,
                                          VIR_DISK_CHAIN_NO_ACCESS);
        goto endjob;
    }

    /* Update vm in place to match changes.  */
    need_unlink = false;
    disk->mirror = mirror;
    mirror = NULL;
13337 13338

endjob:
13339 13340 13341
    if (need_unlink && unlink(dest))
        VIR_WARN("unable to unlink just-created %s", dest);
    if (ret < 0)
13342
        disk->mirrorFormat = VIR_STORAGE_FILE_NONE;
13343
    VIR_FREE(mirror);
13344 13345 13346 13347 13348 13349
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

cleanup:
13350 13351
    if (cgroup)
        virCgroupFree(&cgroup);
13352 13353
    VIR_FREE(device);
    if (vm)
13354
        virObjectUnlock(vm);
13355 13356 13357
    return ret;
}

13358
static int
13359 13360
qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base,
                      unsigned long bandwidth, unsigned int flags)
13361
{
13362
    virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
13363
                  VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT |
13364 13365 13366 13367 13368 13369 13370 13371 13372 13373 13374 13375
                  VIR_DOMAIN_BLOCK_REBASE_COPY |
                  VIR_DOMAIN_BLOCK_REBASE_COPY_RAW, -1);

    if (flags & VIR_DOMAIN_BLOCK_REBASE_COPY) {
        const char *format = NULL;
        if (flags & VIR_DOMAIN_BLOCK_REBASE_COPY_RAW)
            format = "raw";
        flags &= ~(VIR_DOMAIN_BLOCK_REBASE_COPY |
                   VIR_DOMAIN_BLOCK_REBASE_COPY_RAW);
        return qemuDomainBlockCopy(dom, path, base, format, bandwidth, flags);
    }

13376 13377
    return qemuDomainBlockJobImpl(dom, path, base, bandwidth, NULL,
                                  BLOCK_JOB_PULL, flags);
13378
}
13379

13380 13381 13382 13383
static int
qemuDomainBlockPull(virDomainPtr dom, const char *path, unsigned long bandwidth,
                    unsigned int flags)
{
13384 13385 13386
    virCheckFlags(0, -1);
    return qemuDomainBlockJobImpl(dom, path, NULL, bandwidth, NULL,
                                  BLOCK_JOB_PULL, flags);
13387 13388
}

13389 13390 13391 13392 13393 13394

static int
qemuDomainBlockCommit(virDomainPtr dom, const char *path, const char *base,
                      const char *top, unsigned long bandwidth,
                      unsigned int flags)
{
13395
    virQEMUDriverPtr driver = dom->conn->privateData;
13396 13397 13398 13399 13400
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm = NULL;
    char *device = NULL;
    int ret = -1;
    int idx;
E
Eric Blake 已提交
13401
    virDomainDiskDefPtr disk = NULL;
13402 13403 13404 13405
    const char *top_canon = NULL;
    virStorageFileMetadataPtr top_meta = NULL;
    const char *top_parent = NULL;
    const char *base_canon = NULL;
13406
    virCgroupPtr cgroup = NULL;
E
Eric Blake 已提交
13407
    bool clean_access = false;
13408

13409
    virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW, -1);
13410 13411 13412 13413 13414 13415 13416 13417 13418 13419 13420 13421 13422 13423 13424 13425 13426 13427 13428 13429 13430 13431 13432 13433 13434 13435 13436 13437 13438 13439

    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
    priv = vm->privateData;

    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;
    }
    if (!qemuCapsGet(priv->caps, QEMU_CAPS_BLOCK_COMMIT)) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("online commit not supported with this QEMU binary"));
        goto endjob;
    }

    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device)
        goto endjob;
    disk = vm->def->disks[idx];

    if (!disk->src) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk %s has no source file to be committed"),
                       disk->dst);
        goto endjob;
    }
13440 13441
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
        goto endjob;
13442

13443 13444 13445 13446 13447 13448 13449 13450 13451 13452 13453 13454 13455 13456 13457 13458 13459 13460 13461 13462 13463 13464 13465 13466 13467 13468 13469 13470 13471 13472 13473 13474 13475 13476 13477 13478 13479 13480 13481
    if (!top) {
        top_canon = disk->src;
        top_meta = disk->backingChain;
    } else if (!(top_canon = virStorageFileChainLookup(disk->backingChain,
                                                       disk->src,
                                                       top, &top_meta,
                                                       &top_parent))) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("could not find top '%s' in chain for '%s'"),
                       top, path);
        goto endjob;
    }
    if (!top_meta || !top_meta->backingStore) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("top '%s' in chain for '%s' has no backing file"),
                       top, path);
        goto endjob;
    }
    if (!base && (flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW)) {
        base_canon = top_meta->backingStore;
    } else if (!(base_canon = virStorageFileChainLookup(top_meta, top_canon,
                                                        base, NULL, NULL))) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("could not find base '%s' below '%s' in chain "
                         "for '%s'"),
                       base ? base : "(default)", top_canon, path);
        goto endjob;
    }
    /* Note that this code exploits the fact that
     * virStorageFileChainLookup guarantees a simple pointer
     * comparison will work, rather than needing full-blown STREQ.  */
    if ((flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW) &&
        base_canon != top_meta->backingStore) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("base '%s' is not immediately below '%s' in chain "
                         "for '%s'"),
                       base, top_canon, path);
        goto endjob;
    }
13482

13483 13484 13485 13486 13487 13488 13489 13490 13491 13492 13493 13494 13495 13496
    /* For the commit to succeed, we must allow qemu to open both the
     * 'base' image and the parent of 'top' as read/write; 'top' might
     * not have a parent, or might already be read-write.  XXX It
     * would also be nice to revert 'base' to read-only, as well as
     * revoke access to files removed from the chain, when the commit
     * operation succeeds, but doing that requires tracking the
     * operation in XML across libvirtd restarts.  */
    if (qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_DEVICES) &&
        virCgroupForDomain(driver->cgroup, vm->def->name, &cgroup, 0) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Unable to find cgroup for %s"),
                       vm->def->name);
        goto endjob;
    }
E
Eric Blake 已提交
13497
    clean_access = true;
13498 13499 13500 13501 13502 13503 13504 13505 13506
    if (qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, base_canon,
                                          VIR_DISK_CHAIN_READ_WRITE) < 0 ||
        (top_parent && top_parent != disk->src &&
         qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk,
                                           top_parent,
                                           VIR_DISK_CHAIN_READ_WRITE) < 0))
        goto endjob;

    /* Start the commit operation.  */
13507
    qemuDomainObjEnterMonitor(driver, vm);
13508 13509
    ret = qemuMonitorBlockCommit(priv->mon, device, top_canon, base_canon,
                                 bandwidth);
13510 13511 13512
    qemuDomainObjExitMonitor(driver, vm);

endjob:
E
Eric Blake 已提交
13513
    if (ret < 0 && clean_access) {
13514 13515 13516 13517 13518 13519 13520 13521 13522 13523
        /* Revert access to read-only, if possible.  */
        qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk, base_canon,
                                          VIR_DISK_CHAIN_READ_ONLY);
        if (top_parent && top_parent != disk->src)
            qemuDomainPrepareDiskChainElement(driver, vm, cgroup, disk,
                                              top_parent,
                                              VIR_DISK_CHAIN_READ_ONLY);
    }
    if (cgroup)
        virCgroupFree(&cgroup);
13524 13525 13526 13527 13528 13529 13530 13531
    if (qemuDomainObjEndJob(driver, vm) == 0) {
        vm = NULL;
        goto cleanup;
    }

cleanup:
    VIR_FREE(device);
    if (vm)
13532
        virObjectUnlock(vm);
13533 13534 13535
    return ret;
}

13536 13537 13538 13539 13540 13541
static int
qemuDomainOpenGraphics(virDomainPtr dom,
                       unsigned int idx,
                       int fd,
                       unsigned int flags)
{
13542
    virQEMUDriverPtr driver = dom->conn->privateData;
13543 13544 13545 13546 13547 13548 13549 13550 13551 13552 13553 13554
    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) {
13555 13556
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
13557 13558 13559 13560
        goto cleanup;
    }

    if (!virDomainObjIsActive(vm)) {
13561 13562
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
13563 13564 13565 13566 13567 13568
        goto cleanup;
    }

    priv = vm->privateData;

    if (idx >= vm->def->ngraphics) {
13569 13570
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No graphics backend with index %d"), idx);
13571 13572 13573 13574 13575 13576 13577 13578 13579 13580
        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:
13581 13582 13583
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Can only open VNC or SPICE graphics backends, not %s"),
                       virDomainGraphicsTypeToString(vm->def->graphics[idx]->type));
13584 13585 13586 13587 13588 13589 13590 13591 13592 13593 13594 13595 13596 13597 13598 13599
        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)
13600
        virObjectUnlock(vm);
13601 13602 13603 13604
    qemuDriverUnlock(driver);
    return ret;
}

13605 13606 13607 13608 13609 13610 13611
static int
qemuDomainSetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int nparams,
                         unsigned int flags)
{
13612
    virQEMUDriverPtr driver = dom->conn->privateData;
13613 13614 13615 13616
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virDomainDefPtr persistentDef = NULL;
    virDomainBlockIoTuneInfo info;
E
Eric Blake 已提交
13617
    virDomainBlockIoTuneInfo *oldinfo;
13618 13619 13620 13621 13622
    char uuidstr[VIR_UUID_STRING_BUFLEN];
    const char *device = NULL;
    int ret = -1;
    int i;
    int idx = -1;
E
Eric Blake 已提交
13623 13624
    bool set_bytes = false;
    bool set_iops = false;
13625 13626 13627

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
13628 13629 13630 13631 13632 13633 13634 13635 13636 13637 13638 13639 13640 13641 13642
    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;
13643 13644 13645 13646 13647 13648 13649

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

    qemuDriverLock(driver);
    virUUIDFormat(dom->uuid, uuidstr);
    vm = virDomainFindByUUID(&driver->domains, dom->uuid);
    if (!vm) {
13650 13651
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
13652 13653
        goto cleanup;
    }
13654
    priv = vm->privateData;
13655
    if (!qemuCapsGet(priv->caps, QEMU_CAPS_DRIVE_IOTUNE)) {
13656 13657 13658
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block I/O throttling not supported with this "
                         "QEMU binary"));
13659 13660
        goto cleanup;
    }
13661

E
Eric Blake 已提交
13662
    device = qemuDiskPathToAlias(vm, disk, &idx);
13663 13664 13665 13666 13667 13668 13669
    if (!device) {
        goto cleanup;
    }

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

13670 13671
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
13672 13673 13674 13675 13676 13677 13678
        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 已提交
13679
            set_bytes = true;
13680 13681 13682
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC)) {
            info.read_bytes_sec = param->value.ul;
E
Eric Blake 已提交
13683
            set_bytes = true;
13684 13685 13686
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC)) {
            info.write_bytes_sec = param->value.ul;
E
Eric Blake 已提交
13687
            set_bytes = true;
13688 13689 13690
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC)) {
            info.total_iops_sec = param->value.ul;
E
Eric Blake 已提交
13691
            set_iops = true;
13692 13693 13694
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC)) {
            info.read_iops_sec = param->value.ul;
E
Eric Blake 已提交
13695
            set_iops = true;
13696 13697 13698
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC)) {
            info.write_iops_sec = param->value.ul;
E
Eric Blake 已提交
13699
            set_iops = true;
13700 13701 13702 13703 13704
        }
    }

    if ((info.total_bytes_sec && info.read_bytes_sec) ||
        (info.total_bytes_sec && info.write_bytes_sec)) {
13705 13706
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("total and read/write of bytes_sec cannot be set at the same time"));
13707 13708 13709 13710 13711
        goto endjob;
    }

    if ((info.total_iops_sec && info.read_iops_sec) ||
        (info.total_iops_sec && info.write_iops_sec)) {
13712 13713
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("total and read/write of iops_sec cannot be set at the same time"));
13714 13715 13716 13717
        goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
E
Eric Blake 已提交
13718 13719 13720 13721 13722 13723 13724 13725 13726 13727 13728 13729 13730 13731
        /* 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;
        }
13732 13733 13734
        qemuDomainObjEnterMonitorWithDriver(driver, vm);
        ret = qemuMonitorSetBlockIoThrottle(priv->mon, device, &info);
        qemuDomainObjExitMonitorWithDriver(driver, vm);
L
Lei Li 已提交
13735 13736
        if (ret < 0)
            goto endjob;
13737
        vm->def->disks[idx]->blkdeviotune = info;
13738 13739 13740
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
13741 13742 13743 13744
        sa_assert(persistentDef);
        idx = virDomainDiskIndexByName(persistentDef, disk, true);
        if (idx < 0)
            goto endjob;
E
Eric Blake 已提交
13745 13746 13747 13748 13749 13750 13751 13752 13753 13754 13755
        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;
        }
13756 13757 13758
        persistentDef->disks[idx]->blkdeviotune = info;
        ret = virDomainSaveConfig(driver->configDir, persistentDef);
        if (ret < 0) {
13759
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
13760 13761 13762 13763 13764 13765 13766 13767 13768 13769 13770 13771
                           _("Write to config file failed"));
            goto endjob;
        }
    }

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

cleanup:
    VIR_FREE(device);
    if (vm)
13772
        virObjectUnlock(vm);
13773 13774 13775 13776 13777 13778 13779 13780 13781 13782 13783
    qemuDriverUnlock(driver);
    return ret;
}

static int
qemuDomainGetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int *nparams,
                         unsigned int flags)
{
13784
    virQEMUDriverPtr driver = dom->conn->privateData;
13785 13786 13787 13788 13789 13790 13791 13792 13793 13794 13795 13796 13797 13798 13799 13800 13801 13802 13803 13804
    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) {
13805 13806
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
13807 13808 13809 13810 13811 13812 13813 13814 13815 13816
        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 已提交
13817
    device = qemuDiskPathToAlias(vm, disk, NULL);
13818 13819 13820 13821 13822 13823 13824 13825

    if (!device) {
        goto cleanup;
    }

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

13826 13827
    if (virDomainLiveConfigHelperMethod(driver->caps, vm, &flags,
                                        &persistentDef) < 0)
13828 13829 13830 13831 13832 13833 13834 13835 13836 13837 13838 13839 13840 13841 13842 13843 13844 13845 13846 13847 13848
        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];

13849
        switch (i) {
13850
        case 0:
13851 13852 13853 13854
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_bytes_sec) < 0)
13855 13856 13857
                goto endjob;
            break;
        case 1:
13858 13859 13860 13861
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_bytes_sec) < 0)
13862 13863 13864
                goto endjob;
            break;
        case 2:
13865 13866 13867 13868
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_bytes_sec) < 0)
13869 13870 13871
                goto endjob;
            break;
        case 3:
13872 13873 13874 13875
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_iops_sec) < 0)
13876 13877 13878
                goto endjob;
            break;
        case 4:
13879 13880 13881 13882
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_iops_sec) < 0)
13883 13884 13885
                goto endjob;
            break;
        case 5:
13886 13887 13888 13889
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_iops_sec) < 0)
13890 13891 13892 13893 13894 13895 13896 13897 13898 13899 13900 13901 13902 13903 13904 13905 13906 13907
                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)
13908
        virObjectUnlock(vm);
13909 13910 13911
    qemuDriverUnlock(driver);
    return ret;
}
13912

13913 13914 13915 13916 13917 13918
static int
qemuDomainGetDiskErrors(virDomainPtr dom,
                        virDomainDiskErrorPtr errors,
                        unsigned int nerrors,
                        unsigned int flags)
{
13919
    virQEMUDriverPtr driver = dom->conn->privateData;
13920 13921 13922 13923 13924 13925 13926 13927 13928
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virHashTablePtr table = NULL;
    int ret = -1;
    int i;
    int n = 0;

    virCheckFlags(0, -1);

13929
    if (!(vm = qemuDomObjFromDomain(dom)))
13930 13931 13932 13933 13934 13935 13936 13937
        goto cleanup;

    priv = vm->privateData;

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

    if (!virDomainObjIsActive(vm)) {
13938 13939
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
13940 13941 13942 13943 13944 13945 13946 13947 13948 13949 13950 13951 13952 13953 13954 13955 13956 13957 13958 13959 13960 13961 13962 13963 13964 13965 13966 13967 13968 13969 13970 13971 13972 13973 13974 13975 13976 13977 13978 13979
        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)
13980
        virObjectUnlock(vm);
13981 13982 13983 13984 13985 13986 13987 13988
    virHashFree(table);
    if (ret < 0) {
        for (i = 0; i < n; i++)
            VIR_FREE(errors[i].disk);
    }
    return ret;
}

13989 13990 13991 13992 13993 13994 13995 13996
static int
qemuDomainSetMetadata(virDomainPtr dom,
                      int type,
                      const char *metadata,
                      const char *key ATTRIBUTE_UNUSED,
                      const char *uri ATTRIBUTE_UNUSED,
                      unsigned int flags)
{
13997
    virQEMUDriverPtr driver = dom->conn->privateData;
13998 13999 14000 14001 14002 14003 14004
    virDomainObjPtr vm;
    virDomainDefPtr persistentDef;
    int ret = -1;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

14005
    if (!(vm = qemuDomObjFromDomain(dom)))
14006 14007 14008 14009 14010 14011 14012 14013 14014 14015 14016 14017 14018 14019 14020 14021 14022 14023 14024 14025 14026
        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:
14027
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
14028
                           _("QEmu driver does not support modifying "
14029
                             "<metadata> element"));
14030 14031 14032
            goto cleanup;
            break;
        default:
14033 14034
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("unknown metadata type"));
14035 14036 14037 14038 14039 14040 14041 14042 14043 14044 14045 14046 14047 14048 14049 14050 14051 14052 14053 14054
            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:
14055
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
14056
                           _("QEMU driver does not support "
14057
                             "<metadata> element"));
14058 14059
            goto cleanup;
         default:
14060 14061
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("unknown metadata type"));
14062 14063 14064 14065 14066 14067 14068 14069 14070 14071 14072 14073
            goto cleanup;
            break;
        }

        if (virDomainSaveConfig(driver->configDir, persistentDef) < 0)
            goto cleanup;
    }

    ret = 0;

cleanup:
    if (vm)
14074
        virObjectUnlock(vm);
14075 14076 14077 14078 14079 14080 14081 14082 14083 14084 14085 14086
    return ret;
no_memory:
    virReportOOMError();
    goto cleanup;
}

static char *
qemuDomainGetMetadata(virDomainPtr dom,
                      int type,
                      const char *uri ATTRIBUTE_UNUSED,
                      unsigned int flags)
{
14087
    virQEMUDriverPtr driver = dom->conn->privateData;
14088 14089 14090 14091 14092 14093 14094 14095
    virDomainObjPtr vm;
    virDomainDefPtr def;
    char *ret = NULL;
    char *field = NULL;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, NULL);

14096
    if (!(vm = qemuDomObjFromDomain(dom)))
14097 14098 14099 14100 14101 14102 14103 14104 14105 14106 14107 14108 14109 14110 14111 14112 14113
        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:
14114
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
14115
                       _("QEMU driver does not support "
14116
                         "<metadata> element"));
14117 14118 14119
        goto cleanup;
        break;
    default:
14120 14121
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("unknown metadata type"));
14122 14123 14124 14125 14126
        goto cleanup;
        break;
    }

    if (!field) {
14127 14128
        virReportError(VIR_ERR_NO_DOMAIN_METADATA, "%s",
                       _("Requested metadata element is not present"));
14129 14130 14131 14132 14133 14134 14135 14136 14137 14138
        goto cleanup;
    }

    if (!(ret = strdup(field))) {
        virReportOOMError();
        goto cleanup;
    }

cleanup:
    if (vm)
14139
        virObjectUnlock(vm);
14140 14141 14142
    return ret;
}

14143 14144 14145 14146 14147 14148 14149 14150 14151 14152
/* 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 已提交
14153
        return QEMU_NB_TOTAL_CPU_STAT_PARAM;
14154 14155 14156 14157 14158 14159 14160
    /* 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 已提交
14161 14162 14163 14164 14165 14166 14167 14168 14169 14170 14171 14172 14173 14174 14175 14176 14177 14178 14179 14180 14181 14182 14183 14184 14185 14186 14187 14188 14189
    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;
14190 14191
}

14192 14193 14194 14195 14196 14197 14198 14199 14200 14201 14202 14203 14204 14205 14206 14207 14208 14209 14210 14211 14212 14213 14214 14215 14216 14217 14218 14219 14220 14221 14222
/* 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) {
14223 14224
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("error accessing cgroup cpuacct for vcpu"));
14225 14226 14227
            goto cleanup;
        }

14228
        if (virCgroupGetCpuacctPercpuUsage(group_vcpu, &buf) < 0)
14229 14230 14231 14232 14233
            goto cleanup;

        pos = buf;
        for (j = 0; j < num; j++) {
            if (virStrToLong_ull(pos, &pos, 10, &tmp) < 0) {
14234 14235
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("cpuacct parse error"));
14236 14237 14238 14239 14240 14241 14242 14243 14244 14245 14246 14247 14248 14249 14250 14251
                goto cleanup;
            }
            sum_cpu_time[j] += tmp;
        }

        virCgroupFree(&group_vcpu);
        VIR_FREE(buf);
    }

    ret = 0;
cleanup:
    virCgroupFree(&group_vcpu);
    VIR_FREE(buf);
    return ret;
}

14252
static int
14253
qemuDomainGetPercpuStats(virDomainObjPtr vm,
14254 14255 14256 14257 14258 14259 14260
                         virCgroupPtr group,
                         virTypedParameterPtr params,
                         unsigned int nparams,
                         int start_cpu,
                         unsigned int ncpus)
{
    int rv = -1;
14261
    int i, id, max_id;
14262 14263
    char *pos;
    char *buf = NULL;
14264 14265 14266 14267
    unsigned long long *sum_cpu_time = NULL;
    unsigned long long *sum_cpu_pos;
    unsigned int n = 0;
    qemuDomainObjPrivatePtr priv = vm->privateData;
14268 14269
    virTypedParameterPtr ent;
    int param_idx;
14270
    unsigned long long cpu_time;
14271 14272 14273

    /* return the number of supported params */
    if (nparams == 0 && ncpus != 0)
14274
        return QEMU_NB_PER_CPU_STAT_PARAM;
14275

14276 14277 14278
    /* To parse account file, we need to know how many cpus are present.  */
    max_id = nodeGetCPUCount();
    if (max_id < 0)
14279 14280 14281
        return rv;

    if (ncpus == 0) { /* returns max cpu ID */
14282
        rv = max_id;
14283 14284 14285 14286
        goto cleanup;
    }

    if (start_cpu > max_id) {
14287 14288 14289
        virReportError(VIR_ERR_INVALID_ARG,
                       _("start_cpu %d larger than maximum of %d"),
                       start_cpu, max_id);
14290 14291 14292 14293 14294 14295 14296
        goto cleanup;
    }

    /* we get percpu cputime accounting info. */
    if (virCgroupGetCpuacctPercpuUsage(group, &buf))
        goto cleanup;
    pos = buf;
14297
    memset(params, 0, nparams * ncpus);
14298

14299 14300 14301
    /* return percpu cputime in index 0 */
    param_idx = 0;

14302 14303 14304
    /* number of cpus to compute */
    id = max_id;

14305
    if (max_id - start_cpu > ncpus - 1)
14306
        id = start_cpu + ncpus - 1;
14307

14308
    for (i = 0; i <= id; i++) {
14309
        if (virStrToLong_ull(pos, &pos, 10, &cpu_time) < 0) {
14310
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
14311
                           _("cpuacct parse error"));
14312
            goto cleanup;
14313 14314
        } else {
            n++;
14315 14316 14317
        }
        if (i < start_cpu)
            continue;
14318
        ent = &params[(i - start_cpu) * nparams + param_idx];
E
Eric Blake 已提交
14319 14320 14321
        if (virTypedParameterAssign(ent, VIR_DOMAIN_CPU_STATS_CPUTIME,
                                    VIR_TYPED_PARAM_ULLONG, cpu_time) < 0)
            goto cleanup;
14322
    }
14323 14324 14325 14326 14327 14328 14329 14330 14331 14332 14333 14334 14335 14336 14337

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

    sum_cpu_pos = sum_cpu_time;
14338
    for (i = 0; i <= id; i++) {
14339
        cpu_time = *(sum_cpu_pos++);
14340 14341 14342 14343 14344 14345 14346 14347 14348 14349
        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;
    }

14350 14351
    rv = param_idx + 1;
cleanup:
14352
    VIR_FREE(sum_cpu_time);
14353 14354 14355 14356 14357 14358 14359 14360 14361 14362 14363 14364 14365
    VIR_FREE(buf);
    return rv;
}


static int
qemuDomainGetCPUStats(virDomainPtr domain,
                virTypedParameterPtr params,
                unsigned int nparams,
                int start_cpu,
                unsigned int ncpus,
                unsigned int flags)
{
14366
    virQEMUDriverPtr driver = domain->conn->privateData;
14367 14368 14369 14370 14371 14372 14373 14374 14375 14376 14377
    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) {
14378 14379
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No such domain %s"), domain->uuid);
14380 14381 14382 14383 14384
        goto cleanup;
    }

    isActive = virDomainObjIsActive(vm);
    if (!isActive) {
14385 14386
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
14387 14388 14389 14390
        goto cleanup;
    }

    if (!qemuCgroupControllerActive(driver, VIR_CGROUP_CONTROLLER_CPUACCT)) {
14391 14392
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPUACCT controller is not mounted"));
14393 14394 14395 14396
        goto cleanup;
    }

    if (virCgroupForDomain(driver->cgroup, vm->def->name, &group, 0) != 0) {
14397 14398
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find cgroup for domain %s"), vm->def->name);
14399 14400 14401 14402 14403 14404
        goto cleanup;
    }

    if (start_cpu == -1)
        ret = qemuDomainGetTotalcpuStats(group, params, nparams);
    else
14405
        ret = qemuDomainGetPercpuStats(vm, group, params, nparams,
14406 14407 14408 14409
                                       start_cpu, ncpus);
cleanup:
    virCgroupFree(&group);
    if (vm)
14410
        virObjectUnlock(vm);
14411 14412 14413 14414
    qemuDriverUnlock(driver);
    return ret;
}

14415 14416 14417 14418 14419 14420
static int
qemuDomainPMSuspendForDuration(virDomainPtr dom,
                               unsigned int target,
                               unsigned long long duration,
                               unsigned int flags)
{
14421
    virQEMUDriverPtr driver = dom->conn->privateData;
14422 14423 14424 14425 14426 14427 14428
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

    if (duration) {
14429 14430
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Duration not supported. Use 0 for now"));
14431 14432 14433 14434 14435 14436
        return -1;
    }

    if (!(target == VIR_NODE_SUSPEND_TARGET_MEM ||
          target == VIR_NODE_SUSPEND_TARGET_DISK ||
          target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
14437 14438 14439
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unknown suspend target: %u"),
                       target);
14440 14441 14442
        return -1;
    }

14443
    if (!(vm = qemuDomObjFromDomain(dom)))
14444 14445 14446 14447
        goto cleanup;

    priv = vm->privateData;

14448
    if (!virDomainObjIsActive(vm)) {
14449 14450
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
14451 14452 14453
        goto cleanup;
    }

14454
    if (!qemuCapsGet(priv->caps, QEMU_CAPS_WAKEUP) &&
14455 14456
        (target == VIR_NODE_SUSPEND_TARGET_MEM ||
         target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
14457 14458 14459
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Unable to suspend domain due to "
                         "missing system_wakeup monitor command"));
O
Osier Yang 已提交
14460
        goto cleanup;
14461 14462
    }

14463 14464 14465 14466 14467 14468 14469 14470 14471 14472 14473 14474 14475 14476 14477 14478 14479
    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;
        }
    }

14480
    if (priv->agentError) {
14481 14482 14483
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                       _("QEMU guest agent is not "
                         "available due to an error"));
14484 14485 14486 14487
        goto cleanup;
    }

    if (!priv->agent) {
14488 14489
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("QEMU guest agent is not configured"));
14490 14491 14492 14493 14494 14495 14496
        goto cleanup;
    }

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

    if (!virDomainObjIsActive(vm)) {
14497 14498
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
14499 14500 14501 14502 14503 14504 14505 14506 14507 14508 14509 14510 14511
        goto endjob;
    }

    qemuDomainObjEnterAgent(driver, vm);
    ret = qemuAgentSuspend(priv->agent, target);
    qemuDomainObjExitAgent(driver, vm);

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

cleanup:
    if (vm)
14512
        virObjectUnlock(vm);
14513 14514 14515
    return ret;
}

14516 14517 14518 14519
static int
qemuDomainPMWakeup(virDomainPtr dom,
                   unsigned int flags)
{
14520
    virQEMUDriverPtr driver = dom->conn->privateData;
14521 14522 14523 14524 14525 14526
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

14527
    if (!(vm = qemuDomObjFromDomain(dom)))
14528 14529 14530 14531 14532 14533
        goto cleanup;

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

    if (!virDomainObjIsActive(vm)) {
14534 14535
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
14536 14537 14538 14539 14540
        goto endjob;
    }

    priv = vm->privateData;

14541
    if (!qemuCapsGet(priv->caps, QEMU_CAPS_WAKEUP)) {
14542 14543 14544
       virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                      _("Unable to wake up domain due to "
                        "missing system_wakeup monitor command"));
14545 14546 14547 14548 14549 14550 14551 14552 14553 14554 14555 14556 14557
       goto endjob;
    }

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

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

cleanup:
    if (vm)
14558
        virObjectUnlock(vm);
14559 14560 14561
    return ret;
}

14562 14563 14564 14565 14566
static int
qemuListAllDomains(virConnectPtr conn,
                   virDomainPtr **domains,
                   unsigned int flags)
{
14567
    virQEMUDriverPtr driver = conn->privateData;
14568 14569
    int ret = -1;

O
Osier Yang 已提交
14570
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
14571 14572 14573 14574 14575 14576 14577 14578

    qemuDriverLock(driver);
    ret = virDomainList(conn, driver->domains.objs, domains, flags);
    qemuDriverUnlock(driver);

    return ret;
}

M
MATSUDA Daiki 已提交
14579
static char *
14580
qemuDomainAgentCommand(virDomainPtr domain,
M
MATSUDA Daiki 已提交
14581 14582 14583 14584
                       const char *cmd,
                       int timeout,
                       unsigned int flags)
{
14585
    virQEMUDriverPtr driver = domain->conn->privateData;
M
MATSUDA Daiki 已提交
14586 14587 14588 14589 14590 14591 14592
    virDomainObjPtr vm;
    int ret = -1;
    char *result = NULL;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, NULL);

14593
    if (!(vm = qemuDomObjFromDomain(domain)))
M
MATSUDA Daiki 已提交
14594 14595 14596 14597 14598 14599 14600 14601 14602 14603 14604
        goto cleanup;

    priv = vm->privateData;

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

    if (priv->agentError) {
14605 14606 14607
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                       _("QEMU guest agent is not "
                         "available due to an error"));
M
MATSUDA Daiki 已提交
14608 14609 14610 14611 14612 14613 14614 14615 14616 14617 14618 14619 14620 14621 14622 14623 14624 14625 14626 14627 14628 14629 14630 14631 14632 14633 14634 14635 14636 14637 14638 14639 14640 14641
        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)
14642
        virObjectUnlock(vm);
M
MATSUDA Daiki 已提交
14643 14644 14645
    return result;
}

M
Michal Privoznik 已提交
14646 14647 14648 14649 14650 14651
static int
qemuDomainFSTrim(virDomainPtr dom,
                 const char *mountPoint,
                 unsigned long long minimum,
                 unsigned int flags)
{
14652
    virQEMUDriverPtr driver = dom->conn->privateData;
M
Michal Privoznik 已提交
14653 14654 14655 14656 14657 14658 14659 14660 14661 14662 14663 14664 14665 14666 14667 14668 14669 14670 14671 14672 14673 14674 14675 14676 14677 14678 14679 14680 14681 14682 14683 14684 14685 14686 14687 14688 14689 14690 14691 14692 14693 14694 14695 14696 14697 14698 14699 14700 14701 14702 14703 14704 14705 14706 14707 14708
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

    if (mountPoint) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Specifying mount point "
                         "is not supported for now"));
        return -1;
    }

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

    priv = vm->privateData;

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

    if (!priv->agent) {
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("QEMU guest agent is not configured"));
        goto cleanup;
    }

    if (priv->agentError) {
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                       _("QEMU guest agent is not "
                         "available due to an error"));
        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 = qemuAgentFSTrim(priv->agent, minimum);
    qemuDomainObjExitAgent(driver, vm);

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

cleanup:
    if (vm)
14709
        virObjectUnlock(vm);
M
Michal Privoznik 已提交
14710 14711 14712
    return ret;
}

14713
static virDriver qemuDriver = {
14714
    .no = VIR_DRV_QEMU,
14715
    .name = QEMU_DRIVER_NAME,
14716 14717 14718 14719 14720
    .open = qemuOpen, /* 0.2.0 */
    .close = qemuClose, /* 0.2.0 */
    .supports_feature = qemuSupportsFeature, /* 0.5.0 */
    .type = qemuGetType, /* 0.2.0 */
    .version = qemuGetVersion, /* 0.2.0 */
14721 14722
    .getHostname = virGetHostname, /* 0.3.3 */
    .getSysinfo = qemuGetSysinfo, /* 0.8.8 */
14723
    .getMaxVcpus = qemuGetMaxVCPUs, /* 0.2.1 */
14724
    .nodeGetInfo = nodeGetInfo, /* 0.2.0 */
14725 14726 14727
    .getCapabilities = qemuGetCapabilities, /* 0.2.1 */
    .listDomains = qemuListDomains, /* 0.2.0 */
    .numOfDomains = qemuNumDomains, /* 0.2.0 */
14728
    .listAllDomains = qemuListAllDomains, /* 0.9.13 */
14729 14730 14731 14732 14733 14734
    .domainCreateXML = qemuDomainCreate, /* 0.2.0 */
    .domainLookupByID = qemuDomainLookupByID, /* 0.2.0 */
    .domainLookupByUUID = qemuDomainLookupByUUID, /* 0.2.0 */
    .domainLookupByName = qemuDomainLookupByName, /* 0.2.0 */
    .domainSuspend = qemuDomainSuspend, /* 0.2.0 */
    .domainResume = qemuDomainResume, /* 0.2.0 */
14735
    .domainShutdown = qemuDomainShutdown, /* 0.2.0 */
14736
    .domainShutdownFlags = qemuDomainShutdownFlags, /* 0.9.10 */
14737
    .domainReboot = qemuDomainReboot, /* 0.9.3 */
14738
    .domainReset = qemuDomainReset, /* 0.9.7 */
14739 14740
    .domainDestroy = qemuDomainDestroy, /* 0.2.0 */
    .domainDestroyFlags = qemuDomainDestroyFlags, /* 0.9.4 */
14741
    .domainGetOSType = qemuDomainGetOSType, /* 0.2.2 */
14742
    .domainGetMaxMemory = qemuDomainGetMaxMemory, /* 0.4.2 */
14743 14744 14745
    .domainSetMaxMemory = qemuDomainSetMaxMemory, /* 0.4.2 */
    .domainSetMemory = qemuDomainSetMemory, /* 0.4.2 */
    .domainSetMemoryFlags = qemuDomainSetMemoryFlags, /* 0.9.0 */
14746 14747 14748 14749
    .domainSetMemoryParameters = qemuDomainSetMemoryParameters, /* 0.8.5 */
    .domainGetMemoryParameters = qemuDomainGetMemoryParameters, /* 0.8.5 */
    .domainSetBlkioParameters = qemuDomainSetBlkioParameters, /* 0.9.0 */
    .domainGetBlkioParameters = qemuDomainGetBlkioParameters, /* 0.9.0 */
14750
    .domainGetInfo = qemuDomainGetInfo, /* 0.2.0 */
14751
    .domainGetState = qemuDomainGetState, /* 0.9.2 */
14752
    .domainGetControlInfo = qemuDomainGetControlInfo, /* 0.9.3 */
14753 14754
    .domainSave = qemuDomainSave, /* 0.2.0 */
    .domainSaveFlags = qemuDomainSaveFlags, /* 0.9.4 */
14755
    .domainRestore = qemuDomainRestore, /* 0.2.0 */
14756
    .domainRestoreFlags = qemuDomainRestoreFlags, /* 0.9.4 */
14757 14758
    .domainSaveImageGetXMLDesc = qemuDomainSaveImageGetXMLDesc, /* 0.9.4 */
    .domainSaveImageDefineXML = qemuDomainSaveImageDefineXML, /* 0.9.4 */
14759
    .domainCoreDump = qemuDomainCoreDump, /* 0.7.0 */
14760
    .domainScreenshot = qemuDomainScreenshot, /* 0.9.2 */
14761 14762
    .domainSetVcpus = qemuDomainSetVcpus, /* 0.4.4 */
    .domainSetVcpusFlags = qemuDomainSetVcpusFlags, /* 0.8.5 */
14763 14764 14765 14766 14767 14768 14769 14770 14771
    .domainGetVcpusFlags = qemuDomainGetVcpusFlags, /* 0.8.5 */
    .domainPinVcpu = qemuDomainPinVcpu, /* 0.4.4 */
    .domainPinVcpuFlags = qemuDomainPinVcpuFlags, /* 0.9.3 */
    .domainGetVcpuPinInfo = qemuDomainGetVcpuPinInfo, /* 0.9.3 */
    .domainPinEmulator = qemuDomainPinEmulator, /* 0.10.0 */
    .domainGetEmulatorPinInfo = qemuDomainGetEmulatorPinInfo, /* 0.10.0 */
    .domainGetVcpus = qemuDomainGetVcpus, /* 0.4.4 */
    .domainGetMaxVcpus = qemuDomainGetMaxVcpus, /* 0.4.4 */
    .domainGetSecurityLabel = qemuDomainGetSecurityLabel, /* 0.6.1 */
M
Marcelo Cerri 已提交
14772
    .domainGetSecurityLabelList = qemuDomainGetSecurityLabelList, /* 0.10.0 */
14773
    .nodeGetSecurityModel = qemuNodeGetSecurityModel, /* 0.6.1 */
14774 14775 14776
    .domainGetXMLDesc = qemuDomainGetXMLDesc, /* 0.2.0 */
    .domainXMLFromNative = qemuDomainXMLFromNative, /* 0.6.4 */
    .domainXMLToNative = qemuDomainXMLToNative, /* 0.6.4 */
14777 14778
    .listDefinedDomains = qemuListDefinedDomains, /* 0.2.0 */
    .numOfDefinedDomains = qemuNumDefinedDomains, /* 0.2.0 */
14779 14780
    .domainCreate = qemuDomainStart, /* 0.2.0 */
    .domainCreateWithFlags = qemuDomainStartWithFlags, /* 0.8.2 */
14781 14782
    .domainDefineXML = qemuDomainDefine, /* 0.2.0 */
    .domainUndefine = qemuDomainUndefine, /* 0.2.0 */
14783
    .domainUndefineFlags = qemuDomainUndefineFlags, /* 0.9.4 */
14784 14785 14786 14787 14788
    .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 */
14789 14790
    .domainGetAutostart = qemuDomainGetAutostart, /* 0.2.1 */
    .domainSetAutostart = qemuDomainSetAutostart, /* 0.2.1 */
14791 14792
    .domainGetSchedulerType = qemuGetSchedulerType, /* 0.7.0 */
    .domainGetSchedulerParameters = qemuGetSchedulerParameters, /* 0.7.0 */
14793
    .domainGetSchedulerParametersFlags = qemuGetSchedulerParametersFlags, /* 0.9.2 */
14794
    .domainSetSchedulerParameters = qemuSetSchedulerParameters, /* 0.7.0 */
14795
    .domainSetSchedulerParametersFlags = qemuSetSchedulerParametersFlags, /* 0.9.2 */
14796
    .domainMigratePerform = qemuDomainMigratePerform, /* 0.5.0 */
14797
    .domainBlockResize = qemuDomainBlockResize, /* 0.9.8 */
14798 14799
    .domainBlockStats = qemuDomainBlockStats, /* 0.4.1 */
    .domainBlockStatsFlags = qemuDomainBlockStatsFlags, /* 0.9.5 */
14800 14801 14802 14803
    .domainInterfaceStats = qemuDomainInterfaceStats, /* 0.4.1 */
    .domainMemoryStats = qemuDomainMemoryStats, /* 0.7.5 */
    .domainBlockPeek = qemuDomainBlockPeek, /* 0.4.4 */
    .domainMemoryPeek = qemuDomainMemoryPeek, /* 0.4.4 */
14804
    .domainGetBlockInfo = qemuDomainGetBlockInfo, /* 0.8.1 */
14805
    .nodeGetCPUStats = nodeGetCPUStats, /* 0.9.3 */
14806
    .nodeGetMemoryStats = nodeGetMemoryStats, /* 0.9.3 */
14807 14808 14809 14810
    .nodeGetCellsFreeMemory = nodeGetCellsFreeMemory, /* 0.4.4 */
    .nodeGetFreeMemory = nodeGetFreeMemory, /* 0.4.4 */
    .domainEventRegister = qemuDomainEventRegister, /* 0.5.0 */
    .domainEventDeregister = qemuDomainEventDeregister, /* 0.5.0 */
14811 14812 14813 14814 14815 14816
    .domainMigratePrepare2 = qemuDomainMigratePrepare2, /* 0.5.0 */
    .domainMigrateFinish2 = qemuDomainMigrateFinish2, /* 0.5.0 */
    .nodeDeviceDettach = qemuNodeDeviceDettach, /* 0.6.1 */
    .nodeDeviceReAttach = qemuNodeDeviceReAttach, /* 0.6.1 */
    .nodeDeviceReset = qemuNodeDeviceReset, /* 0.6.1 */
    .domainMigratePrepareTunnel = qemuDomainMigratePrepareTunnel, /* 0.7.2 */
14817 14818 14819 14820 14821 14822 14823 14824 14825 14826 14827
    .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 */
14828
    .domainMigrateGetMaxSpeed = qemuDomainMigrateGetMaxSpeed, /* 0.9.5 */
14829 14830 14831 14832 14833 14834 14835 14836 14837
    .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 */
14838
    .domainListAllSnapshots = qemuDomainListAllSnapshots, /* 0.9.13 */
14839 14840
    .domainSnapshotNumChildren = qemuDomainSnapshotNumChildren, /* 0.9.7 */
    .domainSnapshotListChildrenNames = qemuDomainSnapshotListChildrenNames, /* 0.9.7 */
14841
    .domainSnapshotListAllChildren = qemuDomainSnapshotListAllChildren, /* 0.9.13 */
14842 14843
    .domainSnapshotLookupByName = qemuDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = qemuDomainHasCurrentSnapshot, /* 0.8.0 */
14844
    .domainSnapshotGetParent = qemuDomainSnapshotGetParent, /* 0.9.7 */
14845
    .domainSnapshotCurrent = qemuDomainSnapshotCurrent, /* 0.8.0 */
14846 14847
    .domainSnapshotIsCurrent = qemuDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = qemuDomainSnapshotHasMetadata, /* 0.9.13 */
14848 14849 14850
    .domainRevertToSnapshot = qemuDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = qemuDomainSnapshotDelete, /* 0.8.0 */
    .qemuDomainMonitorCommand = qemuDomainMonitorCommand, /* 0.8.3 */
14851
    .qemuDomainAttach = qemuDomainAttach, /* 0.9.4 */
14852
    .qemuDomainArbitraryAgentCommand = qemuDomainAgentCommand, /* 0.10.0 */
14853
    .domainOpenConsole = qemuDomainOpenConsole, /* 0.8.6 */
14854
    .domainOpenGraphics = qemuDomainOpenGraphics, /* 0.9.7 */
14855
    .domainInjectNMI = qemuDomainInjectNMI, /* 0.9.2 */
14856 14857 14858 14859 14860 14861
    .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 */
14862
    .domainSendKey = qemuDomainSendKey, /* 0.9.4 */
14863 14864 14865 14866
    .domainBlockJobAbort = qemuDomainBlockJobAbort, /* 0.9.4 */
    .domainGetBlockJobInfo = qemuDomainGetBlockJobInfo, /* 0.9.4 */
    .domainBlockJobSetSpeed = qemuDomainBlockJobSetSpeed, /* 0.9.4 */
    .domainBlockPull = qemuDomainBlockPull, /* 0.9.4 */
14867
    .domainBlockRebase = qemuDomainBlockRebase, /* 0.9.10 */
14868
    .domainBlockCommit = qemuDomainBlockCommit, /* 1.0.0 */
14869
    .isAlive = qemuIsAlive, /* 0.9.8 */
14870
    .nodeSuspendForDuration = nodeSuspendForDuration, /* 0.9.8 */
14871 14872
    .domainSetBlockIoTune = qemuDomainSetBlockIoTune, /* 0.9.8 */
    .domainGetBlockIoTune = qemuDomainGetBlockIoTune, /* 0.9.8 */
14873 14874
    .domainSetNumaParameters = qemuDomainSetNumaParameters, /* 0.9.9 */
    .domainGetNumaParameters = qemuDomainGetNumaParameters, /* 0.9.9 */
14875 14876
    .domainGetInterfaceParameters = qemuDomainGetInterfaceParameters, /* 0.9.9 */
    .domainSetInterfaceParameters = qemuDomainSetInterfaceParameters, /* 0.9.9 */
14877
    .domainGetDiskErrors = qemuDomainGetDiskErrors, /* 0.9.10 */
14878 14879
    .domainSetMetadata = qemuDomainSetMetadata, /* 0.9.10 */
    .domainGetMetadata = qemuDomainGetMetadata, /* 0.9.10 */
14880
    .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */
14881
    .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */
14882
    .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */
14883 14884
    .nodeGetMemoryParameters = nodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = nodeSetMemoryParameters, /* 0.10.2 */
14885
    .nodeGetCPUMap = nodeGetCPUMap, /* 1.0.0 */
M
Michal Privoznik 已提交
14886
    .domainFSTrim = qemuDomainFSTrim, /* 1.0.1 */
14887
    .domainOpenChannel = qemuDomainOpenChannel, /* 1.0.2 */
14888 14889 14890
};


14891
static virStateDriver qemuStateDriver = {
14892
    .name = "QEMU",
14893 14894 14895
    .initialize = qemuStartup,
    .cleanup = qemuShutdown,
    .reload = qemuReload,
14896
    .stop = qemuStop,
14897
};
14898

14899
int qemuRegister(void) {
14900 14901 14902 14903
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
    return 0;
}