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

46

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

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

99 100
#define VIR_FROM_THIS VIR_FROM_QEMU

101 102
#define QEMU_DRIVER_NAME "QEMU"

103 104
#define QEMU_NB_MEM_PARAM  3

105 106
#define QEMU_NB_BLOCK_IO_TUNE_PARAM  6

107 108
#define QEMU_NB_NUMA_PARAM 2

109
#define QEMU_NB_PER_CPU_STAT_PARAM 2
E
Eric Blake 已提交
110

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

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

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

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

134
#define QEMU_NB_BLKIO_PARAM  6
135

136 137
#define QEMU_NB_BANDWIDTH_PARAM 6

C
Chen Fan 已提交
138 139 140 141
static void processWatchdogEvent(virQEMUDriverPtr driver,
                                 virDomainObjPtr vm,
                                 int action);

142 143 144 145
static void processGuestPanicEvent(virQEMUDriverPtr driver,
                                   virDomainObjPtr vm,
                                   int action);

C
Chen Fan 已提交
146
static void qemuProcessEventHandler(void *data, void *opaque);
H
Hu Tao 已提交
147

148
static int qemuStateCleanup(void);
149

150
static int qemuDomainObjStart(virConnectPtr conn,
151
                              virQEMUDriverPtr driver,
152
                              virDomainObjPtr vm,
153
                              unsigned int flags);
J
Jiri Denemark 已提交
154

155
static int qemuDomainGetMaxVcpus(virDomainPtr dom);
156

157 158
static int qemuDomainManagedSaveLoad(virDomainObjPtr vm,
                                     void *opaque);
159

160 161 162 163 164 165 166 167 168 169
static int qemuOpenFile(virQEMUDriverPtr driver,
                        virDomainObjPtr vm,
                        const char *path, int oflags,
                        bool *needUnlink, bool *bypassSecurityDriver);

static int qemuOpenFileAs(uid_t fallback_uid, gid_t fallback_gid,
                          bool dynamicOwnership,
                          const char *path, int oflags,
                          bool *needUnlink, bool *bypassSecurityDriver);

170

171
virQEMUDriverPtr qemu_driver = NULL;
172 173


174
static void
175
qemuVMDriverLock(void) {}
176
static void
177
qemuVMDriverUnlock(void) {}
178 179

static int
180
qemuVMFilterRebuild(virDomainObjListIterator iter, void *data)
181
{
182
    return virDomainObjListForEach(qemu_driver->domains, iter, data);
183 184 185 186 187 188 189 190 191 192
}

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


193
struct qemuAutostartData {
194
    virQEMUDriverPtr driver;
195 196
    virConnectPtr conn;
};
197

198

199
/**
200
 * qemuDomObjFromDomain:
201 202
 * @domain: Domain pointer that has to be looked up
 *
203 204
 * This function looks up @domain and returns the appropriate
 * virDomainObjPtr.
205
 *
206 207
 * Returns the domain object which is locked on success, NULL
 * otherwise.
208
 */
209
static virDomainObjPtr
210
qemuDomObjFromDomain(virDomainPtr domain)
211 212
{
    virDomainObjPtr vm;
213
    virQEMUDriverPtr driver = domain->conn->privateData;
214 215
    char uuidstr[VIR_UUID_STRING_BUFLEN];

216
    vm = virDomainObjListFindByUUID(driver->domains, domain->uuid);
217 218 219
    if (!vm) {
        virUUIDFormat(domain->uuid, uuidstr);
        virReportError(VIR_ERR_NO_DOMAIN,
220 221
                       _("no domain with matching uuid '%s' (%s)"),
                       uuidstr, domain->name);
222
        return NULL;
223 224
    }

225 226
    return vm;
}
227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261

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

262 263
static int
qemuAutostartDomain(virDomainObjPtr vm,
264
                    void *opaque)
265 266
{
    struct qemuAutostartData *data = opaque;
267
    virErrorPtr err;
268
    int flags = 0;
269
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(data->driver);
270
    int ret = -1;
271

272
    if (cfg->autoStartBypassCache)
273
        flags |= VIR_DOMAIN_START_BYPASS_CACHE;
274

275
    virObjectLock(vm);
276
    virResetLastError();
277 278
    if (vm->autostart &&
        !virDomainObjIsActive(vm)) {
279 280
        if (qemuDomainObjBeginJob(data->driver, vm,
                                  QEMU_JOB_MODIFY) < 0) {
281 282 283 284 285 286 287 288
            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) {
289
            err = virGetLastError();
290
            VIR_ERROR(_("Failed to autostart VM '%s': %s"),
291
                      vm->def->name,
292
                      err ? err->message : _("unknown error"));
293
        }
294

E
Eric Blake 已提交
295
        if (!qemuDomainObjEndJob(data->driver, vm))
296
            vm = NULL;
297
    }
298

299
    ret = 0;
300
cleanup:
301
    if (vm)
302
        virObjectUnlock(vm);
303
    virObjectUnref(cfg);
304
    return ret;
305 306
}

307

308
static void
309
qemuAutostartDomains(virQEMUDriverPtr driver)
310
{
311
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
312 313 314 315 316
    /* 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
     */
317
    virConnectPtr conn = virConnectOpen(cfg->uri);
318
    /* Ignoring NULL conn which is mostly harmless here */
319
    struct qemuAutostartData data = { driver, conn };
320

321
    virDomainObjListForEach(driver->domains, qemuAutostartDomain, &data);
322

323
    virObjectUnref(conn);
324
    virObjectUnref(cfg);
325 326
}

327
static int
328
qemuSecurityInit(virQEMUDriverPtr driver)
329
{
330
    char **names;
331 332
    virSecurityManagerPtr mgr = NULL;
    virSecurityManagerPtr stack = NULL;
333
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
334

335 336 337
    if (cfg->securityDriverNames &&
        cfg->securityDriverNames[0]) {
        names = cfg->securityDriverNames;
338
        while (names && *names) {
339 340
            if (!(mgr = virSecurityManagerNew(*names,
                                              QEMU_DRIVER_NAME,
341 342 343
                                              cfg->allowDiskFormatProbing,
                                              cfg->securityDefaultConfined,
                                              cfg->securityRequireConfined)))
344
                goto error;
345 346 347 348 349 350 351 352
            if (!stack) {
                if (!(stack = virSecurityManagerNewStack(mgr)))
                    goto error;
            } else {
                if (virSecurityManagerStackAddNested(stack, mgr) < 0)
                    goto error;
            }
            mgr = NULL;
353 354
            names++;
        }
355 356 357
    } else {
        if (!(mgr = virSecurityManagerNew(NULL,
                                          QEMU_DRIVER_NAME,
358 359 360
                                          cfg->allowDiskFormatProbing,
                                          cfg->securityDefaultConfined,
                                          cfg->securityRequireConfined)))
361
            goto error;
362
        if (!(stack = virSecurityManagerNewStack(mgr)))
363
            goto error;
364 365
        mgr = NULL;
    }
366

367
    if (cfg->privileged) {
368
        if (!(mgr = virSecurityManagerNewDAC(QEMU_DRIVER_NAME,
369 370 371 372 373 374
                                             cfg->user,
                                             cfg->group,
                                             cfg->allowDiskFormatProbing,
                                             cfg->securityDefaultConfined,
                                             cfg->securityRequireConfined,
                                             cfg->dynamicOwnership)))
375 376 377 378 379 380 381 382 383
            goto error;
        if (!stack) {
            if (!(stack = virSecurityManagerNewStack(mgr)))
                goto error;
        } else {
            if (virSecurityManagerStackAddNested(stack, mgr) < 0)
                goto error;
        }
        mgr = NULL;
384
    }
D
Daniel Veillard 已提交
385

386
    driver->securityManager = stack;
387
    virObjectUnref(cfg);
388
    return 0;
389

390
error:
391
    VIR_ERROR(_("Failed to initialize security drivers"));
392 393
    virObjectUnref(stack);
    virObjectUnref(mgr);
394
    virObjectUnref(cfg);
395 396
    return -1;
}
397

398

399 400
static int
qemuDomainSnapshotLoad(virDomainObjPtr vm,
401
                       void *data)
402
{
403 404 405 406 407 408 409
    char *baseDir = (char *)data;
    char *snapDir = NULL;
    DIR *dir = NULL;
    struct dirent *entry;
    char *xmlStr;
    char *fullpath;
    virDomainSnapshotDefPtr def = NULL;
410
    virDomainSnapshotObjPtr snap = NULL;
411
    virDomainSnapshotObjPtr current = NULL;
412
    char ebuf[1024];
413
    unsigned int flags = (VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE |
414
                          VIR_DOMAIN_SNAPSHOT_PARSE_DISKS |
415
                          VIR_DOMAIN_SNAPSHOT_PARSE_INTERNAL);
416
    int ret = -1;
417
    virCapsPtr caps = NULL;
418

419
    virObjectLock(vm);
420 421 422
    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);
423
        goto cleanup;
424 425
    }

426 427 428
    if (!(caps = virQEMUDriverGetCapabilities(qemu_driver, false)))
        goto cleanup;

429 430
    VIR_INFO("Scanning for snapshots for domain %s in %s", vm->def->name,
             snapDir);
431

432 433 434 435 436
    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)));
437
        goto cleanup;
438 439
    }

440 441 442
    while ((entry = readdir(dir))) {
        if (entry->d_name[0] == '.')
            continue;
443

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

448
        if (virAsprintf(&fullpath, "%s/%s", snapDir, entry->d_name) < 0) {
449
            VIR_ERROR(_("Failed to allocate memory for path"));
450 451
            continue;
        }
452

453
        if (virFileReadAll(fullpath, 1024*1024*1, &xmlStr) < 0) {
454 455 456 457 458 459
            /* 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;
        }
460

461
        def = virDomainSnapshotDefParseString(xmlStr, caps,
462
                                              qemu_driver->xmlopt,
463 464
                                              QEMU_EXPECTED_VIRT_TYPES,
                                              flags);
465 466
        if (def == NULL) {
            /* Nothing we can do here, skip this one */
467 468
            VIR_ERROR(_("Failed to parse snapshot XML from file '%s'"),
                      fullpath);
469 470 471 472
            VIR_FREE(fullpath);
            VIR_FREE(xmlStr);
            continue;
        }
473

474
        snap = virDomainSnapshotAssignDef(vm->snapshots, def);
475 476
        if (snap == NULL) {
            virDomainSnapshotDefFree(def);
477 478 479 480
        } else if (snap->def->current) {
            current = snap;
            if (!vm->current_snapshot)
                vm->current_snapshot = snap;
481
        }
482

483 484
        VIR_FREE(fullpath);
        VIR_FREE(xmlStr);
485 486
    }

487 488 489 490 491 492
    if (vm->current_snapshot != current) {
        VIR_ERROR(_("Too many snapshots claiming to be current for domain %s"),
                  vm->def->name);
        vm->current_snapshot = NULL;
    }

493
    if (virDomainSnapshotUpdateRelations(vm->snapshots) < 0)
494 495 496
        VIR_ERROR(_("Snapshots have inconsistent relations for domain %s"),
                  vm->def->name);

497 498 499 500 501 502 503 504
    /* 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.
     */
505

506
    virResetLastError();
507

508
    ret = 0;
509 510 511 512
cleanup:
    if (dir)
        closedir(dir);
    VIR_FREE(snapDir);
513
    virObjectUnref(caps);
514
    virObjectUnlock(vm);
515
    return ret;
516 517
}

518

519 520
static int
qemuDomainNetsRestart(virDomainObjPtr vm,
521
                      void *data ATTRIBUTE_UNUSED)
522
{
523
    size_t i;
524 525
    virDomainDefPtr def = vm->def;

526
    virObjectLock(vm);
527 528 529 530 531 532 533 534

    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,
535
                                                                 &net->mac,
536 537 538 539 540 541 542
                                                                 virDomainNetGetActualDirectDev(net),
                                                                 def->uuid,
                                                                 virDomainNetGetActualVirtPortProfile(net),
                                                                 VIR_NETDEV_VPORT_PROFILE_OP_CREATE));
        }
    }

543
    virObjectUnlock(vm);
544
    return 0;
545 546
}

547

548 549
static int
qemuDomainFindMaxID(virDomainObjPtr vm,
550 551 552 553 554 555
                    void *data)
{
    int *driver_maxid = data;

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

    return 0;
558 559 560
}


561
/**
562
 * qemuStateInitialize:
563 564 565
 *
 * Initialization function for the QEmu daemon
 */
566
static int
567 568 569
qemuStateInitialize(bool privileged,
                    virStateInhibitCallback callback,
                    void *opaque)
570
{
571 572
    char *driverConf = NULL;
    virConnectPtr conn = NULL;
573
    char ebuf[1024];
574 575
    char *membase = NULL;
    char *mempath = NULL;
576
    virQEMUDriverConfigPtr cfg;
577 578
    uid_t run_uid = -1;
    gid_t run_gid = -1;
579

580 581
    if (VIR_ALLOC(qemu_driver) < 0)
        return -1;
582

583
    if (virMutexInit(&qemu_driver->lock) < 0) {
584
        VIR_ERROR(_("cannot initialize mutex"));
585 586
        VIR_FREE(qemu_driver);
        return -1;
587
    }
588

589 590
    qemu_driver->inhibitCallback = callback;
    qemu_driver->inhibitOpaque = opaque;
591

592 593
    /* Don't have a dom0 so start from 1 */
    qemu_driver->nextvmid = 1;
594

595 596
    if (!(qemu_driver->domains = virDomainObjListNew()))
        goto error;
597

598
    /* Init domain events */
599
    qemu_driver->domainEventState = virObjectEventStateNew();
600
    if (!qemu_driver->domainEventState)
601
        goto error;
602

603 604 605
    /* read the host sysinfo */
    if (privileged)
        qemu_driver->hostsysinfo = virSysinfoRead();
606

607 608
    if (!(qemu_driver->config = cfg = virQEMUDriverConfigNew(privileged)))
        goto error;
609

610
    if (virAsprintf(&driverConf, "%s/qemu.conf", cfg->configBaseDir) < 0)
611
        goto error;
612

613 614 615
    if (virQEMUDriverConfigLoadFile(cfg, driverConf) < 0)
        goto error;
    VIR_FREE(driverConf);
H
Hu Tao 已提交
616

617
    if (virFileMakePath(cfg->stateDir) < 0) {
618
        VIR_ERROR(_("Failed to create state dir '%s': %s"),
619
                  cfg->stateDir, virStrerror(errno, ebuf, sizeof(ebuf)));
620
        goto error;
H
Hu Tao 已提交
621
    }
622
    if (virFileMakePath(cfg->libDir) < 0) {
623
        VIR_ERROR(_("Failed to create lib dir '%s': %s"),
624
                  cfg->libDir, virStrerror(errno, ebuf, sizeof(ebuf)));
625 626
        goto error;
    }
627
    if (virFileMakePath(cfg->cacheDir) < 0) {
628
        VIR_ERROR(_("Failed to create cache dir '%s': %s"),
629
                  cfg->cacheDir, virStrerror(errno, ebuf, sizeof(ebuf)));
630 631
        goto error;
    }
632
    if (virFileMakePath(cfg->saveDir) < 0) {
633
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
634
                  cfg->saveDir, virStrerror(errno, ebuf, sizeof(ebuf)));
635 636
        goto error;
    }
637
    if (virFileMakePath(cfg->snapshotDir) < 0) {
638
        VIR_ERROR(_("Failed to create save dir '%s': %s"),
639
                  cfg->snapshotDir, virStrerror(errno, ebuf, sizeof(ebuf)));
640 641
        goto error;
    }
642
    if (virFileMakePath(cfg->autoDumpPath) < 0) {
643
        VIR_ERROR(_("Failed to create dump dir '%s': %s"),
644
                  cfg->autoDumpPath, virStrerror(errno, ebuf, sizeof(ebuf)));
645
        goto error;
646 647
    }

648 649 650
    qemu_driver->qemuImgBinary = virFindFileInPath("kvm-img");
    if (!qemu_driver->qemuImgBinary)
        qemu_driver->qemuImgBinary = virFindFileInPath("qemu-img");
651 652 653 654 655 656 657

    if (!(qemu_driver->lockManager =
          virLockManagerPluginNew(cfg->lockManagerName ?
                                  cfg->lockManagerName : "nop",
                                  "qemu",
                                  cfg->configBaseDir,
                                  0)))
658
        goto error;
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674

   if (cfg->macFilter) {
        if (!(qemu_driver->ebtables = ebtablesContextNew("qemu"))) {
            virReportSystemError(errno,
                                 _("failed to enable mac filter in '%s'"),
                                 __FILE__);
            goto error;
        }

        if ((errno = networkDisableAllFrames(qemu_driver))) {
            virReportSystemError(errno,
                                 _("failed to add rule to drop all frames in '%s'"),
                                 __FILE__);
            goto error;
        }
   }
675

676 677 678
    /* Allocate bitmap for remote display port reservations. We cannot
     * do this before the config is loaded properly, since the port
     * numbers are configurable now */
679
    if ((qemu_driver->remotePorts =
J
Ján Tomko 已提交
680 681
         virPortAllocatorNew(_("display"),
                             cfg->remotePortMin,
682
                             cfg->remotePortMax)) == NULL)
683 684
        goto error;

685
    if ((qemu_driver->webSocketPorts =
J
Ján Tomko 已提交
686 687
         virPortAllocatorNew(_("webSocket"),
                             cfg->webSocketPortMin,
688 689 690
                             cfg->webSocketPortMax)) == NULL)
        goto error;

691
    if ((qemu_driver->migrationPorts =
J
Ján Tomko 已提交
692 693
         virPortAllocatorNew(_("migration"),
                             cfg->migrationPortMin,
694
                             cfg->migrationPortMax)) == NULL)
695 696
        goto error;

697 698
    if (qemuSecurityInit(qemu_driver) < 0)
        goto error;
699

700
    if ((qemu_driver->activePciHostdevs = virPCIDeviceListNew()) == NULL)
701
        goto error;
702

703
    if ((qemu_driver->activeUsbHostdevs = virUSBDeviceListNew()) == NULL)
704 705
        goto error;

706
    if ((qemu_driver->inactivePciHostdevs = virPCIDeviceListNew()) == NULL)
707 708
        goto error;

709 710 711
    if ((qemu_driver->activeScsiHostdevs = virSCSIDeviceListNew()) == NULL)
        goto error;

712
    if (!(qemu_driver->sharedDevices = virHashCreate(30, qemuSharedDeviceEntryFree)))
713 714
        goto error;

715
    if (privileged) {
716
        if (chown(cfg->libDir, cfg->user, cfg->group) < 0) {
717 718
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to user %d:%d"),
E
Eric Blake 已提交
719 720
                                 cfg->libDir, (int) cfg->user,
                                 (int) cfg->group);
721
            goto error;
722
        }
723
        if (chown(cfg->cacheDir, cfg->user, cfg->group) < 0) {
724
            virReportSystemError(errno,
725
                                 _("unable to set ownership of '%s' to %d:%d"),
E
Eric Blake 已提交
726 727
                                 cfg->cacheDir, (int) cfg->user,
                                 (int) cfg->group);
728
            goto error;
729
        }
730
        if (chown(cfg->saveDir, cfg->user, cfg->group) < 0) {
731 732
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to %d:%d"),
E
Eric Blake 已提交
733 734
                                 cfg->saveDir, (int) cfg->user,
                                 (int) cfg->group);
735 736
            goto error;
        }
737
        if (chown(cfg->snapshotDir, cfg->user, cfg->group) < 0) {
738 739
            virReportSystemError(errno,
                                 _("unable to set ownership of '%s' to %d:%d"),
E
Eric Blake 已提交
740 741
                                 cfg->snapshotDir, (int) cfg->user,
                                 (int) cfg->group);
742
            goto error;
743
        }
744 745
        run_uid = cfg->user;
        run_gid = cfg->group;
746
    }
747

748
    qemu_driver->qemuCapsCache = virQEMUCapsCacheNew(cfg->libDir,
749 750
                                                     run_uid,
                                                     run_gid);
751
    if (!qemu_driver->qemuCapsCache)
752 753
        goto error;

754
    if ((qemu_driver->caps = virQEMUDriverCreateCapabilities(qemu_driver)) == NULL)
755 756
        goto error;

757
    if (!(qemu_driver->xmlopt = virQEMUDriverCreateXMLConf(qemu_driver)))
758 759
        goto error;

760 761 762 763 764 765
    /* 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
766
     */
767 768
    if (cfg->hugetlbfsMount &&
        cfg->hugetlbfsMount[0] == '/') {
769
        if (virAsprintf(&membase, "%s/libvirt",
770
                        cfg->hugetlbfsMount) < 0 ||
771
            virAsprintf(&mempath, "%s/qemu", membase) < 0)
772
            goto error;
773

774 775
        if (virFileMakePath(mempath) < 0) {
            virReportSystemError(errno,
776 777
                                 _("unable to create hugepage path %s"), mempath);
            goto error;
778
        }
779
        if (cfg->privileged) {
780 781
            if (virFileUpdatePerm(membase, 0, S_IXGRP | S_IXOTH) < 0)
                goto error;
782
            if (chown(mempath, cfg->user, cfg->group) < 0) {
783 784
                virReportSystemError(errno,
                                     _("unable to set ownership on %s to %d:%d"),
E
Eric Blake 已提交
785 786
                                     mempath, (int) cfg->user,
                                     (int) cfg->group);
787 788
                goto error;
            }
G
Guido Günther 已提交
789
        }
S
Stefan Berger 已提交
790
        VIR_FREE(membase);
E
Eric Blake 已提交
791

792
        cfg->hugepagePath = mempath;
793
    }
794

795
    if (!(qemu_driver->closeCallbacks = virCloseCallbacksNew()))
796 797
        goto error;

798
    /* Get all the running persistent or transient configs first */
799
    if (virDomainObjListLoadAllConfigs(qemu_driver->domains,
800 801
                                       cfg->stateDir,
                                       NULL, 1,
802
                                       qemu_driver->caps,
803
                                       qemu_driver->xmlopt,
804
                                       QEMU_EXPECTED_VIRT_TYPES,
805
                                       NULL, NULL) < 0)
806
        goto error;
807

808 809 810
    /* find the maximum ID from active and transient configs to initialize
     * the driver with. This is to avoid race between autostart and reconnect
     * threads */
811 812 813
    virDomainObjListForEach(qemu_driver->domains,
                            qemuDomainFindMaxID,
                            &qemu_driver->nextvmid);
814

815 816 817
    virDomainObjListForEach(qemu_driver->domains,
                            qemuDomainNetsRestart,
                            NULL);
818

819
    conn = virConnectOpen(cfg->uri);
820

821
    /* Then inactive persistent configs */
822
    if (virDomainObjListLoadAllConfigs(qemu_driver->domains,
823 824
                                       cfg->configDir,
                                       cfg->autostartDir, 0,
825
                                       qemu_driver->caps,
826
                                       qemu_driver->xmlopt,
827
                                       QEMU_EXPECTED_VIRT_TYPES,
828
                                       NULL, NULL) < 0)
829
        goto error;
830

831
    qemuProcessReconnectAll(conn, qemu_driver);
832

833 834 835
    virDomainObjListForEach(qemu_driver->domains,
                            qemuDomainSnapshotLoad,
                            cfg->snapshotDir);
836

837 838 839
    virDomainObjListForEach(qemu_driver->domains,
                            qemuDomainManagedSaveLoad,
                            qemu_driver);
840

C
Chen Fan 已提交
841
    qemu_driver->workerPool = virThreadPoolNew(0, 1, 0, qemuProcessEventHandler, qemu_driver);
842 843
    if (!qemu_driver->workerPool)
        goto error;
844

845
    virObjectUnref(conn);
846

847
    virNWFilterRegisterCallbackDriver(&qemuCallbackDriver);
848
    return 0;
849

850
error:
851
    virObjectUnref(conn);
852
    VIR_FREE(driverConf);
853 854
    VIR_FREE(membase);
    VIR_FREE(mempath);
855
    qemuStateCleanup();
856
    return -1;
857 858
}

859 860 861 862 863 864 865 866 867 868 869 870 871 872
/**
 * qemuStateAutoStart:
 *
 * Function to auto start the QEmu daemons
 */
static void
qemuStateAutoStart(void)
{
    if (!qemu_driver)
        return;

    qemuAutostartDomains(qemu_driver);
}

873
static void qemuNotifyLoadDomain(virDomainObjPtr vm, int newVM, void *opaque)
874
{
875
    virQEMUDriverPtr driver = opaque;
876

877
    if (newVM) {
878
        virObjectEventPtr event =
879
            virDomainEventLifecycleNewFromObj(vm,
880 881 882 883
                                     VIR_DOMAIN_EVENT_DEFINED,
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED);
        if (event)
            qemuDomainEventQueue(driver, event);
E
Eric Blake 已提交
884
    }
885
}
E
Eric Blake 已提交
886

887
/**
888
 * qemuStateReload:
889 890 891 892 893
 *
 * Function to restart the QEmu daemon, it will recheck the configuration
 * files and update its state and the networking
 */
static int
894
qemuStateReload(void) {
895 896
    virQEMUDriverConfigPtr cfg = NULL;
    virCapsPtr caps = NULL;
897

898 899
    if (!qemu_driver)
        return 0;
900

901 902 903
    if (!(caps = virQEMUDriverGetCapabilities(qemu_driver, false)))
        goto cleanup;

904
    cfg = virQEMUDriverGetConfig(qemu_driver);
905 906
    virDomainObjListLoadAllConfigs(qemu_driver->domains,
                                   cfg->configDir,
907 908 909
                                   cfg->autostartDir, 0,
                                   caps, qemu_driver->xmlopt,
                                   QEMU_EXPECTED_VIRT_TYPES,
910
                                   qemuNotifyLoadDomain, qemu_driver);
911
cleanup:
912
    virObjectUnref(cfg);
913
    virObjectUnref(caps);
914 915
    return 0;
}
S
Stefan Berger 已提交
916

917 918

/*
919
 * qemuStateStop:
920 921 922 923 924
 *
 * Save any VMs in preparation for shutdown
 *
 */
static int
925
qemuStateStop(void) {
926 927
    int ret = -1;
    virConnectPtr conn;
928
    int numDomains = 0;
929 930 931 932
    size_t i;
    int state;
    virDomainPtr *domains = NULL;
    unsigned int *flags = NULL;
933
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(qemu_driver);
934

935 936
    if (!(conn = virConnectOpen(cfg->uri)))
        goto cleanup;
937 938 939 940 941 942

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

943
    if (VIR_ALLOC_N(flags, numDomains) < 0)
944 945 946 947 948
        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. */
949
    for (i = 0; i < numDomains; i++) {
950 951 952 953 954 955 956 957 958 959 960
        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 */
961
    for (i = 0; i < numDomains; i++)
962 963 964 965
        if (virDomainManagedSave(domains[i], flags[i]) < 0)
            ret = -1;

 cleanup:
966
    for (i = 0; i < numDomains; i++)
967 968 969
        virDomainFree(domains[i]);
    VIR_FREE(domains);
    VIR_FREE(flags);
970
    virObjectUnref(conn);
971
    virObjectUnref(cfg);
972 973 974 975

    return ret;
}

976
/**
977
 * qemuStateCleanup:
978 979 980 981
 *
 * Shutdown the QEmu daemon, it will stop all active domains and networks
 */
static int
982
qemuStateCleanup(void) {
983 984
    if (!qemu_driver)
        return -1;
985

986
    virNWFilterUnRegisterCallbackDriver(&qemuCallbackDriver);
987
    virObjectUnref(qemu_driver->config);
988 989 990
    virObjectUnref(qemu_driver->activePciHostdevs);
    virObjectUnref(qemu_driver->inactivePciHostdevs);
    virObjectUnref(qemu_driver->activeUsbHostdevs);
991
    virObjectUnref(qemu_driver->activeScsiHostdevs);
992
    virHashFree(qemu_driver->sharedDevices);
993
    virObjectUnref(qemu_driver->caps);
994
    virQEMUCapsCacheFree(qemu_driver->qemuCapsCache);
995

996
    virObjectUnref(qemu_driver->domains);
997
    virObjectUnref(qemu_driver->remotePorts);
998
    virObjectUnref(qemu_driver->webSocketPorts);
999
    virObjectUnref(qemu_driver->migrationPorts);
1000

1001
    virObjectUnref(qemu_driver->xmlopt);
1002

1003
    virSysinfoDefFree(qemu_driver->hostsysinfo);
1004

1005
    virObjectUnref(qemu_driver->closeCallbacks);
1006

E
Eric Blake 已提交
1007
    VIR_FREE(qemu_driver->qemuImgBinary);
1008

1009
    virObjectUnref(qemu_driver->securityManager);
1010

1011
    ebtablesContextFree(qemu_driver->ebtables);
1012

1013
    /* Free domain callback list */
1014
    virObjectEventStateFree(qemu_driver->domainEventState);
D
Daniel P. Berrange 已提交
1015

1016 1017
    virLockManagerPluginUnref(qemu_driver->lockManager);

1018 1019 1020
    virMutexDestroy(&qemu_driver->lock);
    virThreadPoolFree(qemu_driver->workerPool);
    VIR_FREE(qemu_driver);
1021

1022
    return 0;
1023 1024
}

1025

1026 1027 1028
static virDrvOpenStatus qemuConnectOpen(virConnectPtr conn,
                                        virConnectAuthPtr auth ATTRIBUTE_UNUSED,
                                        unsigned int flags)
1029
{
1030 1031
    virQEMUDriverConfigPtr cfg = NULL;
    virDrvOpenStatus ret = VIR_DRV_OPEN_ERROR;
E
Eric Blake 已提交
1032 1033
    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);

1034
    if (conn->uri == NULL) {
1035 1036 1037 1038 1039 1040
        if (qemu_driver == NULL) {
            ret = VIR_DRV_OPEN_DECLINED;
            goto cleanup;
        }

        cfg = virQEMUDriverGetConfig(qemu_driver);
1041

1042 1043
        if (!(conn->uri = virURIParse(cfg->uri)))
            goto cleanup;
1044 1045 1046
    } else {
        /* If URI isn't 'qemu' its definitely not for us */
        if (conn->uri->scheme == NULL ||
1047 1048 1049 1050
            STRNEQ(conn->uri->scheme, "qemu")) {
            ret = VIR_DRV_OPEN_DECLINED;
            goto cleanup;
        }
1051 1052

        /* Allow remote driver to deal with URIs with hostname server */
1053 1054 1055 1056
        if (conn->uri->server != NULL) {
            ret = VIR_DRV_OPEN_DECLINED;
            goto cleanup;
        }
1057

1058
        if (qemu_driver == NULL) {
1059 1060
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("qemu state driver is not active"));
1061
            goto cleanup;
1062 1063
        }

J
Ján Tomko 已提交
1064
        cfg = virQEMUDriverGetConfig(qemu_driver);
1065
        if (conn->uri->path == NULL) {
1066 1067
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no QEMU URI path given, try %s"),
1068 1069
                           cfg->uri);
            goto cleanup;
1070 1071
        }

1072
        if (cfg->privileged) {
1073 1074
            if (STRNEQ(conn->uri->path, "/system") &&
                STRNEQ(conn->uri->path, "/session")) {
1075 1076 1077
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected QEMU URI path '%s', try qemu:///system"),
                               conn->uri->path);
1078
                goto cleanup;
1079 1080
            }
        } else {
1081
            if (STRNEQ(conn->uri->path, "/session")) {
1082 1083 1084
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("unexpected QEMU URI path '%s', try qemu:///session"),
                               conn->uri->path);
1085
                goto cleanup;
1086 1087
            }
        }
1088
    }
1089 1090 1091 1092

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

1093 1094
    conn->privateData = qemu_driver;

1095 1096 1097 1098
    ret = VIR_DRV_OPEN_SUCCESS;
cleanup:
    virObjectUnref(cfg);
    return ret;
1099 1100
}

1101
static int qemuConnectClose(virConnectPtr conn)
1102
{
1103
    virQEMUDriverPtr driver = conn->privateData;
1104 1105

    /* Get rid of callbacks registered for this conn */
1106
    virCloseCallbacksRun(driver->closeCallbacks, conn, driver->domains, driver);
1107 1108 1109 1110 1111 1112

    conn->privateData = NULL;

    return 0;
}

D
Daniel Veillard 已提交
1113 1114
/* Which features are supported by this driver? */
static int
1115
qemuConnectSupportsFeature(virConnectPtr conn, int feature)
D
Daniel Veillard 已提交
1116
{
1117 1118 1119
    if (virConnectSupportsFeatureEnsureACL(conn) < 0)
        return -1;

D
Daniel Veillard 已提交
1120
    switch (feature) {
1121
    case VIR_DRV_FEATURE_MIGRATION_V2:
1122
    case VIR_DRV_FEATURE_MIGRATION_V3:
1123
    case VIR_DRV_FEATURE_MIGRATION_P2P:
1124
    case VIR_DRV_FEATURE_MIGRATE_CHANGE_PROTECTION:
1125
    case VIR_DRV_FEATURE_FD_PASSING:
1126
    case VIR_DRV_FEATURE_TYPED_PARAM_STRING:
1127
    case VIR_DRV_FEATURE_XML_MIGRATABLE:
L
liguang 已提交
1128
    case VIR_DRV_FEATURE_MIGRATION_OFFLINE:
1129
    case VIR_DRV_FEATURE_MIGRATION_PARAMS:
1130 1131 1132
        return 1;
    default:
        return 0;
D
Daniel Veillard 已提交
1133 1134 1135
    }
}

1136
static const char *qemuConnectGetType(virConnectPtr conn ATTRIBUTE_UNUSED) {
1137 1138 1139
    if (virConnectGetTypeEnsureACL(conn) < 0)
        return NULL;

1140
    return "QEMU";
1141 1142
}

1143

1144
static int qemuConnectIsSecure(virConnectPtr conn ATTRIBUTE_UNUSED)
1145 1146 1147 1148 1149
{
    /* Trivially secure, since always inside the daemon */
    return 1;
}

1150
static int qemuConnectIsEncrypted(virConnectPtr conn ATTRIBUTE_UNUSED)
1151 1152 1153 1154 1155
{
    /* Not encrypted, but remote driver takes care of that */
    return 0;
}

1156
static int qemuConnectIsAlive(virConnectPtr conn ATTRIBUTE_UNUSED)
1157 1158 1159 1160
{
    return 1;
}

1161

1162 1163 1164 1165
static int
kvmGetMaxVCPUs(void) {
    int fd;
    int ret;
1166

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

1172
#ifdef KVM_CAP_MAX_VCPUS
1173 1174 1175
    /* at first try KVM_CAP_MAX_VCPUS to determine the maximum count */
    if ((ret = ioctl(fd, KVM_CHECK_EXTENSION, KVM_CAP_MAX_VCPUS)) > 0)
        goto cleanup;
1176
#endif /* KVM_CAP_MAX_VCPUS */
1177 1178 1179 1180 1181 1182 1183 1184 1185

    /* as a fallback get KVM_CAP_NR_VCPUS (the recommended maximum number of
     * vcpus). Note that on most machines this is set to 160. */
    if ((ret = ioctl(fd, KVM_CHECK_EXTENSION, KVM_CAP_NR_VCPUS)) > 0)
        goto cleanup;

    /* if KVM_CAP_NR_VCPUS doesn't exist either, kernel documentation states
     * that 4 should be used as the maximum number of cpus */
    ret = 4;
1186

1187
cleanup:
1188
    VIR_FORCE_CLOSE(fd);
1189
    return ret;
1190 1191 1192
}


E
Eric Blake 已提交
1193
static char *
1194
qemuConnectGetSysinfo(virConnectPtr conn, unsigned int flags)
E
Eric Blake 已提交
1195
{
1196
    virQEMUDriverPtr driver = conn->privateData;
1197
    virBuffer buf = VIR_BUFFER_INITIALIZER;
E
Eric Blake 已提交
1198 1199 1200

    virCheckFlags(0, NULL);

1201 1202 1203
    if (virConnectGetSysinfoEnsureACL(conn) < 0)
        return NULL;

E
Eric Blake 已提交
1204
    if (!driver->hostsysinfo) {
1205 1206
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("Host SMBIOS information is not available"));
E
Eric Blake 已提交
1207 1208 1209
        return NULL;
    }

1210 1211 1212 1213 1214 1215 1216
    if (virSysinfoFormat(&buf, driver->hostsysinfo) < 0)
        return NULL;
    if (virBufferError(&buf)) {
        virReportOOMError();
        return NULL;
    }
    return virBufferContentAndReset(&buf);
E
Eric Blake 已提交
1217 1218
}

1219
static int qemuConnectGetMaxVcpus(virConnectPtr conn ATTRIBUTE_UNUSED, const char *type) {
1220 1221 1222
    if (virConnectGetMaxVcpusEnsureACL(conn) < 0)
        return -1;

1223 1224 1225
    if (!type)
        return 16;

1226
    if (STRCASEEQ(type, "qemu"))
1227 1228
        return 16;

1229
    if (STRCASEEQ(type, "kvm"))
1230
        return kvmGetMaxVCPUs();
1231

1232
    if (STRCASEEQ(type, "kqemu"))
1233
        return 1;
1234

1235 1236
    virReportError(VIR_ERR_INVALID_ARG,
                   _("unknown type '%s'"), type);
1237 1238 1239
    return -1;
}

1240

1241
static char *qemuConnectGetCapabilities(virConnectPtr conn) {
1242
    virQEMUDriverPtr driver = conn->privateData;
1243
    virCapsPtr caps = NULL;
1244
    char *xml = NULL;
1245

1246 1247 1248
    if (virConnectGetCapabilitiesEnsureACL(conn) < 0)
        return NULL;

1249
    if (!(caps = virQEMUDriverGetCapabilities(driver, true)))
1250
        goto cleanup;
1251

1252
    if ((xml = virCapabilitiesFormatXML(caps)) == NULL)
1253
        virReportOOMError();
1254
    virObjectUnref(caps);
1255 1256

cleanup:
1257

1258
    return xml;
1259 1260 1261
}


1262
static int
1263 1264
qemuGetProcessInfo(unsigned long long *cpuTime, int *lastCpu, long *vm_rss,
                   pid_t pid, int tid)
1265 1266
{
    char *proc;
D
Daniel P. Berrange 已提交
1267
    FILE *pidinfo;
1268
    unsigned long long usertime, systime;
1269
    long rss;
1270 1271
    int cpu;
    int ret;
D
Daniel P. Berrange 已提交
1272

1273 1274
    /* In general, we cannot assume pid_t fits in int; but /proc parsing
     * is specific to Linux where int works fine.  */
1275
    if (tid)
1276
        ret = virAsprintf(&proc, "/proc/%d/task/%d/stat", (int) pid, tid);
1277
    else
1278
        ret = virAsprintf(&proc, "/proc/%d/stat", (int) pid);
1279
    if (ret < 0)
D
Daniel P. Berrange 已提交
1280 1281 1282 1283
        return -1;

    if (!(pidinfo = fopen(proc, "r"))) {
        /* VM probably shut down, so fake 0 */
1284 1285 1286 1287
        if (cpuTime)
            *cpuTime = 0;
        if (lastCpu)
            *lastCpu = 0;
1288 1289
        if (vm_rss)
            *vm_rss = 0;
1290
        VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1291 1292
        return 0;
    }
1293
    VIR_FREE(proc);
D
Daniel P. Berrange 已提交
1294

1295 1296 1297 1298 1299 1300
    /* 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 */
1301
               "%*d %*d %*d %*d %*d %*d %*u %*u %ld %*u %*u %*u"
1302 1303
               /* startstack -> processor */
               "%*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %*d %d",
1304
               &usertime, &systime, &rss, &cpu) != 4) {
1305
        VIR_FORCE_FCLOSE(pidinfo);
1306
        VIR_WARN("cannot parse process status data");
1307
        errno = -EINVAL;
D
Daniel P. Berrange 已提交
1308 1309 1310 1311 1312 1313 1314 1315
        return -1;
    }

    /* We got jiffies
     * We want nanoseconds
     * _SC_CLK_TCK is jiffies per second
     * So calulate thus....
     */
1316 1317 1318 1319 1320
    if (cpuTime)
        *cpuTime = 1000ull * 1000ull * 1000ull * (usertime + systime) / (unsigned long long)sysconf(_SC_CLK_TCK);
    if (lastCpu)
        *lastCpu = cpu;

1321 1322 1323 1324 1325 1326
    /* 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 已提交
1327

1328 1329

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

1332
    VIR_FORCE_FCLOSE(pidinfo);
D
Daniel P. Berrange 已提交
1333 1334 1335 1336 1337

    return 0;
}


1338 1339
static virDomainPtr qemuDomainLookupByID(virConnectPtr conn,
                                         int id) {
1340
    virQEMUDriverPtr driver = conn->privateData;
1341 1342 1343
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;

1344
    vm  = virDomainObjListFindByID(driver->domains, id);
1345 1346

    if (!vm) {
1347 1348
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching id %d"), id);
1349
        goto cleanup;
1350 1351
    }

1352 1353 1354
    if (virDomainLookupByIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

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

cleanup:
1359
    if (vm)
1360
        virObjectUnlock(vm);
1361 1362
    return dom;
}
1363

1364 1365
static virDomainPtr qemuDomainLookupByUUID(virConnectPtr conn,
                                           const unsigned char *uuid) {
1366
    virQEMUDriverPtr driver = conn->privateData;
1367 1368
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1369

1370
    vm = virDomainObjListFindByUUID(driver->domains, uuid);
1371

1372
    if (!vm) {
1373 1374
        char uuidstr[VIR_UUID_STRING_BUFLEN];
        virUUIDFormat(uuid, uuidstr);
1375 1376
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching uuid '%s'"), uuidstr);
1377
        goto cleanup;
1378 1379
    }

1380 1381 1382
    if (virDomainLookupByUUIDEnsureACL(conn, vm->def) < 0)
        goto cleanup;

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

cleanup:
1387
    if (vm)
1388
        virObjectUnlock(vm);
1389 1390
    return dom;
}
1391

1392 1393
static virDomainPtr qemuDomainLookupByName(virConnectPtr conn,
                                           const char *name) {
1394
    virQEMUDriverPtr driver = conn->privateData;
1395 1396
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
1397

1398
    vm = virDomainObjListFindByName(driver->domains, name);
1399

1400
    if (!vm) {
1401 1402
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), name);
1403
        goto cleanup;
1404 1405
    }

1406 1407 1408
    if (virDomainLookupByNameEnsureACL(conn, vm->def) < 0)
        goto cleanup;

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

cleanup:
1413
    if (vm)
1414
        virObjectUnlock(vm);
1415 1416 1417
    return dom;
}

1418 1419 1420 1421 1422 1423

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

1424
    if (!(obj = qemuDomObjFromDomain(dom)))
1425
        goto cleanup;
1426

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

1430 1431 1432 1433
    ret = virDomainObjIsActive(obj);

cleanup:
    if (obj)
1434
        virObjectUnlock(obj);
1435 1436 1437 1438 1439 1440 1441 1442
    return ret;
}

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

1443
    if (!(obj = qemuDomObjFromDomain(dom)))
1444
        goto cleanup;
1445

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

1449 1450 1451 1452
    ret = obj->persistent;

cleanup:
    if (obj)
1453
        virObjectUnlock(obj);
1454 1455 1456
    return ret;
}

1457 1458 1459 1460 1461
static int qemuDomainIsUpdated(virDomainPtr dom)
{
    virDomainObjPtr obj;
    int ret = -1;

1462
    if (!(obj = qemuDomObjFromDomain(dom)))
1463
        goto cleanup;
1464

1465 1466 1467
    if (virDomainIsUpdatedEnsureACL(dom->conn, obj->def) < 0)
        goto cleanup;

1468 1469 1470 1471
    ret = obj->updated;

cleanup:
    if (obj)
1472
        virObjectUnlock(obj);
1473 1474
    return ret;
}
1475

1476
static int qemuConnectGetVersion(virConnectPtr conn, unsigned long *version) {
1477
    virQEMUDriverPtr driver = conn->privateData;
1478
    int ret = -1;
1479
    unsigned int qemuVersion = 0;
1480
    virCapsPtr caps = NULL;
1481

1482 1483 1484
    if (virConnectGetVersionEnsureACL(conn) < 0)
        return -1;

1485 1486 1487 1488
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (virQEMUCapsGetDefaultVersion(caps,
1489 1490
                                     driver->qemuCapsCache,
                                     &qemuVersion) < 0)
1491
        goto cleanup;
1492

1493
    *version = qemuVersion;
1494 1495 1496
    ret = 0;

cleanup:
1497
    virObjectUnref(caps);
1498
    return ret;
D
Daniel P. Berrange 已提交
1499 1500
}

1501

1502
static char *qemuConnectGetHostname(virConnectPtr conn)
1503
{
1504 1505 1506
    if (virConnectGetHostnameEnsureACL(conn) < 0)
        return NULL;

1507 1508 1509 1510
    return virGetHostname();
}


1511
static int qemuConnectListDomains(virConnectPtr conn, int *ids, int nids) {
1512
    virQEMUDriverPtr driver = conn->privateData;
1513
    int n;
1514

1515 1516 1517
    if (virConnectListDomainsEnsureACL(conn) < 0)
        return -1;

1518 1519
    n = virDomainObjListGetActiveIDs(driver->domains, ids, nids,
                                     virConnectListDomainsCheckACL, conn);
1520

1521
    return n;
D
Daniel P. Berrange 已提交
1522
}
1523

1524
static int qemuConnectNumOfDomains(virConnectPtr conn) {
1525
    virQEMUDriverPtr driver = conn->privateData;
1526
    int n;
1527

1528 1529 1530
    if (virConnectNumOfDomainsEnsureACL(conn) < 0)
        return -1;

1531 1532
    n = virDomainObjListNumOfDomains(driver->domains, true,
                                     virConnectNumOfDomainsCheckACL, conn);
1533

1534
    return n;
D
Daniel P. Berrange 已提交
1535
}
1536

1537 1538

static int
1539
qemuCanonicalizeMachine(virDomainDefPtr def, virQEMUCapsPtr qemuCaps)
1540
{
1541
    const char *canon;
1542

1543
    if (!(canon = virQEMUCapsGetCanonicalMachine(qemuCaps, def->os.machine)))
1544 1545 1546
        return 0;

    if (STRNEQ(canon, def->os.machine)) {
1547
        char *tmp;
1548
        if (VIR_STRDUP(tmp, canon) < 0)
1549 1550 1551 1552 1553 1554 1555 1556 1557
            return -1;
        VIR_FREE(def->os.machine);
        def->os.machine = tmp;
    }

    return 0;
}


1558 1559 1560
static virDomainPtr qemuDomainCreateXML(virConnectPtr conn,
                                        const char *xml,
                                        unsigned int flags) {
1561
    virQEMUDriverPtr driver = conn->privateData;
1562
    virDomainDefPtr def = NULL;
1563
    virDomainObjPtr vm = NULL;
1564
    virDomainPtr dom = NULL;
1565 1566
    virObjectEventPtr event = NULL;
    virObjectEventPtr event2 = NULL;
1567
    unsigned int start_flags = VIR_QEMU_PROCESS_START_COLD;
1568
    virQEMUCapsPtr qemuCaps = NULL;
1569
    virCapsPtr caps = NULL;
D
Daniel P. Berrange 已提交
1570

1571 1572
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
                  VIR_DOMAIN_START_AUTODESTROY, NULL);
1573

1574 1575 1576
    if (flags & VIR_DOMAIN_START_PAUSED)
        start_flags |= VIR_QEMU_PROCESS_START_PAUSED;
    if (flags & VIR_DOMAIN_START_AUTODESTROY)
1577
        start_flags |= VIR_QEMU_PROCESS_START_AUTODESTROY;
1578

1579 1580
    virNWFilterReadLockFilterUpdates();

1581 1582 1583
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

1584
    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
M
Matthias Bolte 已提交
1585
                                        QEMU_EXPECTED_VIRT_TYPES,
1586
                                        VIR_DOMAIN_XML_INACTIVE)))
1587
        goto cleanup;
1588

1589 1590 1591
    if (virDomainCreateXMLEnsureACL(conn, def) < 0)
        goto cleanup;

1592
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
1593 1594
        goto cleanup;

1595
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
1596 1597
        goto cleanup;

1598
    if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
1599 1600
        goto cleanup;

1601
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
1602 1603
        goto cleanup;

1604
    if (!(vm = virDomainObjListAdd(driver->domains, def,
1605
                                   driver->xmlopt,
1606 1607
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
1608 1609 1610
        goto cleanup;

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

E
Eric Blake 已提交
1612 1613 1614 1615 1616
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) {
        qemuDomainRemoveInactive(driver, vm);
        vm = NULL;
        goto cleanup;
    }
1617

1618 1619 1620
    if (qemuProcessStart(conn, driver, vm, NULL, -1, NULL, NULL,
                         VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                         start_flags) < 0) {
1621
        virDomainAuditStart(vm, "booted", false);
E
Eric Blake 已提交
1622
        if (qemuDomainObjEndJob(driver, vm))
1623
            qemuDomainRemoveInactive(driver, vm);
1624
        vm = NULL;
1625
        goto cleanup;
D
Daniel P. Berrange 已提交
1626
    }
1627

1628
    event = virDomainEventLifecycleNewFromObj(vm,
1629 1630
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
1631 1632 1633 1634 1635 1636
    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.  */
1637
        event2 = virDomainEventLifecycleNewFromObj(vm,
1638 1639 1640
                                          VIR_DOMAIN_EVENT_SUSPENDED,
                                          VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
    }
1641
    virDomainAuditStart(vm, "booted", true);
D
Daniel P. Berrange 已提交
1642

1643
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
E
Eric Blake 已提交
1644 1645
    if (dom)
        dom->id = vm->def->id;
1646

E
Eric Blake 已提交
1647
    if (!qemuDomainObjEndJob(driver, vm))
1648
        vm = NULL;
1649

1650 1651
cleanup:
    virDomainDefFree(def);
1652
    if (vm)
1653
        virObjectUnlock(vm);
1654
    if (event) {
1655
        qemuDomainEventQueue(driver, event);
1656 1657 1658
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
1659
    virObjectUnref(caps);
1660
    virObjectUnref(qemuCaps);
1661
    virNWFilterUnlockFilterUpdates();
1662
    return dom;
D
Daniel P. Berrange 已提交
1663 1664 1665
}


1666
static int qemuDomainSuspend(virDomainPtr dom) {
1667
    virQEMUDriverPtr driver = dom->conn->privateData;
1668 1669
    virDomainObjPtr vm;
    int ret = -1;
1670
    virObjectEventPtr event = NULL;
1671
    qemuDomainObjPrivatePtr priv;
1672 1673
    virDomainPausedReason reason;
    int eventDetail;
1674
    int state;
1675
    virQEMUDriverConfigPtr cfg = NULL;
1676

1677 1678
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
1679

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

D
Daniel P. Berrange 已提交
1683
    if (!virDomainObjIsActive(vm)) {
1684 1685
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1686
        goto cleanup;
D
Daniel P. Berrange 已提交
1687
    }
1688

1689
    cfg = virQEMUDriverGetConfig(driver);
1690 1691
    priv = vm->privateData;

1692
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_SUSPEND) < 0)
1693 1694 1695
        goto cleanup;

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

1701 1702 1703
    if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_OUT) {
        reason = VIR_DOMAIN_PAUSED_MIGRATION;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_MIGRATED;
1704 1705 1706
    } else if (priv->job.asyncJob == QEMU_ASYNC_JOB_SNAPSHOT) {
        reason = VIR_DOMAIN_PAUSED_SNAPSHOT;
        eventDetail = -1; /* don't create lifecycle events when doing snapshot */
1707 1708 1709 1710 1711
    } else {
        reason = VIR_DOMAIN_PAUSED_USER;
        eventDetail = VIR_DOMAIN_EVENT_SUSPENDED_PAUSED;
    }

1712 1713 1714 1715 1716 1717
    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) {
1718
        if (qemuProcessStopCPUs(driver, vm, reason, QEMU_ASYNC_JOB_NONE) < 0) {
1719
            goto endjob;
1720
        }
1721 1722

        if (eventDetail >= 0) {
1723
            event = virDomainEventLifecycleNewFromObj(vm,
1724 1725 1726
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             eventDetail);
        }
D
Daniel P. Berrange 已提交
1727
    }
1728
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
1729 1730
        goto endjob;
    ret = 0;
1731

1732
endjob:
E
Eric Blake 已提交
1733
    if (!qemuDomainObjEndJob(driver, vm))
1734
        vm = NULL;
1735

1736
cleanup:
1737
    if (vm)
1738
        virObjectUnlock(vm);
1739

1740
    if (event)
1741
        qemuDomainEventQueue(driver, event);
1742
    virObjectUnref(cfg);
1743
    return ret;
D
Daniel P. Berrange 已提交
1744 1745 1746
}


1747
static int qemuDomainResume(virDomainPtr dom) {
1748
    virQEMUDriverPtr driver = dom->conn->privateData;
1749 1750
    virDomainObjPtr vm;
    int ret = -1;
1751
    virObjectEventPtr event = NULL;
1752
    int state;
1753
    virQEMUDriverConfigPtr cfg = NULL;
1754
    virCapsPtr caps = NULL;
1755

1756 1757
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
1758

1759 1760
    cfg = virQEMUDriverGetConfig(driver);

1761 1762 1763
    if (virDomainResumeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

D
Daniel P. Berrange 已提交
1767
    if (!virDomainObjIsActive(vm)) {
1768 1769
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1770
        goto endjob;
D
Daniel P. Berrange 已提交
1771
    }
1772 1773 1774 1775 1776 1777 1778

    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 已提交
1779
        if (qemuProcessStartCPUs(driver, vm, dom->conn,
1780 1781
                                 VIR_DOMAIN_RUNNING_UNPAUSED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
1782
            if (virGetLastError() == NULL)
1783 1784
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("resume operation failed"));
1785
            goto endjob;
1786
        }
1787
        event = virDomainEventLifecycleNewFromObj(vm,
1788 1789
                                         VIR_DOMAIN_EVENT_RESUMED,
                                         VIR_DOMAIN_EVENT_RESUMED_UNPAUSED);
D
Daniel P. Berrange 已提交
1790
    }
1791 1792
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto endjob;
1793
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
1794
        goto endjob;
1795 1796
    ret = 0;

1797
endjob:
E
Eric Blake 已提交
1798
    if (!qemuDomainObjEndJob(driver, vm))
1799
        vm = NULL;
1800

1801
cleanup:
1802
    if (vm)
1803
        virObjectUnlock(vm);
1804
    if (event)
1805
        qemuDomainEventQueue(driver, event);
1806
    virObjectUnref(caps);
1807
    virObjectUnref(cfg);
1808
    return ret;
D
Daniel P. Berrange 已提交
1809 1810
}

1811
static int qemuDomainShutdownFlags(virDomainPtr dom, unsigned int flags) {
1812
    virQEMUDriverPtr driver = dom->conn->privateData;
1813 1814
    virDomainObjPtr vm;
    int ret = -1;
1815
    qemuDomainObjPrivatePtr priv;
1816
    bool useAgent = false, agentRequested, acpiRequested;
1817 1818
    bool isReboot = false;
    int agentFlag = QEMU_AGENT_SHUTDOWN_POWERDOWN;
1819 1820 1821

    virCheckFlags(VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN |
                  VIR_DOMAIN_SHUTDOWN_GUEST_AGENT, -1);
1822

1823
    if (!(vm = qemuDomObjFromDomain(dom)))
1824
        goto cleanup;
1825

1826 1827 1828 1829 1830 1831 1832
    if (vm->def->onPoweroff == VIR_DOMAIN_LIFECYCLE_RESTART ||
        vm->def->onPoweroff == VIR_DOMAIN_LIFECYCLE_RESTART_RENAME) {
        isReboot = true;
        agentFlag = QEMU_AGENT_SHUTDOWN_REBOOT;
        VIR_INFO("Domain on_poweroff setting overridden, attempting reboot");
    }

1833
    priv = vm->privateData;
1834 1835
    agentRequested = flags & VIR_DOMAIN_SHUTDOWN_GUEST_AGENT;
    acpiRequested  = flags & VIR_DOMAIN_SHUTDOWN_ACPI_POWER_BTN;
1836

1837 1838
    /* Prefer agent unless we were requested to not to. */
    if (agentRequested || (!flags && priv->agent))
1839 1840
        useAgent = true;

1841
    if (virDomainShutdownFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
1842 1843
        goto cleanup;

1844 1845
    if (priv->agentError) {
        if (agentRequested && !acpiRequested) {
1846 1847 1848
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                           _("QEMU guest agent is not "
                             "available due to an error"));
1849
            goto cleanup;
1850 1851
        } else {
            useAgent = false;
1852
        }
1853 1854 1855 1856
    }

    if (!priv->agent) {
        if (agentRequested && !acpiRequested) {
1857 1858
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
1859
            goto cleanup;
1860 1861
        } else {
            useAgent = false;
1862 1863 1864
        }
    }

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

D
Daniel P. Berrange 已提交
1868
    if (!virDomainObjIsActive(vm)) {
1869 1870
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1871
        goto endjob;
1872 1873
    }

1874
    if (useAgent) {
1875
        qemuDomainObjEnterAgent(vm);
1876
        ret = qemuAgentShutdown(priv->agent, agentFlag);
1877
        qemuDomainObjExitAgent(vm);
1878 1879 1880 1881 1882 1883 1884
    }

    /* If we are not enforced to use just an agent, try ACPI
     * shutdown as well in case agent did not succeed.
     */
    if (!useAgent ||
        (ret < 0 && (acpiRequested || !flags))) {
1885
        qemuDomainSetFakeReboot(driver, vm, isReboot);
1886

1887 1888 1889 1890
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSystemPowerdown(priv->mon);
        qemuDomainObjExitMonitor(driver, vm);
    }
1891

1892
endjob:
E
Eric Blake 已提交
1893
    if (!qemuDomainObjEndJob(driver, vm))
1894
        vm = NULL;
1895

1896
cleanup:
1897
    if (vm)
1898
        virObjectUnlock(vm);
1899
    return ret;
1900 1901
}

1902 1903
static int qemuDomainShutdown(virDomainPtr dom)
{
1904 1905 1906
    return qemuDomainShutdownFlags(dom, 0);
}

1907

1908 1909 1910
static int
qemuDomainReboot(virDomainPtr dom, unsigned int flags)
{
1911
    virQEMUDriverPtr driver = dom->conn->privateData;
1912 1913 1914
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
1915
    bool useAgent = false;
1916 1917
    bool isReboot = true;
    int agentFlag = QEMU_AGENT_SHUTDOWN_REBOOT;
1918

1919
    virCheckFlags(VIR_DOMAIN_REBOOT_ACPI_POWER_BTN |
E
Eric Blake 已提交
1920
                  VIR_DOMAIN_REBOOT_GUEST_AGENT, -1);
1921

1922 1923 1924 1925 1926 1927 1928 1929
    /* 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;
    }

1930
    if (!(vm = qemuDomObjFromDomain(dom)))
1931 1932
        goto cleanup;

1933 1934 1935 1936 1937 1938 1939
    if (vm->def->onReboot == VIR_DOMAIN_LIFECYCLE_DESTROY ||
        vm->def->onReboot == VIR_DOMAIN_LIFECYCLE_PRESERVE) {
        agentFlag = QEMU_AGENT_SHUTDOWN_POWERDOWN;
        isReboot = false;
        VIR_INFO("Domain on_reboot setting overridden, shutting down");
    }

1940 1941
    priv = vm->privateData;

1942
    if (virDomainRebootEnsureACL(dom->conn, vm->def, flags) < 0)
1943 1944
        goto cleanup;

1945 1946
    if ((flags & VIR_DOMAIN_REBOOT_GUEST_AGENT) ||
        (!(flags & VIR_DOMAIN_REBOOT_ACPI_POWER_BTN) &&
1947 1948 1949 1950 1951
         priv->agent))
        useAgent = true;

    if (useAgent) {
        if (priv->agentError) {
1952 1953 1954
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                           _("QEMU guest agent is not "
                             "available due to an error"));
1955 1956 1957
            goto cleanup;
        }
        if (!priv->agent) {
1958 1959
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
1960 1961 1962
            goto cleanup;
        }
    } else {
1963
#if WITH_YAJL
1964 1965
        if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_MONITOR_JSON)) {
            if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_NO_SHUTDOWN)) {
1966 1967
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                               _("Reboot is not supported with this QEMU binary"));
1968 1969 1970 1971
                goto cleanup;
            }
        } else {
#endif
1972 1973
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Reboot is not supported without the JSON monitor"));
1974
            goto cleanup;
1975
#if WITH_YAJL
1976
        }
1977 1978
#endif
    }
1979

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

1983
    if (!virDomainObjIsActive(vm)) {
1984 1985
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
1986 1987
        goto endjob;
    }
1988

1989
    if (useAgent) {
1990
        qemuDomainObjEnterAgent(vm);
1991
        ret = qemuAgentShutdown(priv->agent, agentFlag);
1992
        qemuDomainObjExitAgent(vm);
1993
    } else {
1994
        qemuDomainObjEnterMonitor(driver, vm);
1995
        ret = qemuMonitorSystemPowerdown(priv->mon);
1996
        qemuDomainObjExitMonitor(driver, vm);
1997

1998
        if (ret == 0)
1999
            qemuDomainSetFakeReboot(driver, vm, isReboot);
2000 2001
    }

2002
endjob:
E
Eric Blake 已提交
2003
    if (!qemuDomainObjEndJob(driver, vm))
2004 2005
        vm = NULL;

2006 2007
cleanup:
    if (vm)
2008
        virObjectUnlock(vm);
2009 2010 2011 2012
    return ret;
}


2013 2014 2015
static int
qemuDomainReset(virDomainPtr dom, unsigned int flags)
{
2016
    virQEMUDriverPtr driver = dom->conn->privateData;
2017 2018 2019 2020 2021 2022
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2023
    if (!(vm = qemuDomObjFromDomain(dom)))
2024 2025
        goto cleanup;

2026 2027 2028
    if (virDomainResetEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2029 2030 2031 2032
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
2033 2034
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045
        goto endjob;
    }

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

    priv->fakeReboot = false;

endjob:
E
Eric Blake 已提交
2046
    if (!qemuDomainObjEndJob(driver, vm))
2047 2048 2049 2050
        vm = NULL;

cleanup:
    if (vm)
2051
        virObjectUnlock(vm);
2052 2053 2054 2055
    return ret;
}


2056
/* Count how many snapshots in a set are external snapshots or checkpoints.  */
2057 2058 2059 2060 2061 2062 2063 2064
static void
qemuDomainSnapshotCountExternal(void *payload,
                                const void *name ATTRIBUTE_UNUSED,
                                void *data)
{
    virDomainSnapshotObjPtr snap = payload;
    int *count = data;

2065
    if (virDomainSnapshotIsExternal(snap))
2066 2067 2068
        (*count)++;
}

2069 2070 2071 2072
static int
qemuDomainDestroyFlags(virDomainPtr dom,
                       unsigned int flags)
{
2073
    virQEMUDriverPtr driver = dom->conn->privateData;
2074 2075
    virDomainObjPtr vm;
    int ret = -1;
2076
    virObjectEventPtr event = NULL;
2077
    qemuDomainObjPrivatePtr priv;
2078

2079
    virCheckFlags(VIR_DOMAIN_DESTROY_GRACEFUL, -1);
2080

2081 2082
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
2083

2084 2085
    priv = vm->privateData;

2086 2087 2088
    if (virDomainDestroyFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2089
    qemuDomainSetFakeReboot(driver, vm, false);
2090

2091 2092 2093 2094 2095 2096

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

2097 2098 2099 2100 2101
    /* 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
     */
2102
    if (flags & VIR_DOMAIN_DESTROY_GRACEFUL) {
2103
        if (qemuProcessKill(vm, 0) < 0) {
2104
            priv->beingDestroyed = false;
2105
            goto cleanup;
2106
        }
2107
    } else {
2108
        if (qemuProcessKill(vm, VIR_QEMU_PROCESS_KILL_FORCE) < 0) {
2109
            priv->beingDestroyed = false;
2110
            goto cleanup;
2111
        }
2112
    }
2113

2114
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_DESTROY) < 0)
2115 2116
        goto cleanup;

2117 2118
    priv->beingDestroyed = false;

D
Daniel P. Berrange 已提交
2119
    if (!virDomainObjIsActive(vm)) {
2120 2121
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2122
        goto endjob;
2123
    }
2124

2125
    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_DESTROYED, 0);
2126
    event = virDomainEventLifecycleNewFromObj(vm,
2127 2128
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_DESTROYED);
2129
    virDomainAuditStop(vm, "destroyed");
2130

2131
    if (!vm->persistent) {
E
Eric Blake 已提交
2132
        if (qemuDomainObjEndJob(driver, vm))
2133
            qemuDomainRemoveInactive(driver, vm);
2134 2135
        vm = NULL;
    }
2136 2137
    ret = 0;

2138
endjob:
E
Eric Blake 已提交
2139
    if (vm && !qemuDomainObjEndJob(driver, vm))
2140
        vm = NULL;
2141

2142
cleanup:
2143
    if (vm)
2144
        virObjectUnlock(vm);
2145 2146
    if (event)
        qemuDomainEventQueue(driver, event);
2147
    return ret;
D
Daniel P. Berrange 已提交
2148 2149
}

2150 2151 2152 2153 2154
static int
qemuDomainDestroy(virDomainPtr dom)
{
    return qemuDomainDestroyFlags(dom, 0);
}
D
Daniel P. Berrange 已提交
2155

2156
static char *qemuDomainGetOSType(virDomainPtr dom) {
2157 2158
    virDomainObjPtr vm;
    char *type = NULL;
2159

2160
    if (!(vm = qemuDomObjFromDomain(dom)))
2161
        goto cleanup;
2162

2163 2164 2165
    if (virDomainGetOSTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2166
    ignore_value(VIR_STRDUP(type, vm->def->os.type));
2167 2168

cleanup:
2169
    if (vm)
2170
        virObjectUnlock(vm);
2171 2172 2173
    return type;
}

2174
/* Returns max memory in kb, 0 if error */
2175 2176 2177
static unsigned long long
qemuDomainGetMaxMemory(virDomainPtr dom)
{
2178
    virDomainObjPtr vm;
2179
    unsigned long long ret = 0;
2180

2181
    if (!(vm = qemuDomObjFromDomain(dom)))
2182
        goto cleanup;
2183

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

2187
    ret = vm->def->mem.max_balloon;
2188 2189

cleanup:
2190
    if (vm)
2191
        virObjectUnlock(vm);
2192
    return ret;
2193 2194
}

2195 2196
static int qemuDomainSetMemoryFlags(virDomainPtr dom, unsigned long newmem,
                                    unsigned int flags) {
2197
    virQEMUDriverPtr driver = dom->conn->privateData;
2198
    qemuDomainObjPrivatePtr priv;
2199
    virDomainObjPtr vm;
2200
    virDomainDefPtr persistentDef = NULL;
2201
    int ret = -1, r;
2202
    virQEMUDriverConfigPtr cfg = NULL;
2203
    virCapsPtr caps = NULL;
2204

2205 2206
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
2207
                  VIR_DOMAIN_MEM_MAXIMUM, -1);
2208

2209
    if (!(vm = qemuDomObjFromDomain(dom)))
2210
        goto cleanup;
2211

2212 2213
    cfg = virQEMUDriverGetConfig(driver);

2214 2215 2216
    if (virDomainSetMemoryFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

2220 2221
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto endjob;
2222
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
2223
                                        &persistentDef) < 0)
2224
        goto endjob;
2225

2226 2227 2228
    if (flags & VIR_DOMAIN_MEM_MAXIMUM) {
        /* resize the maximum memory */

2229
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2230 2231 2232
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot resize the maximum memory on an "
                             "active domain"));
2233
            goto endjob;
2234
        }
2235

2236
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
2237 2238
            /* Help clang 2.8 decipher the logic flow.  */
            sa_assert(persistentDef);
2239 2240 2241
            persistentDef->mem.max_balloon = newmem;
            if (persistentDef->mem.cur_balloon > newmem)
                persistentDef->mem.cur_balloon = newmem;
2242
            ret = virDomainSaveConfig(cfg->configDir, persistentDef);
2243 2244 2245
            goto endjob;
        }

2246 2247
    } else {
        /* resize the current memory */
2248
        unsigned long oldmax = 0;
2249

2250 2251 2252 2253 2254 2255 2256 2257
        if (flags & VIR_DOMAIN_AFFECT_LIVE)
            oldmax = vm->def->mem.max_balloon;
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
            if (!oldmax || oldmax > persistentDef->mem.max_balloon)
                oldmax = persistentDef->mem.max_balloon;
        }

        if (newmem > oldmax) {
2258 2259
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("cannot set memory higher than max memory"));
2260 2261 2262
            goto endjob;
        }

2263
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2264
            priv = vm->privateData;
2265
            qemuDomainObjEnterMonitor(driver, vm);
2266
            r = qemuMonitorSetBalloon(priv->mon, newmem);
2267
            qemuDomainObjExitMonitor(driver, vm);
2268 2269
            virDomainAuditMemory(vm, vm->def->mem.cur_balloon, newmem, "update",
                                 r == 1);
2270 2271 2272 2273 2274
            if (r < 0)
                goto endjob;

            /* Lack of balloon support is a fatal error */
            if (r == 0) {
2275 2276 2277
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("Unable to change memory of active domain without "
                                 "the balloon device and guest OS balloon driver"));
2278 2279 2280 2281
                goto endjob;
            }
        }

2282
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
2283
            sa_assert(persistentDef);
2284
            persistentDef->mem.cur_balloon = newmem;
2285
            ret = virDomainSaveConfig(cfg->configDir, persistentDef);
2286 2287
            goto endjob;
        }
2288
    }
2289

2290
    ret = 0;
2291
endjob:
E
Eric Blake 已提交
2292
    if (!qemuDomainObjEndJob(driver, vm))
2293
        vm = NULL;
2294

2295
cleanup:
2296
    if (vm)
2297
        virObjectUnlock(vm);
2298
    virObjectUnref(caps);
2299
    virObjectUnref(cfg);
2300
    return ret;
2301 2302
}

2303
static int qemuDomainSetMemory(virDomainPtr dom, unsigned long newmem)
2304
{
2305
    return qemuDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
2306 2307
}

2308
static int qemuDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
2309
{
2310
    return qemuDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
2311 2312
}

2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357 2358 2359 2360 2361 2362 2363 2364 2365
static int qemuDomainSetMemoryStatsPeriod(virDomainPtr dom, int period,
                                          unsigned int flags)
{
    virQEMUDriverPtr driver = dom->conn->privateData;
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1, r;
    virQEMUDriverConfigPtr cfg = NULL;
    virCapsPtr caps = NULL;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

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

    cfg = virQEMUDriverGetConfig(driver);

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

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

    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto endjob;
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
                                        &persistentDef) < 0)
        goto endjob;

    /* Set the balloon driver collection interval */
    priv = vm->privateData;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {

        qemuDomainObjEnterMonitor(driver, vm);
        r = qemuMonitorSetMemoryStatsPeriod(priv->mon, period);
        qemuDomainObjExitMonitor(driver, vm);
        if (r < 0)
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("unable to set balloon driver collection period"));
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        sa_assert(persistentDef);
        persistentDef->memballoon->period = period;
        ret = virDomainSaveConfig(cfg->configDir, persistentDef);
        goto endjob;
    }

    ret = 0;
endjob:
E
Eric Blake 已提交
2366
    if (!qemuDomainObjEndJob(driver, vm))
2367 2368 2369 2370 2371 2372 2373 2374 2375 2376
        vm = NULL;

cleanup:
    if (vm)
        virObjectUnlock(vm);
    virObjectUnref(caps);
    virObjectUnref(cfg);
    return ret;
}

2377 2378
static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags)
{
2379
    virQEMUDriverPtr driver = domain->conn->privateData;
2380 2381 2382 2383 2384 2385
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2386 2387
    if (!(vm = qemuDomObjFromDomain(domain)))
        return -1;
2388

2389 2390 2391
    if (virDomainInjectNMIEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

2392
    if (!virDomainObjIsActive(vm)) {
2393 2394
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2395 2396 2397 2398 2399
        goto cleanup;
    }

    priv = vm->privateData;

2400
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
2401
        goto cleanup;
2402 2403

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

2409
    qemuDomainObjEnterMonitor(driver, vm);
2410
    ret = qemuMonitorInjectNMI(priv->mon);
2411
    qemuDomainObjExitMonitor(driver, vm);
2412 2413

endjob:
E
Eric Blake 已提交
2414
    if (!qemuDomainObjEndJob(driver, vm))
2415 2416 2417 2418
        vm = NULL;

cleanup:
    if (vm)
2419
        virObjectUnlock(vm);
2420 2421 2422
    return ret;
}

2423 2424 2425 2426 2427 2428 2429
static int qemuDomainSendKey(virDomainPtr domain,
                             unsigned int codeset,
                             unsigned int holdtime,
                             unsigned int *keycodes,
                             int nkeycodes,
                             unsigned int flags)
{
2430
    virQEMUDriverPtr driver = domain->conn->privateData;
2431 2432 2433 2434 2435 2436
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2437 2438
    /* translate the keycode to RFB for qemu driver */
    if (codeset != VIR_KEYCODE_SET_RFB) {
2439
        size_t i;
2440 2441 2442
        int keycode;

        for (i = 0; i < nkeycodes; i++) {
2443
            keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_RFB,
2444 2445
                                               keycodes[i]);
            if (keycode < 0) {
2446 2447 2448 2449
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot translate keycode %u of %s codeset to rfb keycode"),
                               keycodes[i],
                               virKeycodeSetTypeToString(codeset));
2450 2451 2452 2453 2454 2455
                return -1;
            }
            keycodes[i] = keycode;
        }
    }

2456
    if (!(vm = qemuDomObjFromDomain(domain)))
2457 2458 2459 2460
        goto cleanup;

    priv = vm->privateData;

2461 2462 2463
    if (virDomainSendKeyEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

2464
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
2465 2466 2467
        goto cleanup;

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

2473
    qemuDomainObjEnterMonitor(driver, vm);
2474
    ret = qemuMonitorSendKey(priv->mon, holdtime, keycodes, nkeycodes);
2475
    qemuDomainObjExitMonitor(driver, vm);
2476 2477

endjob:
E
Eric Blake 已提交
2478
    if (!qemuDomainObjEndJob(driver, vm))
2479 2480 2481 2482
        vm = NULL;

cleanup:
    if (vm)
2483
        virObjectUnlock(vm);
2484 2485 2486
    return ret;
}

2487 2488
static int qemuDomainGetInfo(virDomainPtr dom,
                             virDomainInfoPtr info)
2489
{
2490
    virQEMUDriverPtr driver = dom->conn->privateData;
2491 2492
    virDomainObjPtr vm;
    int ret = -1;
2493
    int err;
2494
    unsigned long long balloon;
2495

2496
    if (!(vm = qemuDomObjFromDomain(dom)))
2497
        goto cleanup;
D
Daniel P. Berrange 已提交
2498

2499 2500 2501
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

D
Daniel P. Berrange 已提交
2504
    if (!virDomainObjIsActive(vm)) {
2505
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
2506
    } else {
2507
        if (qemuGetProcessInfo(&(info->cpuTime), NULL, NULL, vm->pid, 0) < 0) {
2508 2509
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("cannot read cputime for domain"));
2510
            goto cleanup;
D
Daniel P. Berrange 已提交
2511 2512 2513
        }
    }

2514
    info->maxMem = vm->def->mem.max_balloon;
2515

D
Daniel P. Berrange 已提交
2516
    if (virDomainObjIsActive(vm)) {
2517
        qemuDomainObjPrivatePtr priv = vm->privateData;
2518 2519 2520

        if ((vm->def->memballoon != NULL) &&
            (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
2521
            info->memory = vm->def->mem.max_balloon;
2522
        } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT)) {
2523
            info->memory = vm->def->mem.cur_balloon;
2524
        } else if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
2525
            if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
2526
                goto cleanup;
2527 2528 2529
            if (!virDomainObjIsActive(vm))
                err = 0;
            else {
2530
                qemuDomainObjEnterMonitor(driver, vm);
2531
                err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
2532
                qemuDomainObjExitMonitor(driver, vm);
2533
            }
E
Eric Blake 已提交
2534
            if (!qemuDomainObjEndJob(driver, vm)) {
2535
                vm = NULL;
2536 2537 2538
                goto cleanup;
            }

2539 2540 2541 2542 2543 2544 2545
            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) {
2546
                /* Balloon not supported, so maxmem is always the allocation */
2547
                info->memory = vm->def->mem.max_balloon;
2548
            } else {
2549
                info->memory = balloon;
2550
            }
2551
        } else {
2552
            info->memory = vm->def->mem.cur_balloon;
2553
        }
2554
    } else {
2555
        info->memory = vm->def->mem.cur_balloon;
2556 2557
    }

2558
    info->nrVirtCpu = vm->def->vcpus;
2559 2560 2561
    ret = 0;

cleanup:
2562
    if (vm)
2563
        virObjectUnlock(vm);
2564
    return ret;
D
Daniel P. Berrange 已提交
2565 2566
}

2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577
static int
qemuDomainGetState(virDomainPtr dom,
                   int *state,
                   int *reason,
                   unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

2578
    if (!(vm = qemuDomObjFromDomain(dom)))
2579 2580
        goto cleanup;

2581 2582 2583
    if (virDomainGetStateEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

J
Jiri Denemark 已提交
2584
    *state = virDomainObjGetState(vm, reason);
2585 2586 2587 2588
    ret = 0;

cleanup:
    if (vm)
2589
        virObjectUnlock(vm);
2590 2591 2592
    return ret;
}

2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603
static int
qemuDomainGetControlInfo(virDomainPtr dom,
                          virDomainControlInfoPtr info,
                          unsigned int flags)
{
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

2604
    if (!(vm = qemuDomObjFromDomain(dom)))
2605 2606
        goto cleanup;

2607 2608 2609
    if (virDomainGetControlInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2610
    if (!virDomainObjIsActive(vm)) {
2611 2612
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2613 2614 2615 2616 2617 2618 2619 2620 2621
        goto cleanup;
    }

    priv = vm->privateData;

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

    if (priv->monError) {
        info->state = VIR_DOMAIN_CONTROL_ERROR;
2622
    } else if (priv->job.active) {
2623 2624
        if (!priv->monStart) {
            info->state = VIR_DOMAIN_CONTROL_JOB;
2625
            if (virTimeMillisNow(&info->stateTime) < 0)
2626
                goto cleanup;
2627
            info->stateTime -= priv->job.start;
2628 2629
        } else {
            info->state = VIR_DOMAIN_CONTROL_OCCUPIED;
2630
            if (virTimeMillisNow(&info->stateTime) < 0)
2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641
                goto cleanup;
            info->stateTime -= priv->monStart;
        }
    } else {
        info->state = VIR_DOMAIN_CONTROL_OK;
    }

    ret = 0;

cleanup:
    if (vm)
2642
        virObjectUnlock(vm);
2643 2644 2645
    return ret;
}

D
Daniel P. Berrange 已提交
2646

2647 2648 2649 2650 2651 2652
/* 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
2653

2654
verify(sizeof(QEMU_SAVE_MAGIC) == sizeof(QEMU_SAVE_PARTIAL));
E
Eric Blake 已提交
2655

2656
typedef enum {
2657 2658 2659
    QEMU_SAVE_FORMAT_RAW = 0,
    QEMU_SAVE_FORMAT_GZIP = 1,
    QEMU_SAVE_FORMAT_BZIP2 = 2,
2660 2661
    /*
     * Deprecated by xz and never used as part of a release
2662
     * QEMU_SAVE_FORMAT_LZMA
2663
     */
2664 2665
    QEMU_SAVE_FORMAT_XZ = 3,
    QEMU_SAVE_FORMAT_LZOP = 4,
2666 2667 2668
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
2669

2670
    QEMU_SAVE_FORMAT_LAST
2671
} virQEMUSaveFormat;
2672

2673 2674
VIR_ENUM_DECL(qemuSaveCompression)
VIR_ENUM_IMPL(qemuSaveCompression, QEMU_SAVE_FORMAT_LAST,
2675 2676 2677
              "raw",
              "gzip",
              "bzip2",
2678 2679
              "xz",
              "lzop")
2680

2681 2682 2683
typedef struct _virQEMUSaveHeader virQEMUSaveHeader;
typedef virQEMUSaveHeader *virQEMUSaveHeaderPtr;
struct _virQEMUSaveHeader {
2684
    char magic[sizeof(QEMU_SAVE_MAGIC)-1];
2685 2686 2687 2688 2689
    uint32_t version;
    uint32_t xml_len;
    uint32_t was_running;
    uint32_t compressed;
    uint32_t unused[15];
2690 2691
};

2692
static inline void
2693
bswap_header(virQEMUSaveHeaderPtr hdr) {
2694 2695 2696 2697 2698 2699 2700
    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);
}


2701
/* return -errno on failure, or 0 on success */
E
Eric Blake 已提交
2702
static int
2703
qemuDomainSaveHeader(int fd, const char *path, const char *xml,
2704
                     virQEMUSaveHeaderPtr header)
E
Eric Blake 已提交
2705
{
2706 2707
    int ret = 0;

E
Eric Blake 已提交
2708
    if (safewrite(fd, header, sizeof(*header)) != sizeof(*header)) {
2709
        ret = -errno;
2710 2711 2712
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to write header to domain save file '%s'"),
                       path);
2713 2714 2715
        goto endjob;
    }

E
Eric Blake 已提交
2716
    if (safewrite(fd, xml, header->xml_len) != header->xml_len) {
2717
        ret = -errno;
2718 2719
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to write xml to '%s'"), path);
2720 2721 2722 2723 2724 2725
        goto endjob;
    }
endjob:
    return ret;
}

2726
/* Given a virQEMUSaveFormat compression level, return the name
2727 2728 2729 2730
 * of the program to run, or NULL if no program is needed.  */
static const char *
qemuCompressProgramName(int compress)
{
2731 2732
    return (compress == QEMU_SAVE_FORMAT_RAW ? NULL :
            qemuSaveCompressionTypeToString(compress));
2733 2734
}

2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761
static virCommandPtr
qemuCompressGetCommand(virQEMUSaveFormat compression)
{
    virCommandPtr ret = NULL;
    const char *prog = qemuSaveCompressionTypeToString(compression);

    if (!prog) {
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("Invalid compressed save format %d"),
                       compression);
        return NULL;
    }

    ret = virCommandNew(prog);
    virCommandAddArg(ret, "-dc");

    switch (compression) {
    case QEMU_SAVE_FORMAT_LZOP:
        virCommandAddArg(ret, "--ignore-warn");
        break;
    default:
        break;
    }

    return ret;
}

E
Eric Blake 已提交
2762
/* Internal function to properly create or open existing files, with
2763
 * ownership affected by qemu driver setup and domain DAC label.  */
E
Eric Blake 已提交
2764
static int
2765 2766 2767
qemuOpenFile(virQEMUDriverPtr driver,
             virDomainObjPtr vm,
             const char *path, int oflags,
E
Eric Blake 已提交
2768
             bool *needUnlink, bool *bypassSecurityDriver)
2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796
{
    int ret = -1;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
    uid_t user = cfg->user;
    gid_t group = cfg->group;
    bool dynamicOwnership = cfg->dynamicOwnership;
    virSecurityLabelDefPtr seclabel;

    virObjectUnref(cfg);

    /* TODO: Take imagelabel into account? */
    if (vm &&
        (seclabel = virDomainDefGetSecurityLabelDef(vm->def, "dac")) != NULL &&
        (virParseOwnershipIds(seclabel->label, &user, &group) < 0))
        goto cleanup;

    ret = qemuOpenFileAs(user, group, dynamicOwnership,
                         path, oflags, needUnlink, bypassSecurityDriver);

 cleanup:
    return ret;
}

static int
qemuOpenFileAs(uid_t fallback_uid, gid_t fallback_gid,
               bool dynamicOwnership,
               const char *path, int oflags,
               bool *needUnlink, bool *bypassSecurityDriver)
E
Eric Blake 已提交
2797 2798 2799 2800 2801
{
    struct stat sb;
    bool is_reg = true;
    bool need_unlink = false;
    bool bypass_security = false;
L
Laine Stump 已提交
2802
    unsigned int vfoflags = 0;
E
Eric Blake 已提交
2803
    int fd = -1;
2804
    int path_shared = virStorageFileIsSharedFS(path);
2805 2806
    uid_t uid = geteuid();
    gid_t gid = getegid();
E
Eric Blake 已提交
2807 2808 2809 2810 2811 2812

    /* 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;
2813 2814 2815

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

E
Eric Blake 已提交
2819 2820 2821 2822 2823
        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 */
2824
            if (is_reg && !dynamicOwnership) {
E
Eric Blake 已提交
2825 2826 2827 2828 2829 2830 2831 2832
                uid = sb.st_uid;
                gid = sb.st_gid;
            }
        }
    }

    /* First try creating the file as root */
    if (!is_reg) {
2833 2834 2835
        if ((fd = open(path, oflags & ~O_CREAT)) < 0) {
            fd = -errno;
            goto error;
E
Eric Blake 已提交
2836 2837
        }
    } else {
L
Laine Stump 已提交
2838 2839
        if ((fd = virFileOpenAs(path, oflags, S_IRUSR | S_IWUSR, uid, gid,
                                vfoflags | VIR_FILE_OPEN_NOFORK)) < 0) {
E
Eric Blake 已提交
2840 2841 2842
            /* 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
2843
               qemu user is non-root, just set a flag to
E
Eric Blake 已提交
2844 2845
               bypass security driver shenanigans, and retry the operation
               after doing setuid to qemu user */
2846
            if ((fd != -EACCES && fd != -EPERM) || fallback_uid == geteuid())
2847
                goto error;
E
Eric Blake 已提交
2848 2849

            /* On Linux we can also verify the FS-type of the directory. */
2850
            switch (path_shared) {
E
Eric Blake 已提交
2851
                case 1:
2852 2853 2854 2855
                    /* it was on a network share, so we'll continue
                     * as outlined above
                     */
                    break;
E
Eric Blake 已提交
2856 2857

                case -1:
2858 2859 2860 2861 2862 2863 2864
                    virReportSystemError(-fd, oflags & O_CREAT
                                         ? _("Failed to create file "
                                             "'%s': couldn't determine fs type")
                                         : _("Failed to open file "
                                             "'%s': couldn't determine fs type"),
                                         path);
                    goto cleanup;
E
Eric Blake 已提交
2865 2866 2867

                case 0:
                default:
2868 2869
                    /* local file - log the error returned by virFileOpenAs */
                    goto error;
E
Eric Blake 已提交
2870 2871
            }

2872
            /* Retry creating the file as qemu user */
E
Eric Blake 已提交
2873 2874 2875

            if ((fd = virFileOpenAs(path, oflags,
                                    S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
2876
                                    fallback_uid, fallback_gid,
L
Laine Stump 已提交
2877
                                    vfoflags | VIR_FILE_OPEN_FORK)) < 0) {
2878 2879 2880
                virReportSystemError(-fd, oflags & O_CREAT
                                     ? _("Error from child process creating '%s'")
                                     : _("Error from child process opening '%s'"),
E
Eric Blake 已提交
2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897
                                     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;
2898 2899 2900 2901 2902 2903 2904

error:
    virReportSystemError(-fd, oflags & O_CREAT
                         ? _("Failed to create file '%s'")
                         : _("Failed to open file '%s'"),
                         path);
    goto cleanup;
E
Eric Blake 已提交
2905 2906
}

2907 2908 2909
/* 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 */
2910
static int
2911
qemuDomainSaveMemory(virQEMUDriverPtr driver,
2912 2913
                     virDomainObjPtr vm,
                     const char *path,
2914
                     const char *domXML,
2915 2916 2917 2918
                     int compressed,
                     bool was_running,
                     unsigned int flags,
                     enum qemuDomainAsyncJob asyncJob)
2919
{
2920
    virQEMUSaveHeader header;
2921
    bool bypassSecurityDriver = false;
E
Eric Blake 已提交
2922
    bool needUnlink = false;
2923
    int ret = -1;
2924
    int fd = -1;
2925
    int directFlag = 0;
J
Jiri Denemark 已提交
2926
    virFileWrapperFdPtr wrapperFd = NULL;
2927
    unsigned int wrapperFlags = VIR_FILE_WRAPPER_NON_BLOCKING;
2928 2929 2930
    unsigned long long pad;
    unsigned long long offset;
    size_t len;
2931
    char *xml = NULL;
2932

2933
    memset(&header, 0, sizeof(header));
2934 2935
    memcpy(header.magic, QEMU_SAVE_PARTIAL, sizeof(header.magic));
    header.version = QEMU_SAVE_VERSION;
2936
    header.was_running = was_running ? 1 : 0;
2937

2938
    header.compressed = compressed;
2939

2940
    len = strlen(domXML) + 1;
2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953
    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));
2954
    if (VIR_ALLOC_N(xml, len + pad) < 0)
2955
        goto cleanup;
2956 2957
    strcpy(xml, domXML);

2958 2959
    offset += pad;
    header.xml_len = len;
2960

2961
    /* Obtain the file handle.  */
2962 2963
    if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE)) {
        wrapperFlags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
2964 2965
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
2966 2967
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
E
Eric Blake 已提交
2968
            goto cleanup;
2969
        }
2970
    }
2971 2972
    fd = qemuOpenFile(driver, vm, path,
                      O_WRONLY | O_TRUNC | O_CREAT | directFlag,
E
Eric Blake 已提交
2973 2974
                      &needUnlink, &bypassSecurityDriver);
    if (fd < 0)
2975 2976
        goto cleanup;

2977
    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, wrapperFlags)))
2978
        goto cleanup;
2979

2980
    /* Write header to file, followed by XML */
2981 2982
    if (qemuDomainSaveHeader(fd, path, xml, &header) < 0)
        goto cleanup;
2983

2984
    /* Perform the migration */
2985
    if (qemuMigrationToFile(driver, vm, fd, offset, path,
2986
                            qemuCompressProgramName(compressed),
E
Eric Blake 已提交
2987
                            bypassSecurityDriver,
2988 2989
                            asyncJob) < 0)
        goto cleanup;
E
Eric Blake 已提交
2990

2991 2992 2993 2994 2995 2996 2997 2998
    /* 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);
2999
        goto cleanup;
E
Eric Blake 已提交
3000
    }
3001

3002
    if (virFileWrapperFdClose(wrapperFd) < 0)
3003 3004
        goto cleanup;

3005
    if ((fd = qemuOpenFile(driver, vm, path, O_WRONLY, NULL, NULL)) < 0)
3006
        goto cleanup;
3007

3008
    memcpy(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic));
3009

E
Eric Blake 已提交
3010 3011
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
        virReportSystemError(errno, _("unable to write %s"), path);
3012
        goto cleanup;
E
Eric Blake 已提交
3013
    }
3014

3015 3016
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("unable to close %s"), path);
3017
        goto cleanup;
3018 3019
    }

3020 3021
    ret = 0;

3022 3023 3024
cleanup:
    VIR_FORCE_CLOSE(fd);
    virFileWrapperFdFree(wrapperFd);
3025
    VIR_FREE(xml);
3026 3027 3028 3029 3030 3031 3032

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

    return ret;
}

3033
/* The vm must be active + locked. Vm will be unlocked and
3034 3035 3036 3037 3038
 * 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
3039
qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
3040 3041 3042 3043 3044 3045 3046
                       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;
3047
    virObjectEventPtr event = NULL;
3048
    qemuDomainObjPrivatePtr priv = vm->privateData;
3049 3050 3051 3052
    virCapsPtr caps;

    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;
3053

3054
    if (!qemuMigrationIsAllowed(driver, vm, vm->def, false, false))
3055 3056
        goto cleanup;

3057 3058
    if (qemuDomainObjBeginAsyncJob(driver, vm, QEMU_ASYNC_JOB_SAVE) < 0)
        goto cleanup;
3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089

    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;

3090
        if (!(def = virDomainDefParseString(xmlin, caps, driver->xmlopt,
3091 3092 3093 3094
                                            QEMU_EXPECTED_VIRT_TYPES,
                                            VIR_DOMAIN_XML_INACTIVE))) {
            goto endjob;
        }
3095
        if (!qemuDomainDefCheckABIStability(driver, vm->def, def)) {
3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113
            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;

3114
    /* Shut it down */
3115
    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SAVED, 0);
3116
    virDomainAuditStop(vm, "saved");
3117
    event = virDomainEventLifecycleNewFromObj(vm,
3118 3119
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
3120
    if (!vm->persistent) {
3121
        if (qemuDomainObjEndAsyncJob(driver, vm) > 0)
3122
            qemuDomainRemoveInactive(driver, vm);
3123 3124
        vm = NULL;
    }
3125

3126
endjob:
3127
    if (vm) {
3128
        if (ret != 0) {
3129
            if (was_running && virDomainObjIsActive(vm)) {
J
Jiri Denemark 已提交
3130
                rc = qemuProcessStartCPUs(driver, vm, dom->conn,
3131 3132
                                          VIR_DOMAIN_RUNNING_SAVE_CANCELED,
                                          QEMU_ASYNC_JOB_SAVE);
3133
                if (rc < 0) {
3134
                    VIR_WARN("Unable to resume guest CPUs after save failure");
3135
                    event = virDomainEventLifecycleNewFromObj(vm,
3136 3137 3138
                                                     VIR_DOMAIN_EVENT_SUSPENDED,
                                                     VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
                }
3139
            }
3140
        }
3141
        if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
3142
            vm = NULL;
3143
    }
3144

3145 3146
cleanup:
    VIR_FREE(xml);
3147 3148
    if (event)
        qemuDomainEventQueue(driver, event);
3149
    if (vm)
3150
        virObjectUnlock(vm);
3151
    virObjectUnref(caps);
3152
    return ret;
D
Daniel P. Berrange 已提交
3153 3154
}

3155
/* Returns true if a compression program is available in PATH */
3156 3157
static bool
qemuCompressProgramAvailable(virQEMUSaveFormat compress)
3158
{
3159
    char *path;
3160

3161
    if (compress == QEMU_SAVE_FORMAT_RAW)
3162
        return true;
3163 3164

    if (!(path = virFindFileInPath(qemuSaveCompressionTypeToString(compress))))
3165
        return false;
3166 3167

    VIR_FREE(path);
3168 3169 3170
    return true;
}

3171 3172 3173
static int
qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
                    unsigned int flags)
3174
{
3175
    virQEMUDriverPtr driver = dom->conn->privateData;
3176
    int compressed = QEMU_SAVE_FORMAT_RAW;
3177 3178
    int ret = -1;
    virDomainObjPtr vm = NULL;
3179
    virQEMUDriverConfigPtr cfg = NULL;
3180

3181 3182 3183
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
3184

3185
    cfg = virQEMUDriverGetConfig(driver);
3186
    if (cfg->saveImageFormat) {
3187
        compressed = qemuSaveCompressionTypeFromString(cfg->saveImageFormat);
3188
        if (compressed < 0) {
3189 3190 3191
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Invalid save image format specified "
                             "in configuration file"));
3192
            goto cleanup;
3193
        }
3194
        if (!qemuCompressProgramAvailable(compressed)) {
3195 3196 3197
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Compression program for image format "
                             "in configuration file isn't available"));
3198
            goto cleanup;
3199
        }
3200 3201
    }

3202
    if (!(vm = qemuDomObjFromDomain(dom)))
3203 3204
        goto cleanup;

3205 3206 3207
    if (virDomainSaveFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3208
    if (!virDomainObjIsActive(vm)) {
3209 3210
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3211 3212 3213
        goto cleanup;
    }

3214
    ret = qemuDomainSaveInternal(driver, dom, vm, path, compressed,
3215
                                 dxml, flags);
3216
    vm = NULL;
3217 3218 3219

cleanup:
    if (vm)
3220
        virObjectUnlock(vm);
3221
    virObjectUnref(cfg);
3222
    return ret;
3223 3224
}

3225 3226 3227 3228 3229 3230
static int
qemuDomainSave(virDomainPtr dom, const char *path)
{
    return qemuDomainSaveFlags(dom, path, NULL, 0);
}

3231
static char *
3232 3233
qemuDomainManagedSavePath(virQEMUDriverPtr driver, virDomainObjPtr vm)
{
3234
    char *ret;
3235
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
3236

3237 3238
    if (virAsprintf(&ret, "%s/%s.save", cfg->saveDir, vm->def->name) < 0) {
        virObjectUnref(cfg);
3239
        return NULL;
3240 3241
    }

3242
    virObjectUnref(cfg);
3243
    return ret;
3244 3245 3246 3247 3248
}

static int
qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
{
3249
    virQEMUDriverPtr driver = dom->conn->privateData;
3250 3251
    virQEMUDriverConfigPtr cfg = NULL;
    int compressed = QEMU_SAVE_FORMAT_RAW;
3252
    virDomainObjPtr vm;
3253 3254 3255
    char *name = NULL;
    int ret = -1;

3256 3257 3258
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
3259

3260
    if (!(vm = qemuDomObjFromDomain(dom)))
3261
        return -1;
3262

3263 3264 3265
    if (virDomainManagedSaveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3266
    if (!virDomainObjIsActive(vm)) {
3267 3268
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3269 3270
        goto cleanup;
    }
3271
    if (!vm->persistent) {
3272 3273
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot do managed save for transient domain"));
3274 3275
        goto cleanup;
    }
3276

3277 3278 3279 3280 3281 3282 3283 3284 3285 3286 3287 3288 3289 3290 3291 3292 3293
    cfg = virQEMUDriverGetConfig(driver);
    if (cfg->saveImageFormat) {
        compressed = qemuSaveCompressionTypeFromString(cfg->saveImageFormat);
        if (compressed < 0) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Invalid save image format specified "
                             "in configuration file"));
            goto cleanup;
        }
        if (!qemuCompressProgramAvailable(compressed)) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Compression program for image format "
                             "in configuration file isn't available"));
            goto cleanup;
        }
    }

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

3297
    VIR_INFO("Saving state of domain '%s' to '%s'", vm->def->name, name);
3298

3299
    if ((ret = qemuDomainSaveInternal(driver, dom, vm, name, compressed,
3300 3301 3302
                                      NULL, flags)) == 0)
        vm->hasManagedSave = true;

3303
    vm = NULL;
3304 3305 3306

cleanup:
    if (vm)
3307
        virObjectUnlock(vm);
3308
    VIR_FREE(name);
3309
    virObjectUnref(cfg);
3310 3311

    return ret;
3312 3313
}

3314 3315
static int
qemuDomainManagedSaveLoad(virDomainObjPtr vm,
3316 3317
                          void *opaque)
{
3318
    virQEMUDriverPtr driver = opaque;
3319
    char *name;
3320
    int ret = -1;
3321

3322
    virObjectLock(vm);
3323 3324 3325 3326 3327 3328

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

    vm->hasManagedSave = virFileExists(name);

3329
    ret = 0;
3330
cleanup:
3331
    virObjectUnlock(vm);
3332
    VIR_FREE(name);
3333
    return ret;
3334 3335
}

3336

3337 3338 3339 3340
static int
qemuDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    virDomainObjPtr vm = NULL;
3341
    int ret = -1;
3342

3343
    virCheckFlags(0, -1);
3344

3345 3346
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
3347

3348 3349 3350
    if (virDomainHasManagedSaveImageEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3351
    ret = vm->hasManagedSave;
3352 3353

cleanup:
3354
    virObjectUnlock(vm);
3355 3356 3357 3358 3359 3360
    return ret;
}

static int
qemuDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
{
3361
    virQEMUDriverPtr driver = dom->conn->privateData;
3362
    virDomainObjPtr vm;
3363 3364 3365
    int ret = -1;
    char *name = NULL;

3366
    virCheckFlags(0, -1);
3367

3368
    if (!(vm = qemuDomObjFromDomain(dom)))
3369
        return -1;
3370

3371 3372 3373
    if (virDomainManagedSaveRemoveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

3377 3378 3379 3380 3381 3382 3383
    if (unlink(name) < 0) {
        virReportSystemError(errno,
                             _("Failed to remove managed save file '%s'"),
                             name);
        goto cleanup;
    }

3384
    vm->hasManagedSave = false;
3385
    ret = 0;
3386 3387 3388

cleanup:
    VIR_FREE(name);
3389
    virObjectUnlock(vm);
3390 3391
    return ret;
}
D
Daniel P. Berrange 已提交
3392

3393
static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm,
3394 3395 3396 3397 3398
                        int fd, enum qemuDomainAsyncJob asyncJob)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;

3399
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY)) {
3400
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3401
                       _("dump-guest-memory is not supported"));
3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413
        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;

3414
    ret = qemuMonitorDumpToFd(priv->mon, fd);
3415
    qemuDomainObjExitMonitor(driver, vm);
3416 3417 3418 3419

    return ret;
}

3420
static int
3421
doCoreDump(virQEMUDriverPtr driver,
3422 3423
           virDomainObjPtr vm,
           const char *path,
3424
           virQEMUSaveFormat compress,
3425
           unsigned int dump_flags)
H
Hu Tao 已提交
3426 3427 3428
{
    int fd = -1;
    int ret = -1;
J
Jiri Denemark 已提交
3429
    virFileWrapperFdPtr wrapperFd = NULL;
3430
    int directFlag = 0;
3431
    unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
H
Hu Tao 已提交
3432 3433

    /* Create an empty file with appropriate ownership.  */
3434
    if (dump_flags & VIR_DUMP_BYPASS_CACHE) {
3435
        flags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
3436 3437
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
3438 3439
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
3440 3441 3442
            goto cleanup;
        }
    }
E
Eric Blake 已提交
3443 3444 3445
    /* Core dumps usually imply last-ditch analysis efforts are
     * desired, so we intentionally do not unlink even if a file was
     * created.  */
3446
    if ((fd = qemuOpenFile(driver, vm, path,
E
Eric Blake 已提交
3447 3448
                           O_CREAT | O_TRUNC | O_WRONLY | directFlag,
                           NULL, NULL)) < 0)
H
Hu Tao 已提交
3449 3450
        goto cleanup;

3451
    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, flags)))
3452 3453
        goto cleanup;

3454 3455 3456 3457 3458 3459 3460 3461 3462
    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)
3463 3464
        goto cleanup;

H
Hu Tao 已提交
3465 3466
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno,
3467
                             _("unable to close file %s"),
H
Hu Tao 已提交
3468 3469 3470
                             path);
        goto cleanup;
    }
J
Jiri Denemark 已提交
3471
    if (virFileWrapperFdClose(wrapperFd) < 0)
3472
        goto cleanup;
H
Hu Tao 已提交
3473

3474
    ret = 0;
H
Hu Tao 已提交
3475 3476

cleanup:
3477
    VIR_FORCE_CLOSE(fd);
3478
    if (ret != 0)
H
Hu Tao 已提交
3479
        unlink(path);
3480
    virFileWrapperFdFree(wrapperFd);
H
Hu Tao 已提交
3481 3482 3483
    return ret;
}

3484
static virQEMUSaveFormat
3485
getCompressionType(virQEMUDriverPtr driver)
3486
{
3487 3488
    int ret = QEMU_SAVE_FORMAT_RAW;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
3489

3490 3491 3492 3493
    /*
     * We reuse "save" flag for "dump" here. Then, we can support the same
     * format in "save" and "dump".
     */
3494 3495
    if (cfg->dumpImageFormat) {
        ret = qemuSaveCompressionTypeFromString(cfg->dumpImageFormat);
3496 3497 3498
        /* Use "raw" as the format if the specified format is not valid,
         * or the compress program is not available.
         */
3499
        if (ret < 0) {
3500 3501
            VIR_WARN("%s", _("Invalid dump image format specified in "
                             "configuration file, using raw"));
3502 3503
            ret = QEMU_SAVE_FORMAT_RAW;
            goto cleanup;
3504
        }
3505
        if (!qemuCompressProgramAvailable(ret)) {
3506 3507 3508
            VIR_WARN("%s", _("Compression program for dump image format "
                             "in configuration file isn't available, "
                             "using raw"));
3509 3510
            ret = QEMU_SAVE_FORMAT_RAW;
            goto cleanup;
3511
        }
3512
    }
3513 3514 3515
cleanup:
    virObjectUnref(cfg);
    return ret;
3516 3517
}

3518 3519 3520
static int qemuDomainCoreDump(virDomainPtr dom,
                              const char *path,
                              unsigned int flags)
3521
{
3522
    virQEMUDriverPtr driver = dom->conn->privateData;
3523
    virDomainObjPtr vm;
M
Michal Privoznik 已提交
3524
    qemuDomainObjPrivatePtr priv;
3525
    bool resume = false, paused = false;
H
Hu Tao 已提交
3526
    int ret = -1;
3527
    virObjectEventPtr event = NULL;
3528

M
Michal Privoznik 已提交
3529
    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH |
3530 3531
                  VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET |
                  VIR_DUMP_MEMORY_ONLY, -1);
3532

3533 3534
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
P
Paolo Bonzini 已提交
3535

3536 3537 3538
    if (virDomainCoreDumpEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3539 3540
    if (qemuDomainObjBeginAsyncJob(driver, vm,
                                   QEMU_ASYNC_JOB_DUMP) < 0)
3541 3542
        goto cleanup;

D
Daniel P. Berrange 已提交
3543
    if (!virDomainObjIsActive(vm)) {
3544 3545
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3546
        goto endjob;
P
Paolo Bonzini 已提交
3547 3548
    }

P
Paolo Bonzini 已提交
3549 3550
    /* Migrate will always stop the VM, so the resume condition is
       independent of whether the stop command is issued.  */
J
Jiri Denemark 已提交
3551
    resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
P
Paolo Bonzini 已提交
3552 3553

    /* Pause domain for non-live dump */
J
Jiri Denemark 已提交
3554 3555
    if (!(flags & VIR_DUMP_LIVE) &&
        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
3556 3557
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_DUMP,
                                QEMU_ASYNC_JOB_DUMP) < 0)
3558
            goto endjob;
3559
        paused = true;
3560 3561

        if (!virDomainObjIsActive(vm)) {
3562 3563
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
3564 3565
            goto endjob;
        }
P
Paolo Bonzini 已提交
3566 3567
    }

3568
    ret = doCoreDump(driver, vm, path, getCompressionType(driver), flags);
3569 3570 3571
    if (ret < 0)
        goto endjob;

3572
    paused = true;
3573 3574

endjob:
3575
    if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
3576
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED, 0);
3577
        virDomainAuditStop(vm, "crashed");
3578
        event = virDomainEventLifecycleNewFromObj(vm,
3579 3580 3581 3582
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
    }

P
Paolo Bonzini 已提交
3583 3584 3585
    /* 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 已提交
3586 3587 3588 3589
    else if (((resume && paused) || (flags & VIR_DUMP_RESET)) &&
             virDomainObjIsActive(vm)) {
        if ((ret == 0) && (flags & VIR_DUMP_RESET)) {
            priv =  vm->privateData;
3590
            qemuDomainObjEnterMonitor(driver, vm);
M
Michal Privoznik 已提交
3591
            ret = qemuMonitorSystemReset(priv->mon);
3592
            qemuDomainObjExitMonitor(driver, vm);
M
Michal Privoznik 已提交
3593 3594 3595 3596 3597
        }

        if (resume && qemuProcessStartCPUs(driver, vm, dom->conn,
                                           VIR_DOMAIN_RUNNING_UNPAUSED,
                                           QEMU_ASYNC_JOB_DUMP) < 0) {
3598
            event = virDomainEventLifecycleNewFromObj(vm,
3599 3600
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
3601
            if (virGetLastError() == NULL)
3602 3603
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
3604 3605
        }
    }
3606

3607
    if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
3608
        vm = NULL;
3609
    else if ((ret == 0) && (flags & VIR_DUMP_CRASH) && !vm->persistent) {
3610
        qemuDomainRemoveInactive(driver, vm);
3611 3612
        vm = NULL;
    }
3613 3614

cleanup:
P
Paolo Bonzini 已提交
3615
    if (vm)
3616
        virObjectUnlock(vm);
3617 3618
    if (event)
        qemuDomainEventQueue(driver, event);
P
Paolo Bonzini 已提交
3619 3620 3621
    return ret;
}

3622 3623 3624 3625
static char *
qemuDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
3626
                     unsigned int flags)
3627
{
3628
    virQEMUDriverPtr driver = dom->conn->privateData;
3629 3630 3631 3632 3633
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    char *tmp = NULL;
    int tmp_fd = -1;
    char *ret = NULL;
E
Eric Blake 已提交
3634
    bool unlink_tmp = false;
3635
    virQEMUDriverConfigPtr cfg = NULL;
3636

E
Eric Blake 已提交
3637 3638
    virCheckFlags(0, NULL);

3639
    if (!(vm = qemuDomObjFromDomain(dom)))
3640 3641 3642
        goto cleanup;

    priv = vm->privateData;
3643
    cfg = virQEMUDriverGetConfig(driver);
3644

3645 3646 3647
    if (virDomainScreenshotEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3648
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
3649 3650 3651
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
3652 3653
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3654 3655 3656 3657 3658 3659
        goto endjob;
    }

    /* Well, even if qemu allows multiple graphic cards, heads, whatever,
     * screenshot command does not */
    if (screen) {
3660 3661 3662
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("currently is supported only taking "
                               "screenshots of screen ID 0"));
3663 3664 3665
        goto endjob;
    }

3666
    if (virAsprintf(&tmp, "%s/qemu.screendump.XXXXXX", cfg->cacheDir) < 0)
3667 3668
        goto endjob;

3669 3670
    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
3671 3672
        goto endjob;
    }
E
Eric Blake 已提交
3673
    unlink_tmp = true;
3674

3675
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
3676

3677
    qemuDomainObjEnterMonitor(driver, vm);
3678
    if (qemuMonitorScreendump(priv->mon, tmp) < 0) {
3679
        qemuDomainObjExitMonitor(driver, vm);
3680 3681
        goto endjob;
    }
3682
    qemuDomainObjExitMonitor(driver, vm);
3683 3684 3685 3686 3687 3688

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

E
Eric Blake 已提交
3689
    if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
3690 3691
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to open stream"));
3692 3693 3694
        goto endjob;
    }

3695
    ignore_value(VIR_STRDUP(ret, "image/x-portable-pixmap"));
3696 3697 3698

endjob:
    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
3699 3700
    if (unlink_tmp)
        unlink(tmp);
E
Eric Blake 已提交
3701
    VIR_FREE(tmp);
3702

E
Eric Blake 已提交
3703
    if (!qemuDomainObjEndJob(driver, vm))
3704 3705 3706 3707
        vm = NULL;

cleanup:
    if (vm)
3708
        virObjectUnlock(vm);
3709
    virObjectUnref(cfg);
3710 3711 3712
    return ret;
}

C
Chen Fan 已提交
3713
static void processWatchdogEvent(virQEMUDriverPtr driver, virDomainObjPtr vm, int action)
H
Hu Tao 已提交
3714 3715
{
    int ret;
C
Chen Fan 已提交
3716
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
W
Wen Congyang 已提交
3717

C
Chen Fan 已提交
3718
    switch (action) {
H
Hu Tao 已提交
3719 3720 3721
    case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
        {
            char *dumpfile;
3722
            unsigned int flags = 0;
H
Hu Tao 已提交
3723

E
Eric Blake 已提交
3724
            if (virAsprintf(&dumpfile, "%s/%s-%u",
3725
                            cfg->autoDumpPath,
C
Chen Fan 已提交
3726
                            vm->def->name,
3727
                            (unsigned int)time(NULL)) < 0)
C
Chen Fan 已提交
3728
                goto cleanup;
H
Hu Tao 已提交
3729

C
Chen Fan 已提交
3730 3731
            if (qemuDomainObjBeginAsyncJob(driver, vm,
                                           QEMU_ASYNC_JOB_DUMP) < 0) {
W
Wen Congyang 已提交
3732
                VIR_FREE(dumpfile);
C
Chen Fan 已提交
3733
                goto cleanup;
W
Wen Congyang 已提交
3734
            }
H
Hu Tao 已提交
3735

C
Chen Fan 已提交
3736
            if (!virDomainObjIsActive(vm)) {
3737 3738
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("domain is not running"));
W
Wen Congyang 已提交
3739 3740
                VIR_FREE(dumpfile);
                goto endjob;
H
Hu Tao 已提交
3741 3742
            }

3743
            flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0;
C
Chen Fan 已提交
3744
            ret = doCoreDump(driver, vm, dumpfile,
3745
                             getCompressionType(driver), flags);
H
Hu Tao 已提交
3746
            if (ret < 0)
3747 3748
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Dump failed"));
H
Hu Tao 已提交
3749

C
Chen Fan 已提交
3750
            ret = qemuProcessStartCPUs(driver, vm, NULL,
3751 3752
                                       VIR_DOMAIN_RUNNING_UNPAUSED,
                                       QEMU_ASYNC_JOB_DUMP);
H
Hu Tao 已提交
3753 3754

            if (ret < 0)
3755 3756
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Resuming after dump failed"));
H
Hu Tao 已提交
3757 3758 3759 3760

            VIR_FREE(dumpfile);
        }
        break;
W
Wen Congyang 已提交
3761
    default:
C
Chen Fan 已提交
3762
        goto cleanup;
H
Hu Tao 已提交
3763 3764
    }

W
Wen Congyang 已提交
3765 3766 3767 3768
endjob:
    /* Safe to ignore value since ref count was incremented in
     * qemuProcessHandleWatchdog().
     */
C
Chen Fan 已提交
3769
    ignore_value(qemuDomainObjEndAsyncJob(driver, vm));
W
Wen Congyang 已提交
3770

C
Chen Fan 已提交
3771
cleanup:
3772
    virObjectUnref(cfg);
H
Hu Tao 已提交
3773
}
P
Paolo Bonzini 已提交
3774

3775 3776 3777 3778 3779 3780 3781 3782 3783 3784 3785 3786 3787 3788 3789 3790 3791 3792
static int
doCoreDumpToAutoDumpPath(virQEMUDriverPtr driver,
                         virDomainObjPtr vm,
                         unsigned int flags)
{
    int ret = -1;
    char *dumpfile = NULL;
    time_t curtime = time(NULL);
    char timestr[100];
    struct tm time_info;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);

    localtime_r(&curtime, &time_info);
    strftime(timestr, sizeof(timestr), "%Y-%m-%d-%H:%M:%S", &time_info);

    if (virAsprintf(&dumpfile, "%s/%s-%s",
                    cfg->autoDumpPath,
                    vm->def->name,
3793
                    timestr) < 0)
3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817 3818 3819 3820 3821 3822 3823 3824 3825
        goto cleanup;

    if (qemuDomainObjBeginAsyncJob(driver, vm,
                                   QEMU_ASYNC_JOB_DUMP) < 0) {
        goto cleanup;
    }

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

    flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0;
    ret = doCoreDump(driver, vm, dumpfile,
                     getCompressionType(driver), flags);
    if (ret < 0)
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("Dump failed"));

endjob:
    /* Safe to ignore value since ref count was incremented in
     * qemuProcessHandleGuestPanic().
     */
    ignore_value(qemuDomainObjEndAsyncJob(driver, vm));

cleanup:
    VIR_FREE(dumpfile);
    virObjectUnref(cfg);
    return ret;
}

3826 3827 3828 3829 3830 3831
static void
processGuestPanicEvent(virQEMUDriverPtr driver,
                       virDomainObjPtr vm,
                       int action)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
3832
    virObjectEventPtr event = NULL;
3833 3834 3835 3836 3837 3838 3839 3840 3841 3842 3843 3844
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);

    if (!virDomainObjIsActive(vm)) {
        VIR_DEBUG("Ignoring GUEST_PANICKED event from inactive domain %s",
                  vm->def->name);
        goto cleanup;
    }

    virDomainObjSetState(vm,
                         VIR_DOMAIN_CRASHED,
                         VIR_DOMAIN_CRASHED_PANICKED);

3845
    event = virDomainEventLifecycleNewFromObj(vm,
3846 3847 3848 3849 3850 3851 3852 3853 3854 3855 3856 3857 3858 3859 3860 3861
                                     VIR_DOMAIN_EVENT_CRASHED,
                                     VIR_DOMAIN_EVENT_CRASHED_PANICKED);

    if (event)
        qemuDomainEventQueue(driver, event);

    if (virDomainLockProcessPause(driver->lockManager, vm, &priv->lockState) < 0)
        VIR_WARN("Unable to release lease on %s", vm->def->name);
    VIR_DEBUG("Preserving lock state '%s'", NULLSTR(priv->lockState));

    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
        VIR_WARN("Unable to save status on vm %s after state change",
                 vm->def->name);
     }

    switch (action) {
3862 3863 3864 3865 3866 3867
    case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_DESTROY:
        if (doCoreDumpToAutoDumpPath(driver, vm, VIR_DUMP_MEMORY_ONLY) < 0) {
            goto cleanup;
        }
        /* fall through */

3868 3869 3870 3871 3872 3873 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884
    case VIR_DOMAIN_LIFECYCLE_CRASH_DESTROY:
        priv->beingDestroyed = true;

        if (qemuProcessKill(vm, VIR_QEMU_PROCESS_KILL_FORCE) < 0) {
            priv->beingDestroyed = false;
            goto cleanup;
        }

        priv->beingDestroyed = false;

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

        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED, 0);
3885
        event = virDomainEventLifecycleNewFromObj(vm,
3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);

        if (event)
            qemuDomainEventQueue(driver, event);

        virDomainAuditStop(vm, "destroyed");

        if (!vm->persistent) {
            qemuDomainRemoveInactive(driver, vm);
        }
        break;

3899 3900 3901 3902 3903 3904
    case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_RESTART:
        if (doCoreDumpToAutoDumpPath(driver, vm, VIR_DUMP_MEMORY_ONLY) < 0) {
            goto cleanup;
        }
        /* fall through */

3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920
    case VIR_DOMAIN_LIFECYCLE_CRASH_RESTART:
        qemuDomainSetFakeReboot(driver, vm, true);
        qemuProcessShutdownOrReboot(driver, vm);
        break;

    case VIR_DOMAIN_LIFECYCLE_CRASH_PRESERVE:
        break;

    default:
        break;
    }

cleanup:
    virObjectUnref(cfg);
}

C
Chen Fan 已提交
3921 3922 3923 3924 3925 3926
static void qemuProcessEventHandler(void *data, void *opaque)
{
    struct qemuProcessEvent *processEvent = data;
    virDomainObjPtr vm = processEvent->vm;
    virQEMUDriverPtr driver = opaque;

3927 3928
    VIR_DEBUG("vm=%p", vm);

C
Chen Fan 已提交
3929 3930 3931 3932 3933 3934
    virObjectLock(vm);

    switch (processEvent->eventType) {
    case QEMU_PROCESS_EVENT_WATCHDOG:
        processWatchdogEvent(driver, vm, processEvent->action);
        break;
3935 3936 3937
    case QEMU_PROCESS_EVENT_GUESTPANIC:
        processGuestPanicEvent(driver, vm, processEvent->action);
        break;
C
Chen Fan 已提交
3938 3939 3940 3941 3942 3943 3944 3945 3946
    default:
       break;
    }

    if (virObjectUnref(vm))
        virObjectUnlock(vm);
    VIR_FREE(processEvent);
}

3947
static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver,
3948 3949
                                  virDomainObjPtr vm,
                                  unsigned int nvcpus)
3950 3951
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
3952 3953
    size_t i;
    int rc = 1;
3954
    int ret = -1;
3955
    int oldvcpus = vm->def->vcpus;
E
Eric Blake 已提交
3956
    int vcpus = oldvcpus;
3957 3958
    pid_t *cpupids = NULL;
    int ncpupids;
3959
    virCgroupPtr cgroup_vcpu = NULL;
3960

3961
    qemuDomainObjEnterMonitor(driver, vm);
3962

3963 3964 3965
    /* 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 已提交
3966
    if (nvcpus > vcpus) {
3967
        for (i = vcpus; i < nvcpus; i++) {
3968
            /* Online new CPU */
3969
            rc = qemuMonitorSetCPU(priv->mon, i, true);
3970 3971 3972 3973 3974
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3975
            vcpus++;
3976 3977
        }
    } else {
3978
        for (i = vcpus - 1; i >= nvcpus; i--) {
3979
            /* Offline old CPU */
3980
            rc = qemuMonitorSetCPU(priv->mon, i, false);
3981 3982 3983 3984 3985
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3986
            vcpus--;
3987 3988 3989
        }
    }

3990 3991
    /* hotplug succeeded */

3992 3993
    ret = 0;

3994 3995 3996 3997 3998 3999 4000 4001 4002 4003
    /* 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;
    }

4004 4005 4006 4007 4008 4009 4010 4011 4012
    /* 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;
    }

4013
    if (ncpupids != vcpus) {
4014 4015 4016 4017
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("got wrong number of vCPU pids from QEMU monitor. "
                         "got %d, wanted %d"),
                       ncpupids, vcpus);
4018
        vcpus = oldvcpus;
4019 4020 4021 4022
        ret = -1;
        goto cleanup;
    }

4023 4024
    if (nvcpus > oldvcpus) {
        for (i = oldvcpus; i < nvcpus; i++) {
4025
            if (priv->cgroup) {
4026
                int rv = -1;
4027
                /* Create cgroup for the onlined vcpu */
4028
                if (virCgroupNewVcpu(priv->cgroup, i, true, &cgroup_vcpu) < 0)
4029 4030 4031 4032 4033 4034
                    goto cleanup;

                /* Add vcpu thread to the cgroup */
                rv = virCgroupAddTask(cgroup_vcpu, cpupids[i]);
                if (rv < 0) {
                    virReportSystemError(-rv,
4035
                                         _("unable to add vcpu %zu task %d to cgroup"),
4036 4037 4038 4039
                                         i, cpupids[i]);
                    virCgroupRemove(cgroup_vcpu);
                    goto cleanup;
                }
4040
            }
4041

4042 4043 4044 4045 4046 4047 4048 4049
            /* 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,
4050
                                  vm->def->cputune.nvcpupin + 1) < 0)
4051 4052
                    goto cleanup;

4053
                if (VIR_ALLOC(vcpupin) < 0)
4054 4055 4056 4057 4058 4059 4060
                    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;

4061
                if (cgroup_vcpu) {
4062 4063 4064 4065 4066
                    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"
4067
                                         " for vcpu %zu"), i);
4068 4069 4070 4071
                        ret = -1;
                        goto cleanup;
                    }
                } else {
4072 4073
                    if (virProcessSetAffinity(cpupids[i],
                                              vcpupin->cpumask) < 0) {
4074
                        virReportError(VIR_ERR_SYSTEM_ERROR,
4075
                                       _("failed to set cpu affinity for vcpu %zu"),
4076 4077 4078 4079 4080
                                       i);
                        ret = -1;
                        goto cleanup;
                    }
                }
4081
            }
4082 4083

            virCgroupFree(&cgroup_vcpu);
G
Guido Günther 已提交
4084
        }
4085 4086 4087 4088
    } else {
        for (i = oldvcpus - 1; i >= nvcpus; i--) {
            virDomainVcpuPinDefPtr vcpupin = NULL;

4089
            if (priv->cgroup) {
4090
                if (virCgroupNewVcpu(priv->cgroup, i, false, &cgroup_vcpu) < 0)
4091 4092 4093 4094 4095 4096 4097
                    goto cleanup;

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

4098 4099 4100 4101 4102
            /* Free vcpupin setting */
            if ((vcpupin = virDomainLookupVcpuPin(vm->def, i))) {
                VIR_FREE(vcpupin);
            }
        }
4103 4104
    }

4105 4106 4107 4108 4109
    priv->nvcpupids = ncpupids;
    VIR_FREE(priv->vcpupids);
    priv->vcpupids = cpupids;
    cpupids = NULL;

4110
cleanup:
4111
    qemuDomainObjExitMonitor(driver, vm);
E
Eric Blake 已提交
4112
    vm->def->vcpus = vcpus;
4113
    VIR_FREE(cpupids);
4114
    virDomainAuditVcpu(vm, oldvcpus, nvcpus, "update", rc == 1);
4115 4116
    if (cgroup_vcpu)
        virCgroupFree(&cgroup_vcpu);
4117 4118 4119
    return ret;

unsupported:
4120 4121
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("cannot change vcpu count of this domain"));
4122 4123 4124 4125
    goto cleanup;
}


4126
static int
4127 4128
qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
4129
{
4130
    virQEMUDriverPtr driver = dom->conn->privateData;
4131
    virDomainObjPtr vm = NULL;
4132
    virDomainDefPtr persistentDef;
4133
    int ret = -1;
4134
    bool maximum;
4135
    unsigned int maxvcpus = 0;
4136
    virQEMUDriverConfigPtr cfg = NULL;
4137
    virCapsPtr caps = NULL;
4138 4139 4140
    qemuAgentCPUInfoPtr cpuinfo = NULL;
    int ncpuinfo;
    qemuDomainObjPrivatePtr priv;
4141

4142 4143
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
4144
                  VIR_DOMAIN_VCPU_MAXIMUM |
4145
                  VIR_DOMAIN_VCPU_GUEST, -1);
4146 4147

    if (!nvcpus || (unsigned short) nvcpus != nvcpus) {
4148 4149
        virReportError(VIR_ERR_INVALID_ARG,
                       _("argument out of range: %d"), nvcpus);
4150 4151 4152
        return -1;
    }

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

4156
    cfg = virQEMUDriverGetConfig(driver);
4157 4158

    if (virDomainSetVcpusFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
4159
        goto cleanup;
4160

4161
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
4162
        goto cleanup;
4163

4164 4165
    priv = vm->privateData;

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

4169 4170 4171
    maximum = (flags & VIR_DOMAIN_VCPU_MAXIMUM) != 0;
    flags &= ~VIR_DOMAIN_VCPU_MAXIMUM;

4172
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
4173 4174
                                        &persistentDef) < 0)
        goto endjob;
4175 4176 4177

    /* MAXIMUM cannot be mixed with LIVE.  */
    if (maximum && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
4178 4179
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("cannot adjust maximum on running domain"));
4180 4181 4182
        goto endjob;
    }

4183 4184 4185 4186 4187 4188 4189
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
        maxvcpus = vm->def->maxvcpus;
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        if (!maxvcpus || maxvcpus > persistentDef->maxvcpus)
            maxvcpus = persistentDef->maxvcpus;
    }
    if (!maximum && nvcpus > maxvcpus) {
4190 4191
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
4192
                         " vcpus for the domain: %d > %d"),
4193
                       nvcpus, maxvcpus);
4194 4195 4196
        goto endjob;
    }

4197
    if (flags & VIR_DOMAIN_VCPU_GUEST) {
4198 4199
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4200
                           _("changing of maximum vCPU count isn't supported "
4201
                             "via guest agent"));
4202
            goto endjob;
4203
        }
4204

4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217
        if (priv->agentError) {
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                           _("QEMU guest agent is not "
                             "available due to an error"));
            goto endjob;
        }

        if (!priv->agent) {
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
            goto endjob;
        }

4218 4219 4220 4221 4222 4223 4224 4225
        if (nvcpus > vm->def->vcpus) {
            virReportError(VIR_ERR_INVALID_ARG,
                           _("requested vcpu count is greater than the count "
                             "of enabled vcpus in the domain: %d > %d"),
                           nvcpus, vm->def->vcpus);
            goto endjob;
        }

4226 4227 4228 4229 4230 4231 4232
        qemuDomainObjEnterAgent(vm);
        ncpuinfo = qemuAgentGetVCPUs(priv->agent, &cpuinfo);
        qemuDomainObjExitAgent(vm);

        if (ncpuinfo < 0)
            goto endjob;

4233
        if (qemuAgentUpdateCPUInfo(nvcpus, cpuinfo, ncpuinfo) < 0)
4234 4235 4236 4237 4238 4239 4240
            goto endjob;

        qemuDomainObjEnterAgent(vm);
        ret = qemuAgentSetVCPUs(priv->agent, cpuinfo, ncpuinfo);
        qemuDomainObjExitAgent(vm);

        if (ret < 0)
4241
            goto endjob;
4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259 4260 4261 4262 4263 4264 4265 4266 4267

        if (ret < ncpuinfo) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("failed to set state of cpu %d via guest agent"),
                           cpuinfo[ret-1].id);
            ret = -1;
            goto endjob;
        }
    } else {
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
            if (qemuDomainHotplugVcpus(driver, vm, nvcpus) < 0)
                goto endjob;
        }

        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
            if (maximum) {
                persistentDef->maxvcpus = nvcpus;
                if (nvcpus < persistentDef->vcpus)
                    persistentDef->vcpus = nvcpus;
            } else {
                persistentDef->vcpus = nvcpus;
            }

            if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
                goto endjob;
        }
4268
    }
4269

4270
    ret = 0;
4271

4272
endjob:
E
Eric Blake 已提交
4273
    if (!qemuDomainObjEndJob(driver, vm))
4274
        vm = NULL;
4275

4276
cleanup:
4277
    if (vm)
4278
        virObjectUnlock(vm);
4279
    virObjectUnref(caps);
4280
    VIR_FREE(cpuinfo);
4281
    virObjectUnref(cfg);
4282
    return ret;
4283 4284
}

4285
static int
4286
qemuDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
4287
{
4288
    return qemuDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
4289 4290
}

4291 4292

static int
4293 4294 4295 4296 4297
qemuDomainPinVcpuFlags(virDomainPtr dom,
                       unsigned int vcpu,
                       unsigned char *cpumap,
                       int maplen,
                       unsigned int flags) {
4298

4299
    virQEMUDriverPtr driver = dom->conn->privateData;
4300
    virDomainObjPtr vm;
4301
    virDomainDefPtr persistentDef = NULL;
4302
    virCgroupPtr cgroup_vcpu = NULL;
4303
    int ret = -1;
4304
    qemuDomainObjPrivatePtr priv;
4305
    bool doReset = false;
4306 4307
    int newVcpuPinNum = 0;
    virDomainVcpuPinDefPtr *newVcpuPin = NULL;
4308
    virBitmapPtr pcpumap = NULL;
4309
    virQEMUDriverConfigPtr cfg = NULL;
4310
    virCapsPtr caps = NULL;
4311

4312 4313 4314
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4315 4316
    cfg = virQEMUDriverGetConfig(driver);

4317
    if (!(vm = qemuDomObjFromDomain(dom)))
4318 4319
        goto cleanup;

4320 4321 4322
    if (virDomainPinVcpuFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4323 4324 4325
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

4326
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
4327
                                        &persistentDef) < 0)
4328
        goto cleanup;
4329

4330 4331 4332
    priv = vm->privateData;

    if (vcpu > (priv->nvcpupids-1)) {
4333 4334 4335
        virReportError(VIR_ERR_INVALID_ARG,
                       _("vcpu number out of range %d > %d"),
                       vcpu, priv->nvcpupids);
4336
        goto cleanup;
4337 4338
    }

4339 4340 4341 4342
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

4343 4344 4345 4346 4347 4348
    if (virBitmapIsAllClear(pcpumap)) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Empty cpu list for pinning"));
        goto cleanup;
    }

4349 4350 4351
    /* pinning to all physical cpus means resetting,
     * so check if we can reset setting.
     */
4352 4353
    if (virBitmapIsAllSet(pcpumap))
        doReset = true;
4354

4355
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4356

4357
        if (priv->vcpupids == NULL) {
4358 4359
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cpu affinity is not supported"));
4360 4361 4362
            goto cleanup;
        }

4363 4364 4365 4366 4367 4368 4369 4370
        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 {
4371
            if (VIR_ALLOC(newVcpuPin) < 0)
4372 4373 4374 4375
                goto cleanup;
            newVcpuPinNum = 0;
        }

4376
        if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, vcpu) < 0) {
4377 4378
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("failed to update vcpupin"));
H
Hu Tao 已提交
4379
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
4380 4381 4382 4383
            goto cleanup;
        }

        /* Configure the corresponding cpuset cgroup before set affinity. */
4384
        if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) {
4385 4386 4387
            if (virCgroupNewVcpu(priv->cgroup, vcpu, false, &cgroup_vcpu) < 0)
                goto cleanup;
            if (qemuSetupCgroupVcpuPin(cgroup_vcpu, newVcpuPin, newVcpuPinNum, vcpu) < 0) {
4388 4389 4390
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("failed to set cpuset.cpus in cgroup"
                                 " for vcpu %d"), vcpu);
4391 4392 4393
                goto cleanup;
            }
        } else {
4394
            if (virProcessSetAffinity(priv->vcpupids[vcpu], pcpumap) < 0) {
4395 4396 4397 4398
                virReportError(VIR_ERR_SYSTEM_ERROR,
                               _("failed to set cpu affinity for vcpu %d"),
                               vcpu);
                goto cleanup;
H
Hu Tao 已提交
4399
            }
4400 4401
        }

4402
        if (doReset) {
4403
            if (virDomainVcpuPinDel(vm->def, vcpu) < 0) {
4404
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4405
                               _("failed to delete vcpupin xml of "
4406
                                 "a running domain"));
4407 4408
                goto cleanup;
            }
4409 4410
        } else {
            if (vm->def->cputune.vcpupin)
H
Hu Tao 已提交
4411
                virDomainVcpuPinDefArrayFree(vm->def->cputune.vcpupin, vm->def->cputune.nvcpupin);
4412 4413 4414 4415

            vm->def->cputune.vcpupin = newVcpuPin;
            vm->def->cputune.nvcpupin = newVcpuPinNum;
            newVcpuPin = NULL;
4416 4417
        }

4418
        if (newVcpuPin)
H
Hu Tao 已提交
4419
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
4420

4421
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
4422
            goto cleanup;
4423
    }
4424

4425 4426
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

4427
        if (doReset) {
E
Eric Blake 已提交
4428
            if (virDomainVcpuPinDel(persistentDef, vcpu) < 0) {
4429 4430 4431
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to delete vcpupin xml of "
                                 "a persistent domain"));
4432 4433 4434
                goto cleanup;
            }
        } else {
H
Hu Tao 已提交
4435
            if (!persistentDef->cputune.vcpupin) {
4436
                if (VIR_ALLOC(persistentDef->cputune.vcpupin) < 0)
H
Hu Tao 已提交
4437 4438 4439
                    goto cleanup;
                persistentDef->cputune.nvcpupin = 0;
            }
4440
            if (virDomainVcpuPinAdd(&persistentDef->cputune.vcpupin,
H
Hu Tao 已提交
4441 4442 4443 4444
                                    &persistentDef->cputune.nvcpupin,
                                    cpumap,
                                    maplen,
                                    vcpu) < 0) {
4445 4446 4447
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update or add vcpupin xml of "
                                 "a persistent domain"));
4448 4449
                goto cleanup;
            }
4450
        }
4451

4452
        ret = virDomainSaveConfig(cfg->configDir, persistentDef);
4453 4454 4455
        goto cleanup;
    }

4456
    ret = 0;
4457

4458
cleanup:
4459 4460
    if (cgroup_vcpu)
        virCgroupFree(&cgroup_vcpu);
4461
    if (vm)
4462
        virObjectUnlock(vm);
4463
    virBitmapFree(pcpumap);
4464
    virObjectUnref(caps);
4465
    virObjectUnref(cfg);
4466
    return ret;
4467 4468
}

4469
static int
4470
qemuDomainPinVcpu(virDomainPtr dom,
4471 4472 4473
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
4474 4475
    return qemuDomainPinVcpuFlags(dom, vcpu, cpumap, maplen,
                                  VIR_DOMAIN_AFFECT_LIVE);
4476 4477
}

4478
static int
4479 4480 4481 4482 4483
qemuDomainGetVcpuPinInfo(virDomainPtr dom,
                         int ncpumaps,
                         unsigned char *cpumaps,
                         int maplen,
                         unsigned int flags) {
4484

4485
    virQEMUDriverPtr driver = dom->conn->privateData;
E
Eric Blake 已提交
4486
    virDomainObjPtr vm = NULL;
4487 4488 4489 4490
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    int maxcpu, hostcpus, vcpu, pcpu;
    int n;
E
Eric Blake 已提交
4491
    virDomainVcpuPinDefPtr *vcpupin_list;
H
Hu Tao 已提交
4492
    virBitmapPtr cpumask = NULL;
4493
    unsigned char *cpumap;
H
Hu Tao 已提交
4494
    bool pinned;
4495
    virCapsPtr caps = NULL;
4496 4497 4498 4499

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4500
    if (!(vm = qemuDomObjFromDomain(dom)))
4501 4502
        goto cleanup;

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

4506 4507 4508
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

4509
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
4510 4511
                                        &targetDef) < 0)
        goto cleanup;
4512 4513 4514 4515 4516

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

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

4520
    if ((hostcpus = nodeGetCPUCount()) < 0)
4521
        goto cleanup;
4522

4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 4547 4548 4549 4550
    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 已提交
4551 4552 4553
            if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0)
                goto cleanup;
            if (!pinned)
4554 4555 4556 4557 4558 4559 4560
                VIR_UNUSE_CPU(cpumap, pcpu);
        }
    }
    ret = ncpumaps;

cleanup:
    if (vm)
4561
        virObjectUnlock(vm);
4562
    virObjectUnref(caps);
4563 4564 4565
    return ret;
}

H
Hu Tao 已提交
4566
static int
4567 4568 4569 4570
qemuDomainPinEmulator(virDomainPtr dom,
                      unsigned char *cpumap,
                      int maplen,
                      unsigned int flags)
H
Hu Tao 已提交
4571
{
4572
    virQEMUDriverPtr driver = dom->conn->privateData;
H
Hu Tao 已提交
4573 4574 4575 4576 4577 4578
    virDomainObjPtr vm;
    virCgroupPtr cgroup_emulator = NULL;
    pid_t pid;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
4579
    bool doReset = false;
H
Hu Tao 已提交
4580 4581
    int newVcpuPinNum = 0;
    virDomainVcpuPinDefPtr *newVcpuPin = NULL;
4582
    virBitmapPtr pcpumap = NULL;
4583
    virQEMUDriverConfigPtr cfg = NULL;
4584
    virCapsPtr caps = NULL;
H
Hu Tao 已提交
4585 4586 4587 4588

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4589 4590
    cfg = virQEMUDriverGetConfig(driver);

4591
    if (!(vm = qemuDomObjFromDomain(dom)))
H
Hu Tao 已提交
4592 4593
        goto cleanup;

4594 4595 4596
    if (virDomainPinEmulatorEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4597 4598 4599
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

4600 4601 4602 4603 4604 4605 4606
    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;
    }

4607
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
H
Hu Tao 已提交
4608 4609 4610 4611 4612
                                        &persistentDef) < 0)
        goto cleanup;

    priv = vm->privateData;

4613 4614 4615 4616
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

4617 4618 4619 4620 4621 4622
    if (virBitmapIsAllClear(pcpumap)) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Empty cpu list for pinning"));
        goto cleanup;
    }

H
Hu Tao 已提交
4623 4624 4625
    /* pinning to all physical cpus means resetting,
     * so check if we can reset setting.
     */
4626 4627
    if (virBitmapIsAllSet(pcpumap))
        doReset = true;
H
Hu Tao 已提交
4628 4629 4630 4631 4632 4633

    pid = vm->pid;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {

        if (priv->vcpupids != NULL) {
4634
            if (VIR_ALLOC(newVcpuPin) < 0)
H
Hu Tao 已提交
4635 4636
                goto cleanup;

4637
            if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, -1) < 0) {
H
Hu Tao 已提交
4638 4639
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update vcpupin"));
H
Hu Tao 已提交
4640
                virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
H
Hu Tao 已提交
4641 4642 4643
                goto cleanup;
            }

4644 4645
            if (virCgroupHasController(priv->cgroup,
                                       VIR_CGROUP_CONTROLLER_CPUSET)) {
H
Hu Tao 已提交
4646 4647 4648
                /*
                 * Configure the corresponding cpuset cgroup.
                 */
4649 4650 4651 4652 4653 4654 4655 4656
                if (virCgroupNewEmulator(priv->cgroup, false, &cgroup_emulator) < 0)
                    goto cleanup;
                if (qemuSetupCgroupEmulatorPin(cgroup_emulator,
                                               newVcpuPin[0]->cpumask) < 0) {
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("failed to set cpuset.cpus in cgroup"
                                     " for emulator threads"));
                    goto cleanup;
H
Hu Tao 已提交
4657 4658
                }
            } else {
4659
                if (virProcessSetAffinity(pid, pcpumap) < 0) {
H
Hu Tao 已提交
4660 4661 4662 4663 4664 4665 4666
                    virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
                                   _("failed to set cpu affinity for "
                                     "emulator threads"));
                    goto cleanup;
                }
            }

4667
            if (doReset) {
H
Hu Tao 已提交
4668 4669 4670 4671 4672 4673 4674
                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 已提交
4675
                virDomainVcpuPinDefFree(vm->def->cputune.emulatorpin);
H
Hu Tao 已提交
4676 4677 4678 4679 4680
                vm->def->cputune.emulatorpin = newVcpuPin[0];
                VIR_FREE(newVcpuPin);
            }

            if (newVcpuPin)
H
Hu Tao 已提交
4681
                virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
H
Hu Tao 已提交
4682 4683 4684 4685 4686 4687
        } else {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cpu affinity is not supported"));
            goto cleanup;
        }

4688
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
H
Hu Tao 已提交
4689 4690 4691 4692 4693
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

4694
        if (doReset) {
H
Hu Tao 已提交
4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709
            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;
            }
        }

4710
        ret = virDomainSaveConfig(cfg->configDir, persistentDef);
H
Hu Tao 已提交
4711 4712 4713 4714 4715 4716 4717 4718
        goto cleanup;
    }

    ret = 0;

cleanup:
    if (cgroup_emulator)
        virCgroupFree(&cgroup_emulator);
4719
    virBitmapFree(pcpumap);
4720
    virObjectUnref(caps);
H
Hu Tao 已提交
4721
    if (vm)
4722
        virObjectUnlock(vm);
4723
    virObjectUnref(cfg);
H
Hu Tao 已提交
4724 4725 4726 4727
    return ret;
}

static int
4728 4729 4730 4731
qemuDomainGetEmulatorPinInfo(virDomainPtr dom,
                             unsigned char *cpumaps,
                             int maplen,
                             unsigned int flags)
H
Hu Tao 已提交
4732
{
4733
    virQEMUDriverPtr driver = dom->conn->privateData;
H
Hu Tao 已提交
4734 4735 4736 4737
    virDomainObjPtr vm = NULL;
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    int maxcpu, hostcpus, pcpu;
H
Hu Tao 已提交
4738 4739
    virBitmapPtr cpumask = NULL;
    bool pinned;
4740
    virCapsPtr caps = NULL;
H
Hu Tao 已提交
4741 4742 4743 4744

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4745
    if (!(vm = qemuDomObjFromDomain(dom)))
H
Hu Tao 已提交
4746 4747
        goto cleanup;

4748 4749 4750
    if (virDomainGetEmulatorPinInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4751 4752 4753
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

4754
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
4755
                                        vm, &flags, &targetDef) < 0)
H
Hu Tao 已提交
4756 4757 4758 4759 4760 4761 4762 4763
        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);

4764
    if ((hostcpus = nodeGetCPUCount()) < 0)
H
Hu Tao 已提交
4765
        goto cleanup;
4766

H
Hu Tao 已提交
4767 4768 4769 4770 4771 4772 4773 4774 4775 4776
    maxcpu = maplen * 8;
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;

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

4777 4778 4779 4780 4781
    if (targetDef->cputune.emulatorpin) {
        cpumask = targetDef->cputune.emulatorpin->cpumask;
    } else if (targetDef->cpumask) {
        cpumask = targetDef->cpumask;
    } else {
H
Hu Tao 已提交
4782 4783 4784 4785 4786
        ret = 0;
        goto cleanup;
    }

    for (pcpu = 0; pcpu < maxcpu; pcpu++) {
H
Hu Tao 已提交
4787 4788 4789
        if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0)
            goto cleanup;
        if (!pinned)
H
Hu Tao 已提交
4790 4791 4792 4793 4794 4795 4796
            VIR_UNUSE_CPU(cpumaps, pcpu);
    }

    ret = 1;

cleanup:
    if (vm)
4797
        virObjectUnlock(vm);
4798
    virObjectUnref(caps);
H
Hu Tao 已提交
4799 4800 4801
    return ret;
}

4802
static int
4803 4804 4805 4806 4807
qemuDomainGetVcpus(virDomainPtr dom,
                   virVcpuInfoPtr info,
                   int maxinfo,
                   unsigned char *cpumaps,
                   int maplen) {
4808
    virDomainObjPtr vm;
4809 4810
    size_t i;
    int v, maxcpu, hostcpus;
4811
    int ret = -1;
4812
    qemuDomainObjPrivatePtr priv;
4813

4814
    if (!(vm = qemuDomObjFromDomain(dom)))
4815 4816
        goto cleanup;

4817 4818 4819
    if (virDomainGetVcpusEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
4820
    if (!virDomainObjIsActive(vm)) {
4821 4822 4823
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s",
                       _("cannot list vcpu pinning for an inactive domain"));
4824
        goto cleanup;
4825 4826
    }

4827 4828
    priv = vm->privateData;

4829
    if ((hostcpus = nodeGetCPUCount()) < 0)
4830
        goto cleanup;
4831 4832

    maxcpu = maplen * 8;
4833 4834
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
4835 4836

    /* Clamp to actual number of vcpus */
4837 4838
    if (maxinfo > priv->nvcpupids)
        maxinfo = priv->nvcpupids;
4839

4840 4841 4842
    if (maxinfo >= 1) {
        if (info != NULL) {
            memset(info, 0, sizeof(*info) * maxinfo);
4843
            for (i = 0; i < maxinfo; i++) {
4844 4845
                info[i].number = i;
                info[i].state = VIR_VCPU_RUNNING;
4846

4847
                if (priv->vcpupids != NULL &&
4848 4849 4850 4851 4852
                    qemuGetProcessInfo(&(info[i].cpuTime),
                                       &(info[i].cpu),
                                       NULL,
                                       vm->pid,
                                       priv->vcpupids[i]) < 0) {
4853
                    virReportSystemError(errno, "%s",
4854 4855 4856
                                         _("cannot get vCPU placement & pCPU time"));
                    goto cleanup;
                }
4857
            }
4858 4859
        }

4860 4861
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
4862
            if (priv->vcpupids != NULL) {
4863
                for (v = 0; v < maxinfo; v++) {
4864
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);
4865 4866 4867
                    virBitmapPtr map = NULL;
                    unsigned char *tmpmap = NULL;
                    int tmpmapLen = 0;
4868

4869 4870
                    if (virProcessGetAffinity(priv->vcpupids[v],
                                              &map, maxcpu) < 0)
4871
                        goto cleanup;
4872 4873 4874 4875 4876 4877 4878
                    virBitmapToData(map, &tmpmap, &tmpmapLen);
                    if (tmpmapLen > maplen)
                        tmpmapLen = maplen;
                    memcpy(cpumap, tmpmap, tmpmapLen);

                    VIR_FREE(tmpmap);
                    virBitmapFree(map);
4879
                }
4880
            } else {
4881 4882
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("cpu affinity is not available"));
4883
                goto cleanup;
4884 4885 4886
            }
        }
    }
4887
    ret = maxinfo;
4888

4889
cleanup:
4890
    if (vm)
4891
        virObjectUnlock(vm);
4892
    return ret;
4893 4894 4895
}


4896
static int
4897
qemuDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
4898
{
4899
    virQEMUDriverPtr driver = dom->conn->privateData;
4900
    qemuDomainObjPrivatePtr priv;
4901
    virDomainObjPtr vm;
4902
    virDomainDefPtr def;
4903
    int ret = -1;
4904
    virCapsPtr caps = NULL;
4905
    qemuAgentCPUInfoPtr cpuinfo = NULL;
4906
    int ncpuinfo = -1;
4907
    size_t i;
4908

4909 4910
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
4911
                  VIR_DOMAIN_VCPU_MAXIMUM |
4912
                  VIR_DOMAIN_VCPU_GUEST, -1);
4913

4914
    if (!(vm = qemuDomObjFromDomain(dom)))
4915 4916 4917
        return -1;

    priv = vm->privateData;
4918

4919
    if (virDomainGetVcpusFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
4920 4921
        goto cleanup;

4922 4923 4924
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

4925
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
4926
                                        vm, &flags, &def) < 0)
4927
        goto cleanup;
4928

4929
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
4930
        def = vm->def;
4931

4932
    if (flags & VIR_DOMAIN_VCPU_GUEST) {
4933 4934 4935 4936 4937 4938 4939 4940 4941 4942
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("vCPU count provided by the guest agent can only be "
                             " requested for live domains"));
            goto cleanup;
        }

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

4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955
        if (priv->agentError) {
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                           _("QEMU guest agent is not "
                             "available due to an error"));
            goto endjob;
        }

        if (!priv->agent) {
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
            goto endjob;
        }

4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966
        if (!virDomainObjIsActive(vm)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("domain is not running"));
            goto endjob;
        }

        qemuDomainObjEnterAgent(vm);
        ncpuinfo = qemuAgentGetVCPUs(priv->agent, &cpuinfo);
        qemuDomainObjExitAgent(vm);

endjob:
E
Eric Blake 已提交
4967
        if (!qemuDomainObjEndJob(driver, vm))
4968 4969 4970 4971 4972 4973 4974 4975 4976 4977 4978 4979 4980 4981 4982 4983 4984 4985 4986 4987 4988
            vm = NULL;

        if (ncpuinfo < 0)
            goto cleanup;

        if (flags & VIR_DOMAIN_VCPU_MAXIMUM) {
            ret = ncpuinfo;
            goto cleanup;
        }

        /* count the online vcpus */
        ret = 0;
        for (i = 0; i < ncpuinfo; i++) {
            if (cpuinfo[i].online)
                ret++;
        }
    } else {
        if (flags & VIR_DOMAIN_VCPU_MAXIMUM)
            ret = def->maxvcpus;
        else
            ret = def->vcpus;
4989 4990 4991
    }


4992
cleanup:
4993
    if (vm)
4994
        virObjectUnlock(vm);
4995
    virObjectUnref(caps);
4996
    VIR_FREE(cpuinfo);
4997 4998 4999
    return ret;
}

5000
static int
5001
qemuDomainGetMaxVcpus(virDomainPtr dom)
5002
{
5003 5004
    return qemuDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
                                         VIR_DOMAIN_VCPU_MAXIMUM));
5005 5006
}

5007
static int qemuDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
5008
{
5009
    virQEMUDriverPtr driver = dom->conn->privateData;
5010 5011 5012
    virDomainObjPtr vm;
    int ret = -1;

5013 5014
    memset(seclabel, 0, sizeof(*seclabel));

5015 5016
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
5017

5018 5019 5020
    if (virDomainGetSecurityLabelEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

5021
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
5022 5023 5024
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041
        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 已提交
5042
    if (virDomainObjIsActive(vm)) {
5043
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
5044
                                              vm->def, vm->pid, seclabel) < 0) {
5045 5046
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to get security label"));
5047
            goto cleanup;
5048 5049 5050 5051 5052 5053 5054
        }
    }

    ret = 0;

cleanup:
    if (vm)
5055
        virObjectUnlock(vm);
5056 5057 5058
    return ret;
}

M
Marcelo Cerri 已提交
5059 5060 5061
static int qemuDomainGetSecurityLabelList(virDomainPtr dom,
                                          virSecurityLabelPtr* seclabels)
{
5062
    virQEMUDriverPtr driver = dom->conn->privateData;
M
Marcelo Cerri 已提交
5063
    virDomainObjPtr vm;
5064 5065
    size_t i;
    int ret = -1;
M
Marcelo Cerri 已提交
5066

5067 5068
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
M
Marcelo Cerri 已提交
5069

5070 5071 5072
    if (virDomainGetSecurityLabelListEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

M
Marcelo Cerri 已提交
5073 5074 5075 5076 5077 5078 5079 5080
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
        goto cleanup;
    }

    /*
5081
     * Check the comment in qemuDomainGetSecurityLabel function.
M
Marcelo Cerri 已提交
5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 5119 5120
     */
    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) {
            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)
5121
        virObjectUnlock(vm);
M
Marcelo Cerri 已提交
5122 5123
    return ret;
}
5124 5125


5126 5127
static int qemuNodeGetSecurityModel(virConnectPtr conn,
                                    virSecurityModelPtr secmodel)
5128
{
5129
    virQEMUDriverPtr driver = conn->privateData;
5130
    char *p;
5131
    int ret = 0;
5132
    virCapsPtr caps = NULL;
5133

5134 5135
    memset(secmodel, 0, sizeof(*secmodel));

5136 5137 5138
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

5139 5140 5141
    if (virNodeGetSecurityModelEnsureACL(conn) < 0)
        goto cleanup;

5142
    /* We treat no driver as success, but simply return no data in *secmodel */
5143 5144
    if (caps->host.nsecModels == 0 ||
        caps->host.secModels[0].model == NULL)
5145
        goto cleanup;
5146

5147
    p = caps->host.secModels[0].model;
5148
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
5149 5150 5151
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security model string exceeds max %d bytes"),
                       VIR_SECURITY_MODEL_BUFLEN-1);
5152 5153
        ret = -1;
        goto cleanup;
5154 5155 5156
    }
    strcpy(secmodel->model, p);

5157
    p = caps->host.secModels[0].doi;
5158
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
5159 5160 5161
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security DOI string exceeds max %d bytes"),
                       VIR_SECURITY_DOI_BUFLEN-1);
5162 5163
        ret = -1;
        goto cleanup;
5164 5165
    }
    strcpy(secmodel->doi, p);
5166 5167

cleanup:
5168
    virObjectUnref(caps);
5169
    return ret;
5170 5171
}

E
Eric Blake 已提交
5172
/* Return -1 on most failures after raising error, -2 if edit was specified
5173 5174 5175
 * 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.  */
5176
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
5177
qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
5178 5179
                        const char *path,
                        virDomainDefPtr *ret_def,
5180
                        virQEMUSaveHeaderPtr ret_header,
J
Jiri Denemark 已提交
5181 5182
                        bool bypass_cache,
                        virFileWrapperFdPtr *wrapperFd,
5183 5184
                        const char *xmlin, int state, bool edit,
                        bool unlink_corrupt)
J
Jiri Denemark 已提交
5185
{
W
Wen Congyang 已提交
5186
    int fd = -1;
5187
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
5188 5189
    char *xml = NULL;
    virDomainDefPtr def = NULL;
5190
    int oflags = edit ? O_RDWR : O_RDONLY;
5191
    virCapsPtr caps = NULL;
5192

5193
    if (bypass_cache) {
5194
        int directFlag = virFileDirectFdFlag();
5195
        if (directFlag < 0) {
5196 5197
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
5198 5199
            goto error;
        }
5200
        oflags |= directFlag;
5201
    }
5202

5203 5204 5205
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto error;

5206
    if ((fd = qemuOpenFile(driver, NULL, path, oflags, NULL, NULL)) < 0)
E
Eric Blake 已提交
5207
        goto error;
J
Jiri Denemark 已提交
5208 5209 5210
    if (bypass_cache &&
        !(*wrapperFd = virFileWrapperFdNew(&fd, path,
                                           VIR_FILE_WRAPPER_BYPASS_CACHE)))
5211
        goto error;
5212 5213

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
5214 5215 5216 5217 5218 5219 5220 5221 5222
        if (unlink_corrupt) {
            if (VIR_CLOSE(fd) < 0 || unlink(path) < 0) {
                virReportSystemError(errno,
                                     _("cannot remove corrupt file: %s"),
                                     path);
                goto error;
            }
            return -3;
        }
5223 5224
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to read qemu header"));
J
Jiri Denemark 已提交
5225
        goto error;
5226 5227
    }

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

5231
        if (memcmp(header.magic, QEMU_SAVE_PARTIAL,
E
Eric Blake 已提交
5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243
                   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;
            }
        }
5244
        virReportError(VIR_ERR_OPERATION_FAILED, "%s", msg);
J
Jiri Denemark 已提交
5245
        goto error;
5246 5247
    }

5248
    if (header.version > QEMU_SAVE_VERSION) {
5249 5250 5251 5252
        /* convert endianess and try again */
        bswap_header(&header);
    }

5253
    if (header.version > QEMU_SAVE_VERSION) {
5254 5255
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("image version is not supported (%d > %d)"),
5256
                       header.version, QEMU_SAVE_VERSION);
J
Jiri Denemark 已提交
5257
        goto error;
5258 5259
    }

5260
    if (header.xml_len <= 0) {
5261 5262
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("invalid XML length: %d"), header.xml_len);
J
Jiri Denemark 已提交
5263
        goto error;
5264 5265
    }

5266
    if (VIR_ALLOC_N(xml, header.xml_len) < 0)
J
Jiri Denemark 已提交
5267
        goto error;
5268 5269

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
5270 5271
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to read XML"));
J
Jiri Denemark 已提交
5272
        goto error;
5273 5274
    }

5275 5276
    if (edit && STREQ(xml, xmlin) &&
        (state < 0 || state == header.was_running)) {
5277 5278 5279 5280 5281 5282 5283
        VIR_FREE(xml);
        if (VIR_CLOSE(fd) < 0) {
            virReportSystemError(errno, _("cannot close file: %s"), path);
            goto error;
        }
        return -2;
    }
5284 5285
    if (state >= 0)
        header.was_running = state;
5286

5287
    /* Create a domain from this XML */
5288
    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
M
Matthias Bolte 已提交
5289
                                        QEMU_EXPECTED_VIRT_TYPES,
5290
                                        VIR_DOMAIN_XML_INACTIVE)))
J
Jiri Denemark 已提交
5291
        goto error;
5292 5293
    if (xmlin) {
        virDomainDefPtr def2 = NULL;
5294
        virDomainDefPtr newdef = NULL;
5295

5296
        if (!(def2 = virDomainDefParseString(xmlin, caps, driver->xmlopt,
5297 5298 5299
                                             QEMU_EXPECTED_VIRT_TYPES,
                                             VIR_DOMAIN_XML_INACTIVE)))
            goto error;
5300 5301

        newdef = qemuDomainDefCopy(driver, def2, VIR_DOMAIN_XML_MIGRATABLE);
5302 5303
        if (!newdef) {
            virDomainDefFree(def2);
5304
            goto error;
5305
        }
5306 5307 5308

        if (!virDomainDefCheckABIStability(def, newdef)) {
            virDomainDefFree(newdef);
5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324
            virResetLastError();

            /* Due to a bug in older version of external snapshot creation
             * code, the XML saved in the save image was not a migratable
             * XML. To ensure backwards compatibility with the change of the
             * saved XML type, we need to check the ABI compatibility against
             * the user provided XML if the check against the migratable XML
             * fails. Snapshots created prior to v1.1.3 have this issue. */
            if (!virDomainDefCheckABIStability(def, def2)) {
                virDomainDefFree(def2);
                goto error;
            }

            /* use the user provided XML */
            newdef = def2;
            def2 = NULL;
5325 5326
        } else {
            virDomainDefFree(def2);
5327
        }
5328

5329
        virDomainDefFree(def);
5330
        def = newdef;
5331
    }
5332

J
Jiri Denemark 已提交
5333
    VIR_FREE(xml);
5334

J
Jiri Denemark 已提交
5335 5336
    *ret_def = def;
    *ret_header = header;
5337

5338 5339
    virObjectUnref(caps);

J
Jiri Denemark 已提交
5340
    return fd;
5341

J
Jiri Denemark 已提交
5342 5343 5344
error:
    virDomainDefFree(def);
    VIR_FREE(xml);
5345
    VIR_FORCE_CLOSE(fd);
5346
    virObjectUnref(caps);
J
Jiri Denemark 已提交
5347 5348 5349 5350

    return -1;
}

5351 5352
static int ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(6)
qemuDomainSaveImageStartVM(virConnectPtr conn,
5353
                           virQEMUDriverPtr driver,
5354 5355
                           virDomainObjPtr vm,
                           int *fd,
E
Eric Blake 已提交
5356
                           const virQEMUSaveHeader *header,
5357 5358
                           const char *path,
                           bool start_paused)
J
Jiri Denemark 已提交
5359 5360
{
    int ret = -1;
5361
    virObjectEventPtr event;
J
Jiri Denemark 已提交
5362
    int intermediatefd = -1;
5363
    virCommandPtr cmd = NULL;
5364
    char *errbuf = NULL;
5365
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
J
Jiri Denemark 已提交
5366

5367 5368 5369
    if ((header->version == 2) &&
        (header->compressed != QEMU_SAVE_FORMAT_RAW)) {
        if (!(cmd = qemuCompressGetCommand(header->compressed)))
5370
            goto cleanup;
5371

5372 5373
        intermediatefd = *fd;
        *fd = -1;
5374

5375 5376 5377 5378
        virCommandSetInputFD(cmd, intermediatefd);
        virCommandSetOutputFD(cmd, fd);
        virCommandSetErrorBuffer(cmd, &errbuf);
        virCommandDoAsyncIO(cmd);
5379

5380 5381 5382
        if (virCommandRunAsync(cmd, NULL) < 0) {
            *fd = intermediatefd;
            goto cleanup;
5383 5384
        }
    }
J
Jiri Denemark 已提交
5385

5386
    /* Set the migration source and start it up. */
5387 5388 5389
    ret = qemuProcessStart(conn, driver, vm, "stdio", *fd, path, NULL,
                           VIR_NETDEV_VPORT_PROFILE_OP_RESTORE,
                           VIR_QEMU_PROCESS_START_PAUSED);
J
Jiri Denemark 已提交
5390

5391
    if (intermediatefd != -1) {
5392
        if (ret < 0) {
5393 5394 5395
            /* if there was an error setting up qemu, the intermediate
             * process will wait forever to write to stdout, so we
             * must manually kill it.
5396 5397
             */
            VIR_FORCE_CLOSE(intermediatefd);
5398
            VIR_FORCE_CLOSE(*fd);
5399 5400
        }

5401 5402
        if (virCommandWait(cmd, NULL) < 0) {
            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, 0);
5403
            ret = -1;
5404
        }
5405
        VIR_DEBUG("Decompression binary stderr: %s", NULLSTR(errbuf));
5406
    }
5407
    VIR_FORCE_CLOSE(intermediatefd);
J
Jiri Denemark 已提交
5408

5409 5410 5411
    if (VIR_CLOSE(*fd) < 0) {
        virReportSystemError(errno, _("cannot close file: %s"), path);
        ret = -1;
5412
    }
J
Jiri Denemark 已提交
5413

5414
    if (ret < 0) {
5415
        virDomainAuditStart(vm, "restored", false);
5416
        goto cleanup;
5417
    }
5418

5419
    event = virDomainEventLifecycleNewFromObj(vm,
5420 5421
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
5422
    virDomainAuditStart(vm, "restored", true);
J
Jiri Denemark 已提交
5423 5424 5425
    if (event)
        qemuDomainEventQueue(driver, event);

5426

5427 5428
    /* If it was running before, resume it now unless caller requested pause. */
    if (header->was_running && !start_paused) {
J
Jiri Denemark 已提交
5429
        if (qemuProcessStartCPUs(driver, vm, conn,
5430 5431
                                 VIR_DOMAIN_RUNNING_RESTORED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
5432
            if (virGetLastError() == NULL)
5433 5434
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("failed to resume domain"));
5435
            goto cleanup;
5436
        }
5437
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
5438
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
5439
            goto cleanup;
5440
        }
5441 5442 5443
    } else {
        int detail = (start_paused ? VIR_DOMAIN_EVENT_SUSPENDED_PAUSED :
                      VIR_DOMAIN_EVENT_SUSPENDED_RESTORED);
5444
        event = virDomainEventLifecycleNewFromObj(vm,
5445 5446 5447 5448
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         detail);
        if (event)
            qemuDomainEventQueue(driver, event);
5449
    }
J
Jiri Denemark 已提交
5450

5451
    ret = 0;
5452

5453
cleanup:
5454
    virCommandFree(cmd);
5455
    VIR_FREE(errbuf);
5456
    if (virSecurityManagerRestoreSavedStateLabel(driver->securityManager,
5457
                                                 vm->def, path) < 0)
5458
        VIR_WARN("failed to restore save state label on %s", path);
5459
    virObjectUnref(cfg);
J
Jiri Denemark 已提交
5460 5461 5462
    return ret;
}

5463
static int
5464 5465 5466 5467
qemuDomainRestoreFlags(virConnectPtr conn,
                       const char *path,
                       const char *dxml,
                       unsigned int flags)
5468
{
5469
    virQEMUDriverPtr driver = conn->privateData;
J
Jiri Denemark 已提交
5470 5471 5472 5473
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    int fd = -1;
    int ret = -1;
5474
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
5475
    virFileWrapperFdPtr wrapperFd = NULL;
5476
    int state = -1;
J
Jiri Denemark 已提交
5477

5478 5479 5480
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
5481

J
Jiri Denemark 已提交
5482

5483 5484 5485 5486 5487
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

5488 5489
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
                                 (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
J
Jiri Denemark 已提交
5490
                                 &wrapperFd, dxml, state, false, false);
J
Jiri Denemark 已提交
5491 5492 5493
    if (fd < 0)
        goto cleanup;

5494 5495 5496
    if (virDomainRestoreFlagsEnsureACL(conn, def) < 0)
        goto cleanup;

5497
    if (!(vm = virDomainObjListAdd(driver->domains, def,
5498
                                   driver->xmlopt,
5499 5500 5501
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
J
Jiri Denemark 已提交
5502 5503 5504
        goto cleanup;
    def = NULL;

5505
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
J
Jiri Denemark 已提交
5506 5507
        goto cleanup;

5508 5509
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     false);
J
Jiri Denemark 已提交
5510
    if (virFileWrapperFdClose(wrapperFd) < 0)
5511
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
5512

E
Eric Blake 已提交
5513
    if (!qemuDomainObjEndJob(driver, vm))
5514
        vm = NULL;
J
Jiri Denemark 已提交
5515
    else if (ret < 0 && !vm->persistent) {
5516
        qemuDomainRemoveInactive(driver, vm);
J
Jiri Denemark 已提交
5517 5518
        vm = NULL;
    }
5519

5520 5521
cleanup:
    virDomainDefFree(def);
5522
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
5523
    virFileWrapperFdFree(wrapperFd);
5524
    if (vm)
5525
        virObjectUnlock(vm);
5526
    return ret;
D
Daniel P. Berrange 已提交
5527 5528
}

5529 5530 5531 5532 5533 5534 5535
static int
qemuDomainRestore(virConnectPtr conn,
                  const char *path)
{
    return qemuDomainRestoreFlags(conn, path, NULL, 0);
}

5536 5537 5538 5539
static char *
qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
                              unsigned int flags)
{
5540
    virQEMUDriverPtr driver = conn->privateData;
5541 5542 5543
    char *ret = NULL;
    virDomainDefPtr def = NULL;
    int fd = -1;
5544
    virQEMUSaveHeader header;
5545 5546 5547 5548 5549

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

    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
5550
                                 NULL, -1, false, false);
5551 5552 5553 5554

    if (fd < 0)
        goto cleanup;

5555 5556 5557
    if (virDomainSaveImageGetXMLDescEnsureACL(conn, def) < 0)
        goto cleanup;

5558
    ret = qemuDomainDefFormatXML(driver, def, flags);
5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569

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

static int
qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path,
                             const char *dxml, unsigned int flags)
{
5570
    virQEMUDriverPtr driver = conn->privateData;
5571 5572 5573
    int ret = -1;
    virDomainDefPtr def = NULL;
    int fd = -1;
5574
    virQEMUSaveHeader header;
5575 5576
    char *xml = NULL;
    size_t len;
5577
    int state = -1;
5578

5579 5580
    virCheckFlags(VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
5581

5582 5583 5584 5585 5586
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

5587
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
5588
                                 dxml, state, true, false);
5589 5590 5591 5592 5593 5594 5595 5596

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

5597 5598 5599
    if (virDomainSaveImageDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

5600 5601
    xml = qemuDomainDefFormatXML(driver, def,
                                 VIR_DOMAIN_XML_INACTIVE |
5602 5603
                                 VIR_DOMAIN_XML_SECURE |
                                 VIR_DOMAIN_XML_MIGRATABLE);
5604 5605 5606 5607 5608
    if (!xml)
        goto cleanup;
    len = strlen(xml) + 1;

    if (len > header.xml_len) {
5609 5610
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("new xml too large to fit in file"));
5611 5612
        goto cleanup;
    }
5613
    if (VIR_EXPAND_N(xml, len, header.xml_len - len) < 0)
5614 5615
        goto cleanup;

5616
    if (lseek(fd, 0, SEEK_SET) != 0) {
5617 5618 5619
        virReportSystemError(errno, _("cannot seek in '%s'"), path);
        goto cleanup;
    }
5620 5621
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header) ||
        safewrite(fd, xml, len) != len ||
5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635
        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);
    return ret;
}

E
Eric Blake 已提交
5636 5637
/* Return 0 on success, 1 if incomplete saved image was silently unlinked,
 * and -1 on failure with error raised.  */
5638 5639
static int
qemuDomainObjRestore(virConnectPtr conn,
5640
                     virQEMUDriverPtr driver,
5641
                     virDomainObjPtr vm,
5642
                     const char *path,
5643
                     bool start_paused,
5644
                     bool bypass_cache)
J
Jiri Denemark 已提交
5645 5646 5647 5648
{
    virDomainDefPtr def = NULL;
    int fd = -1;
    int ret = -1;
5649
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
5650
    virFileWrapperFdPtr wrapperFd = NULL;
J
Jiri Denemark 已提交
5651

5652
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
J
Jiri Denemark 已提交
5653
                                 bypass_cache, &wrapperFd, NULL, -1, false,
5654
                                 true);
E
Eric Blake 已提交
5655 5656 5657
    if (fd < 0) {
        if (fd == -3)
            ret = 1;
J
Jiri Denemark 已提交
5658
        goto cleanup;
E
Eric Blake 已提交
5659
    }
J
Jiri Denemark 已提交
5660 5661 5662 5663 5664 5665 5666

    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);
5667 5668 5669 5670 5671
        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 已提交
5672 5673 5674
        goto cleanup;
    }

5675
    virDomainObjAssignDef(vm, def, true, NULL);
J
Jiri Denemark 已提交
5676 5677
    def = NULL;

5678 5679
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     start_paused);
J
Jiri Denemark 已提交
5680
    if (virFileWrapperFdClose(wrapperFd) < 0)
5681
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
5682 5683 5684

cleanup:
    virDomainDefFree(def);
5685
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
5686
    virFileWrapperFdFree(wrapperFd);
J
Jiri Denemark 已提交
5687 5688 5689
    return ret;
}

D
Daniel P. Berrange 已提交
5690

5691
static char *qemuDomainGetXMLDesc(virDomainPtr dom,
5692 5693
                                  unsigned int flags)
{
5694
    virQEMUDriverPtr driver = dom->conn->privateData;
5695 5696
    virDomainObjPtr vm;
    char *ret = NULL;
5697
    unsigned long long balloon;
5698
    int err = 0;
5699
    qemuDomainObjPrivatePtr priv;
5700

5701
    /* Flags checked by virDomainDefFormat */
5702

5703
    if (!(vm = qemuDomObjFromDomain(dom)))
5704
        goto cleanup;
D
Daniel P. Berrange 已提交
5705

5706 5707
    priv = vm->privateData;

5708 5709 5710
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

5711 5712 5713
    /* Refresh current memory based on balloon info if supported */
    if ((vm->def->memballoon != NULL) &&
        (vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) &&
5714
        !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT) &&
5715
        (virDomainObjIsActive(vm))) {
5716 5717
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
5718
        if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
5719
            if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
5720 5721
                goto cleanup;

5722
            if (!virDomainObjIsActive(vm)) {
5723 5724
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("domain is not running"));
5725 5726 5727
                goto endjob;
            }

5728
            qemuDomainObjEnterMonitor(driver, vm);
5729
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
5730
            qemuDomainObjExitMonitor(driver, vm);
5731 5732

endjob:
E
Eric Blake 已提交
5733
            if (!qemuDomainObjEndJob(driver, vm)) {
5734 5735 5736
                vm = NULL;
                goto cleanup;
            }
5737 5738 5739
            if (err < 0)
                goto cleanup;
            if (err > 0)
5740
                vm->def->mem.cur_balloon = balloon;
5741 5742
            /* err == 0 indicates no balloon support, so ignore it */
        }
5743
    }
5744

5745 5746 5747 5748
    if ((flags & VIR_DOMAIN_XML_MIGRATABLE))
        flags |= QEMU_DOMAIN_FORMAT_LIVE_FLAGS;

    ret = qemuDomainFormatXML(driver, vm, flags);
5749 5750

cleanup:
5751
    if (vm)
5752
        virObjectUnlock(vm);
5753
    return ret;
D
Daniel P. Berrange 已提交
5754 5755 5756
}


5757 5758 5759 5760
static char *qemuConnectDomainXMLFromNative(virConnectPtr conn,
                                            const char *format,
                                            const char *config,
                                            unsigned int flags)
E
Eric Blake 已提交
5761
{
5762
    virQEMUDriverPtr driver = conn->privateData;
5763 5764
    virDomainDefPtr def = NULL;
    char *xml = NULL;
5765
    virCapsPtr caps = NULL;
5766

E
Eric Blake 已提交
5767 5768
    virCheckFlags(0, NULL);

5769 5770 5771
    if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0)
        goto cleanup;

5772
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
5773 5774
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), format);
5775 5776 5777
        goto cleanup;
    }

5778 5779 5780
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

5781
    def = qemuParseCommandLineString(caps, driver->xmlopt, config,
5782
                                     NULL, NULL, NULL);
5783 5784 5785
    if (!def)
        goto cleanup;

5786
    if (!def->name && VIR_STRDUP(def->name, "unnamed") < 0)
5787 5788
        goto cleanup;

5789
    xml = qemuDomainDefFormatXML(driver, def, VIR_DOMAIN_XML_INACTIVE);
5790 5791 5792

cleanup:
    virDomainDefFree(def);
5793
    virObjectUnref(caps);
5794 5795 5796
    return xml;
}

5797 5798 5799 5800
static char *qemuConnectDomainXMLToNative(virConnectPtr conn,
                                          const char *format,
                                          const char *xmlData,
                                          unsigned int flags)
E
Eric Blake 已提交
5801
{
5802
    virQEMUDriverPtr driver = conn->privateData;
5803
    virDomainDefPtr def = NULL;
5804
    virDomainChrSourceDef monConfig;
5805
    virQEMUCapsPtr qemuCaps = NULL;
T
tangchen 已提交
5806
    bool monitor_json = false;
E
Eric Blake 已提交
5807
    virCommandPtr cmd = NULL;
5808
    char *ret = NULL;
5809
    size_t i;
5810
    virQEMUDriverConfigPtr cfg;
5811
    virCapsPtr caps = NULL;
5812

E
Eric Blake 已提交
5813 5814
    virCheckFlags(0, NULL);

5815
    cfg = virQEMUDriverGetConfig(driver);
5816

5817 5818 5819
    if (virConnectDomainXMLToNativeEnsureACL(conn) < 0)
        goto cleanup;

5820
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
5821 5822
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), format);
5823 5824 5825
        goto cleanup;
    }

5826 5827 5828
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

5829
    def = virDomainDefParseString(xmlData, caps, driver->xmlopt,
M
Matthias Bolte 已提交
5830
                                  QEMU_EXPECTED_VIRT_TYPES, 0);
5831 5832 5833
    if (!def)
        goto cleanup;

5834
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
5835 5836
        goto cleanup;

5837 5838
    /* Since we're just exporting args, we can't do bridge/network/direct
     * setups, since libvirt will normally create TAP/macvtap devices
5839 5840 5841
     * directly. We convert those configs into generic 'ethernet'
     * config and assume the user has suitable 'ifup-qemu' scripts
     */
5842
    for (i = 0; i < def->nnets; i++) {
5843
        virDomainNetDefPtr net = def->nets[i];
5844
        int bootIndex = net->info.bootIndex;
5845
        char *model = net->model;
5846
        virMacAddr mac = net->mac;
5847

5848 5849 5850 5851
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            int actualType = virDomainNetGetActualType(net);
            const char *brname;

5852
            VIR_FREE(net->data.network.name);
5853 5854 5855 5856
            VIR_FREE(net->data.network.portgroup);
            if ((actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
                (brname = virDomainNetGetActualBridgeName(net))) {

5857 5858
                char *brnamecopy;
                if (VIR_STRDUP(brnamecopy, brname) < 0)
5859 5860 5861 5862
                    goto cleanup;

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

5863
                memset(net, 0, sizeof(*net));
5864 5865

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5866
                net->script = NULL;
5867 5868 5869 5870 5871 5872 5873
                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);
5874
                memset(net, 0, sizeof(*net));
5875 5876

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5877
                net->script = NULL;
5878 5879 5880 5881 5882
                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);
5883

5884
            memset(net, 0, sizeof(*net));
5885 5886

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5887
            net->script = NULL;
5888 5889 5890
            net->data.ethernet.dev = NULL;
            net->data.ethernet.ipaddr = NULL;
        } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
5891
            char *script = net->script;
5892 5893 5894
            char *brname = net->data.bridge.brname;
            char *ipaddr = net->data.bridge.ipaddr;

5895
            memset(net, 0, sizeof(*net));
5896 5897

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5898
            net->script = script;
5899 5900 5901
            net->data.ethernet.dev = brname;
            net->data.ethernet.ipaddr = ipaddr;
        }
5902

5903
        VIR_FREE(net->virtPortProfile);
5904
        net->info.bootIndex = bootIndex;
5905
        net->model = model;
5906
        net->mac = mac;
5907 5908
    }

5909
    monitor_json = virQEMUCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON);
T
tangchen 已提交
5910

5911
    if (qemuProcessPrepareMonitorChr(cfg, &monConfig, def->name) < 0)
5912
        goto cleanup;
5913

5914
    if (qemuAssignDeviceAliases(def, qemuCaps) < 0)
5915 5916
        goto cleanup;

5917 5918 5919
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
        goto cleanup;

5920
    /* do fake auto-alloc of graphics ports, if such config is used */
5921
    for (i = 0; i < def->ngraphics; ++i) {
5922 5923 5924 5925 5926
        virDomainGraphicsDefPtr graphics = def->graphics[i];
        if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_VNC &&
            !graphics->data.vnc.socket && graphics->data.vnc.autoport) {
            graphics->data.vnc.port = 5900;
        } else if (graphics->type == VIR_DOMAIN_GRAPHICS_TYPE_SPICE) {
5927
            size_t j;
5928 5929 5930 5931 5932 5933
            bool needTLSPort = false;
            bool needPort = false;
            int defaultMode = graphics->data.spice.defaultMode;

            if (graphics->data.spice.autoport) {
                /* check if tlsPort or port need allocation */
5934
                for (j = 0; j < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST; j++) {
5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971
                    switch (graphics->data.spice.channels[j]) {
                    case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE:
                        needTLSPort = true;
                        break;

                    case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE:
                        needPort = true;
                        break;

                    case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY:
                        switch (defaultMode) {
                        case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_SECURE:
                            needTLSPort = true;
                            break;

                        case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_INSECURE:
                            needPort = true;
                            break;

                        case VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_ANY:
                            needTLSPort = true;
                            needPort = true;
                            break;
                        }
                        break;
                    }
                }
            }

            if (needPort || graphics->data.spice.port == -1)
                graphics->data.spice.port = 5901;

            if (needTLSPort || graphics->data.spice.tlsPort == -1)
                graphics->data.spice.tlsPort = 5902;
        }
    }

5972
    if (!(cmd = qemuBuildCommandLine(conn, driver, def,
5973
                                     &monConfig, monitor_json, qemuCaps,
5974 5975
                                     NULL, -1, NULL, VIR_NETDEV_VPORT_PROFILE_OP_NO_OP,
                                     &buildCommandLineCallbacks)))
5976 5977
        goto cleanup;

E
Eric Blake 已提交
5978
    ret = virCommandToString(cmd);
5979 5980 5981

cleanup:

5982
    virObjectUnref(qemuCaps);
E
Eric Blake 已提交
5983
    virCommandFree(cmd);
5984
    virDomainDefFree(def);
5985
    virObjectUnref(caps);
5986
    virObjectUnref(cfg);
5987 5988 5989 5990
    return ret;
}


5991 5992
static int qemuConnectListDefinedDomains(virConnectPtr conn,
                                         char **const names, int nnames) {
5993
    virQEMUDriverPtr driver = conn->privateData;
5994
    int ret = -1;
5995

5996 5997 5998
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        goto cleanup;

5999
    ret = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
6000 6001
                                           virConnectListDefinedDomainsCheckACL,
                                           conn);
6002 6003 6004

cleanup:
    return ret;
D
Daniel P. Berrange 已提交
6005 6006
}

6007
static int qemuConnectNumOfDefinedDomains(virConnectPtr conn) {
6008
    virQEMUDriverPtr driver = conn->privateData;
6009 6010 6011 6012
    int ret = -1;

    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        goto cleanup;
6013

6014
    ret = virDomainObjListNumOfDomains(driver->domains, false,
6015 6016
                                       virConnectNumOfDefinedDomainsCheckACL,
                                       conn);
6017

6018 6019
cleanup:
    return ret;
D
Daniel P. Berrange 已提交
6020 6021 6022
}


6023 6024
static int
qemuDomainObjStart(virConnectPtr conn,
6025
                   virQEMUDriverPtr driver,
6026
                   virDomainObjPtr vm,
6027
                   unsigned int flags)
J
Jiri Denemark 已提交
6028 6029 6030
{
    int ret = -1;
    char *managed_save;
6031 6032 6033 6034
    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;
6035 6036 6037
    unsigned int start_flags = VIR_QEMU_PROCESS_START_COLD;

    start_flags |= start_paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
6038
    start_flags |= autodestroy ? VIR_QEMU_PROCESS_START_AUTODESTROY : 0;
J
Jiri Denemark 已提交
6039 6040 6041

    /*
     * If there is a managed saved state restore it instead of starting
6042
     * from scratch. The old state is removed once the restoring succeeded.
J
Jiri Denemark 已提交
6043 6044
     */
    managed_save = qemuDomainManagedSavePath(driver, vm);
6045 6046 6047 6048

    if (!managed_save)
        goto cleanup;

E
Eric Blake 已提交
6049
    if (virFileExists(managed_save)) {
6050 6051 6052 6053 6054 6055 6056
        if (force_boot) {
            if (unlink(managed_save) < 0) {
                virReportSystemError(errno,
                                     _("cannot remove managed save file %s"),
                                     managed_save);
                goto cleanup;
            }
6057
            vm->hasManagedSave = false;
6058 6059
        } else {
            ret = qemuDomainObjRestore(conn, driver, vm, managed_save,
6060
                                       start_paused, bypass_cache);
J
Jiri Denemark 已提交
6061

6062 6063 6064 6065 6066 6067 6068
            if (ret == 0) {
                if (unlink(managed_save) < 0)
                    VIR_WARN("Failed to remove the managed state %s", managed_save);
                else
                    vm->hasManagedSave = false;
            }

6069
            if (ret > 0) {
E
Eric Blake 已提交
6070
                VIR_WARN("Ignoring incomplete managed state %s", managed_save);
6071 6072 6073
            } else {
                VIR_WARN("Unable to restore from managed state %s. "
                         "Maybe the file is corrupted?", managed_save);
E
Eric Blake 已提交
6074
                goto cleanup;
6075
            }
6076
        }
J
Jiri Denemark 已提交
6077 6078
    }

6079 6080
    ret = qemuProcessStart(conn, driver, vm, NULL, -1, NULL, NULL,
                           VIR_NETDEV_VPORT_PROFILE_OP_CREATE, start_flags);
6081
    virDomainAuditStart(vm, "booted", ret >= 0);
6082
    if (ret >= 0) {
6083
        virObjectEventPtr event =
6084
            virDomainEventLifecycleNewFromObj(vm,
J
Jiri Denemark 已提交
6085 6086
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
6087
        if (event) {
J
Jiri Denemark 已提交
6088
            qemuDomainEventQueue(driver, event);
6089
            if (start_paused) {
6090
                event = virDomainEventLifecycleNewFromObj(vm,
6091 6092 6093 6094 6095 6096
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
                if (event)
                    qemuDomainEventQueue(driver, event);
            }
        }
J
Jiri Denemark 已提交
6097 6098 6099 6100 6101 6102 6103
    }

cleanup:
    VIR_FREE(managed_save);
    return ret;
}

6104
static int
6105
qemuDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
6106
{
6107
    virQEMUDriverPtr driver = dom->conn->privateData;
6108 6109
    virDomainObjPtr vm;
    int ret = -1;
6110

6111
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
6112
                  VIR_DOMAIN_START_AUTODESTROY |
6113 6114
                  VIR_DOMAIN_START_BYPASS_CACHE |
                  VIR_DOMAIN_START_FORCE_BOOT, -1);
6115

6116 6117
    virNWFilterReadLockFilterUpdates();

6118 6119
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
6120

6121 6122 6123
    if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

6124
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
6125 6126 6127
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
6128 6129
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is already running"));
6130 6131 6132
        goto endjob;
    }

6133
    if (qemuDomainObjStart(dom->conn, driver, vm, flags) < 0)
6134 6135 6136
        goto endjob;

    ret = 0;
6137

6138
endjob:
E
Eric Blake 已提交
6139
    if (!qemuDomainObjEndJob(driver, vm))
6140
        vm = NULL;
6141

6142
cleanup:
6143
    if (vm)
6144
        virObjectUnlock(vm);
6145
    virNWFilterUnlockFilterUpdates();
6146
    return ret;
D
Daniel P. Berrange 已提交
6147 6148
}

6149
static int
6150
qemuDomainCreate(virDomainPtr dom)
6151
{
6152
    return qemuDomainCreateWithFlags(dom, 0);
6153 6154
}

6155
static virDomainPtr qemuDomainDefineXML(virConnectPtr conn, const char *xml) {
6156
    virQEMUDriverPtr driver = conn->privateData;
6157
    virDomainDefPtr def = NULL;
6158
    virDomainDefPtr oldDef = NULL;
6159
    virDomainObjPtr vm = NULL;
6160
    virDomainPtr dom = NULL;
6161
    virObjectEventPtr event = NULL;
6162
    virQEMUCapsPtr qemuCaps = NULL;
6163
    virQEMUDriverConfigPtr cfg;
6164
    virCapsPtr caps = NULL;
6165

6166
    cfg = virQEMUDriverGetConfig(driver);
6167 6168 6169 6170

    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

6171
    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
M
Matthias Bolte 已提交
6172
                                        QEMU_EXPECTED_VIRT_TYPES,
6173
                                        VIR_DOMAIN_XML_INACTIVE)))
6174
        goto cleanup;
6175

6176 6177 6178
    if (virDomainDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

6179
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
6180 6181
        goto cleanup;

6182
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
6183 6184
        goto cleanup;

6185
    if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
6186 6187
        goto cleanup;

6188
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
6189 6190
        goto cleanup;

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

6196
    def = NULL;
E
Eric Blake 已提交
6197 6198 6199
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
6200
        virDomainObjAssignDef(vm, NULL, false, NULL);
E
Eric Blake 已提交
6201 6202
        goto cleanup;
    }
6203
    vm->persistent = 1;
6204

6205
    if (virDomainSaveConfig(cfg->configDir,
6206
                            vm->newDef ? vm->newDef : vm->def) < 0) {
6207
        if (oldDef) {
M
Michal Privoznik 已提交
6208 6209 6210 6211
            /* 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))
6212
                vm->newDef = oldDef;
M
Michal Privoznik 已提交
6213
            else
6214 6215
                vm->def = oldDef;
            oldDef = NULL;
M
Michal Privoznik 已提交
6216 6217 6218 6219 6220 6221
        } else {
            /* Brand new domain. Remove it */
            VIR_INFO("Deleting domain '%s'", vm->def->name);
            qemuDomainRemoveInactive(driver, vm);
            vm = NULL;
        }
6222
        goto cleanup;
6223 6224
    }

6225
    event = virDomainEventLifecycleNewFromObj(vm,
6226
                                     VIR_DOMAIN_EVENT_DEFINED,
6227
                                     !oldDef ?
6228 6229
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
6230

6231
    VIR_INFO("Creating domain '%s'", vm->def->name);
6232
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
6233
    if (dom) dom->id = vm->def->id;
6234 6235

cleanup:
6236
    virDomainDefFree(oldDef);
6237
    virDomainDefFree(def);
6238
    if (vm)
6239
        virObjectUnlock(vm);
6240 6241
    if (event)
        qemuDomainEventQueue(driver, event);
6242
    virObjectUnref(qemuCaps);
6243
    virObjectUnref(caps);
6244
    virObjectUnref(cfg);
6245
    return dom;
D
Daniel P. Berrange 已提交
6246 6247
}

6248 6249
static int
qemuDomainUndefineFlags(virDomainPtr dom,
6250
                        unsigned int flags)
6251
{
6252
    virQEMUDriverPtr driver = dom->conn->privateData;
6253
    virDomainObjPtr vm;
6254
    virObjectEventPtr event = NULL;
6255
    char *name = NULL;
6256
    int ret = -1;
6257
    int nsnapshots;
6258
    virQEMUDriverConfigPtr cfg = NULL;
D
Daniel P. Berrange 已提交
6259

6260 6261
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
                  VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
6262

6263 6264
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
6265

6266
    cfg = virQEMUDriverGetConfig(driver);
D
Daniel P. Berrange 已提交
6267

6268 6269 6270
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

6271
    if (!vm->persistent) {
6272 6273
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
6274 6275 6276
        goto cleanup;
    }

6277
    if (!virDomainObjIsActive(vm) &&
6278
        (nsnapshots = virDomainSnapshotObjListNum(vm->snapshots, NULL, 0))) {
6279
        if (!(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
6280 6281 6282 6283
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("cannot delete inactive domain with %d "
                             "snapshots"),
                           nsnapshots);
6284 6285
            goto cleanup;
        }
6286
        if (qemuDomainSnapshotDiscardAllMetadata(driver, vm) < 0)
6287
            goto cleanup;
6288 6289
    }

6290 6291 6292 6293 6294 6295 6296
    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    if (virFileExists(name)) {
        if (flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE) {
            if (unlink(name) < 0) {
6297 6298 6299
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to remove domain managed "
                                 "save image"));
6300 6301 6302
                goto cleanup;
            }
        } else {
6303 6304 6305
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Refusing to undefine while domain managed "
                             "save image exists"));
6306 6307 6308 6309
            goto cleanup;
        }
    }

6310
    if (virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm) < 0)
6311
        goto cleanup;
D
Daniel P. Berrange 已提交
6312

6313
    event = virDomainEventLifecycleNewFromObj(vm,
6314 6315
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
6316

6317
    VIR_INFO("Undefining domain '%s'", vm->def->name);
6318 6319 6320 6321 6322 6323 6324 6325

    /* 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 {
6326
        qemuDomainRemoveInactive(driver, vm);
6327 6328 6329
        vm = NULL;
    }

6330
    ret = 0;
D
Daniel P. Berrange 已提交
6331

6332
cleanup:
6333
    VIR_FREE(name);
6334
    if (vm)
6335
        virObjectUnlock(vm);
6336 6337
    if (event)
        qemuDomainEventQueue(driver, event);
6338
    virObjectUnref(cfg);
6339
    return ret;
D
Daniel P. Berrange 已提交
6340 6341
}

6342
static int
6343
qemuDomainUndefine(virDomainPtr dom)
6344 6345 6346 6347
{
    return qemuDomainUndefineFlags(dom, 0);
}

6348
static int
6349
qemuDomainAttachDeviceControllerLive(virQEMUDriverPtr driver,
6350
                                     virDomainObjPtr vm,
6351
                                     virDomainDeviceDefPtr dev)
6352 6353 6354 6355 6356 6357
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
6358
        ret = qemuDomainAttachControllerDevice(driver, vm, cont);
6359 6360
        break;
    default:
6361 6362
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot plugged."),
6363
                       virDomainControllerTypeToString(cont->type));
6364 6365 6366 6367 6368 6369 6370 6371
        break;
    }
    return ret;
}

static int
qemuDomainAttachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
6372
                           virDomainPtr dom)
6373
{
6374
    virQEMUDriverPtr driver = dom->conn->privateData;
6375 6376 6377 6378
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
6379
        qemuDomainObjCheckDiskTaint(driver, vm, dev->data.disk, -1);
6380
        ret = qemuDomainAttachDeviceDiskLive(dom->conn, driver, vm, dev);
6381 6382 6383 6384 6385
        if (!ret)
            dev->data.disk = NULL;
        break;

    case VIR_DOMAIN_DEVICE_CONTROLLER:
6386
        ret = qemuDomainAttachDeviceControllerLive(driver, vm, dev);
6387 6388 6389 6390
        if (!ret)
            dev->data.controller = NULL;
        break;

6391 6392 6393 6394 6395 6396 6397
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainAttachLease(driver, vm,
                                    dev->data.lease);
        if (ret == 0)
            dev->data.lease = NULL;
        break;

6398
    case VIR_DOMAIN_DEVICE_NET:
6399
        qemuDomainObjCheckNetTaint(driver, vm, dev->data.net, -1);
6400
        ret = qemuDomainAttachNetDevice(dom->conn, driver, vm,
6401
                                        dev->data.net);
6402 6403 6404 6405 6406 6407
        if (!ret)
            dev->data.net = NULL;
        break;

    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = qemuDomainAttachHostDevice(driver, vm,
6408
                                         dev->data.hostdev);
6409 6410 6411 6412
        if (!ret)
            dev->data.hostdev = NULL;
        break;

6413 6414 6415 6416 6417 6418 6419
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        ret = qemuDomainAttachRedirdevDevice(driver, vm,
                                             dev->data.redirdev);
        if (!ret)
            dev->data.redirdev = NULL;
        break;

6420 6421 6422 6423 6424 6425 6426
    case VIR_DOMAIN_DEVICE_CHR:
        ret = qemuDomainAttachChrDevice(driver, vm,
                                        dev->data.chr);
        if (!ret)
            dev->data.chr = NULL;
        break;

6427
    default:
6428 6429
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("live attach of device '%s' is not supported"),
6430
                       virDomainDeviceTypeToString(dev->type));
6431 6432 6433
        break;
    }

6434 6435 6436
    if (ret == 0)
        qemuDomainUpdateDeviceList(driver, vm);

6437 6438 6439 6440
    return ret;
}

static int
6441
qemuDomainDetachDeviceControllerLive(virQEMUDriverPtr driver,
6442
                                     virDomainObjPtr vm,
6443
                                     virDomainDeviceDefPtr dev)
6444 6445 6446 6447 6448 6449
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
6450
        ret = qemuDomainDetachControllerDevice(driver, vm, dev);
6451 6452
        break;
    default :
6453 6454
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot unplugged."),
6455
                       virDomainControllerTypeToString(cont->type));
6456 6457 6458 6459 6460 6461 6462
    }
    return ret;
}

static int
qemuDomainDetachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
6463
                           virDomainPtr dom)
6464
{
6465
    virQEMUDriverPtr driver = dom->conn->privateData;
6466 6467 6468 6469
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
6470
        ret = qemuDomainDetachDeviceDiskLive(driver, vm, dev);
6471 6472
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
6473
        ret = qemuDomainDetachDeviceControllerLive(driver, vm, dev);
6474
        break;
6475 6476 6477
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainDetachLease(driver, vm, dev->data.lease);
        break;
6478
    case VIR_DOMAIN_DEVICE_NET:
6479
        ret = qemuDomainDetachNetDevice(driver, vm, dev);
6480 6481
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
6482
        ret = qemuDomainDetachHostDevice(driver, vm, dev);
6483
        break;
6484 6485 6486
    case VIR_DOMAIN_DEVICE_CHR:
        ret = qemuDomainDetachChrDevice(driver, vm, dev->data.chr);
        break;
6487
    default:
6488 6489 6490
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("live detach of device '%s' is not supported"),
                       virDomainDeviceTypeToString(dev->type));
6491 6492 6493
        break;
    }

6494 6495 6496
    if (ret == 0)
        qemuDomainUpdateDeviceList(driver, vm);

6497 6498 6499
    return ret;
}

6500
static int
6501 6502
qemuDomainChangeDiskMediaLive(virConnectPtr conn,
                              virDomainObjPtr vm,
6503
                              virDomainDeviceDefPtr dev,
6504
                              virQEMUDriverPtr driver,
6505 6506 6507
                              bool force)
{
    virDomainDiskDefPtr disk = dev->data.disk;
6508 6509 6510 6511
    virDomainDiskDefPtr orig_disk = NULL;
    virDomainDiskDefPtr tmp = NULL;
    virDomainDeviceDefPtr dev_copy = NULL;
    virCapsPtr caps = NULL;
6512
    int ret = -1;
6513

6514 6515 6516
    if (qemuTranslateDiskSourcePool(conn, disk) < 0)
        goto end;

6517
    if (qemuDomainDetermineDiskChain(driver, vm, disk, false) < 0)
6518 6519
        goto end;

6520 6521
    if (qemuSetupDiskCgroup(vm, disk) < 0)
        goto end;
6522 6523 6524 6525

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
6526 6527 6528 6529 6530 6531 6532 6533 6534 6535 6536 6537 6538 6539 6540
        if (!(orig_disk = virDomainDiskFindByBusAndDst(vm->def,
                                                       disk->bus, disk->dst))) {
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("No device with bus '%s' and target '%s'"),
                           virDomainDiskBusTypeToString(disk->bus),
                           disk->dst);
            goto end;
        }

        if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
            goto end;

        tmp = dev->data.disk;
        dev->data.disk = orig_disk;

6541 6542
        if (!(dev_copy = virDomainDeviceDefCopy(dev, vm->def,
                                                caps, driver->xmlopt))) {
6543 6544 6545 6546 6547
            dev->data.disk = tmp;
            goto end;
        }
        dev->data.disk = tmp;

6548
        /* Add the new disk src into shared disk hash table */
6549
        if (qemuAddSharedDevice(driver, dev, vm->def->name) < 0)
6550 6551
            goto end;

6552
        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, orig_disk, force);
6553 6554 6555 6556 6557 6558 6559
        /* 'disk' must not be accessed now - it has been freed.
         * 'orig_disk' now points to the new disk, while 'dev_copy'
         * now points to the old disk */

        /* Need to remove the shared disk entry for the original
         * disk src if the operation is either ejecting or updating.
         */
6560
        if (ret == 0) {
6561
            dev->data.disk = NULL;
6562 6563
            ignore_value(qemuRemoveSharedDevice(driver, dev_copy,
                                                vm->def->name));
6564
        }
6565 6566
        break;
    default:
6567 6568 6569
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk bus '%s' cannot be updated."),
                       virDomainDiskBusTypeToString(disk->bus));
6570 6571 6572
        break;
    }

6573 6574 6575 6576 6577
    if (ret != 0 &&
        qemuTeardownDiskCgroup(vm, disk) < 0)
        VIR_WARN("Failed to teardown cgroup for disk path %s",
                 NULLSTR(disk->src));

6578
end:
6579 6580
    virObjectUnref(caps);
    virDomainDeviceDefFree(dev_copy);
6581 6582 6583 6584
    return ret;
}

static int
6585 6586
qemuDomainUpdateDeviceLive(virConnectPtr conn,
                           virDomainObjPtr vm,
6587 6588 6589 6590
                           virDomainDeviceDefPtr dev,
                           virDomainPtr dom,
                           bool force)
{
6591
    virQEMUDriverPtr driver = dom->conn->privateData;
6592 6593 6594 6595
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
6596
        ret = qemuDomainChangeDiskMediaLive(conn, vm, dev, driver, force);
6597 6598 6599 6600
        break;
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
        break;
6601
    case VIR_DOMAIN_DEVICE_NET:
6602
        ret = qemuDomainChangeNet(driver, vm, dom, dev);
6603
        break;
6604
    default:
6605
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6606
                       _("live update of device '%s' is not supported"),
6607
                       virDomainDeviceTypeToString(dev->type));
6608 6609 6610 6611 6612 6613
        break;
    }

    return ret;
}

6614
static int
6615
qemuDomainAttachDeviceConfig(virQEMUCapsPtr qemuCaps,
6616
                             virDomainDefPtr vmdef,
6617 6618
                             virDomainDeviceDefPtr dev)
{
6619
    virDomainDiskDefPtr disk;
6620
    virDomainNetDefPtr net;
6621
    virDomainHostdevDefPtr hostdev;
6622
    virDomainLeaseDefPtr lease;
6623
    virDomainControllerDefPtr controller;
6624
    virDomainFSDefPtr fs;
6625

6626
    switch (dev->type) {
6627 6628
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6629
        if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
6630 6631
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("target %s already exists"), disk->dst);
6632 6633
            return -1;
        }
6634
        if (virDomainDiskInsert(vmdef, disk))
6635 6636 6637 6638 6639 6640
            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;
6641
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6642 6643 6644
            return -1;
        break;

6645 6646
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
6647
        if (virDomainNetInsert(vmdef, net))
6648 6649
            return -1;
        dev->data.net = NULL;
6650
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6651 6652
            return -1;
        break;
6653

6654 6655 6656
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        hostdev = dev->data.hostdev;
        if (virDomainHostdevFind(vmdef, hostdev, NULL) >= 0) {
6657
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6658
                           _("device is already in the domain configuration"));
6659 6660
            return -1;
        }
6661
        if (virDomainHostdevInsert(vmdef, hostdev))
6662 6663
            return -1;
        dev->data.hostdev = NULL;
6664
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6665 6666 6667
            return -1;
        break;

6668 6669 6670
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
        if (virDomainLeaseIndex(vmdef, lease) >= 0) {
6671
            virReportError(VIR_ERR_OPERATION_INVALID,
6672 6673
                           _("Lease %s in lockspace %s already exists"),
                           lease->key, NULLSTR(lease->lockspace));
6674 6675 6676 6677 6678 6679 6680 6681 6682
            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;

6683 6684 6685
    case VIR_DOMAIN_DEVICE_CONTROLLER:
        controller = dev->data.controller;
        if (virDomainControllerFind(vmdef, controller->type,
6686
                                    controller->idx) >= 0) {
6687
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6688 6689 6690 6691 6692 6693 6694 6695
                           _("Target already exists"));
            return -1;
        }

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

6696
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6697 6698 6699
            return -1;
        break;

6700 6701 6702 6703 6704 6705
    case VIR_DOMAIN_DEVICE_CHR:
        if (qemuDomainChrInsert(vmdef, dev->data.chr) < 0)
            return -1;
        dev->data.chr = NULL;
        break;

6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718
    case VIR_DOMAIN_DEVICE_FS:
        fs = dev->data.fs;
        if (virDomainFSIndexByName(vmdef, fs->dst) >= 0) {
            virReportError(VIR_ERR_OPERATION_INVALID,
                         "%s", _("Target already exists"));
            return -1;
        }

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

6719
    default:
6720 6721 6722
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("persistent attach of device '%s' is not supported"),
                        virDomainDeviceTypeToString(dev->type));
6723 6724 6725 6726 6727 6728 6729
         return -1;
    }
    return 0;
}


static int
6730
qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
6731 6732
                             virDomainDeviceDefPtr dev)
{
6733
    virDomainDiskDefPtr disk, det_disk;
6734
    virDomainNetDefPtr net;
6735
    virDomainHostdevDefPtr hostdev, det_hostdev;
6736
    virDomainLeaseDefPtr lease, det_lease;
6737
    virDomainControllerDefPtr cont, det_cont;
6738
    virDomainChrDefPtr chr;
6739
    virDomainFSDefPtr fs;
6740
    int idx;
6741
    char mac[VIR_MAC_STRING_BUFLEN];
6742

6743
    switch (dev->type) {
6744 6745
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6746
        if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) {
6747 6748
            virReportError(VIR_ERR_INVALID_ARG,
                           _("no target device %s"), disk->dst);
6749 6750
            return -1;
        }
6751
        virDomainDiskDefFree(det_disk);
6752
        break;
6753

6754 6755
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
6756 6757 6758 6759 6760 6761 6762 6763 6764
        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"));
6765 6766
            return -1;
        }
6767 6768
        /* this is guaranteed to succeed */
        virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
6769
        break;
6770

6771 6772 6773
    case VIR_DOMAIN_DEVICE_HOSTDEV: {
        hostdev = dev->data.hostdev;
        if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) {
6774 6775
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("device not present in domain configuration"));
6776 6777 6778 6779 6780 6781 6782
            return -1;
        }
        virDomainHostdevRemove(vmdef, idx);
        virDomainHostdevDefFree(det_hostdev);
        break;
    }

6783 6784
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
6785
        if (!(det_lease = virDomainLeaseRemove(vmdef, lease))) {
6786 6787 6788
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Lease %s in lockspace %s does not exist"),
                           lease->key, NULLSTR(lease->lockspace));
6789 6790
            return -1;
        }
6791
        virDomainLeaseDefFree(det_lease);
6792 6793
        break;

6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806
    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;

6807 6808 6809 6810 6811 6812 6813 6814 6815
    case VIR_DOMAIN_DEVICE_CHR:
        if (!(chr = qemuDomainChrRemove(vmdef, dev->data.chr)))
            return -1;

        virDomainChrDefFree(chr);
        virDomainChrDefFree(dev->data.chr);
        dev->data.chr = NULL;
        break;

6816 6817 6818 6819 6820 6821 6822 6823 6824 6825 6826 6827 6828
    case VIR_DOMAIN_DEVICE_FS:
        fs = dev->data.fs;
        idx = virDomainFSIndexByName(vmdef, fs->dst);
        if (idx < 0) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("no matching filesystem device was found"));
            return -1;
        }

        fs = virDomainFSRemove(vmdef, idx);
        virDomainFSDefFree(fs);
        break;

6829
    default:
6830 6831 6832
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("persistent detach of device '%s' is not supported"),
                       virDomainDeviceTypeToString(dev->type));
6833 6834 6835 6836 6837 6838
        return -1;
    }
    return 0;
}

static int
6839
qemuDomainUpdateDeviceConfig(virQEMUCapsPtr qemuCaps,
6840
                             virDomainDefPtr vmdef,
6841 6842
                             virDomainDeviceDefPtr dev)
{
6843
    virDomainDiskDefPtr orig, disk;
6844
    virDomainNetDefPtr net;
6845
    int pos;
6846 6847
    char mac[VIR_MAC_STRING_BUFLEN];

6848

6849
    switch (dev->type) {
6850 6851
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6852
        pos = virDomainDiskIndexByName(vmdef, disk->dst, false);
6853
        if (pos < 0) {
6854 6855
            virReportError(VIR_ERR_INVALID_ARG,
                           _("target %s doesn't exist."), disk->dst);
6856 6857 6858 6859 6860
            return -1;
        }
        orig = vmdef->disks[pos];
        if (!(orig->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
            !(orig->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)) {
6861 6862
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("this disk doesn't support update"));
6863 6864 6865 6866 6867 6868 6869 6870 6871 6872 6873 6874 6875 6876 6877
            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;
        }
6878 6879
        if (disk->format)
            orig->format = disk->format;
6880 6881
        disk->src = NULL;
        break;
6882 6883 6884

    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
6885 6886 6887 6888 6889 6890 6891 6892 6893 6894 6895 6896
        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);
6897 6898 6899
            return -1;
        }

6900
        virDomainNetDefFree(vmdef->nets[pos]);
6901 6902 6903 6904

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

6905
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6906 6907 6908
            return -1;
        break;

6909
    default:
6910 6911 6912
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("persistent update of device '%s' is not supported"),
                       virDomainDeviceTypeToString(dev->type));
6913 6914 6915 6916 6917
        return -1;
    }
    return 0;
}

6918

6919 6920
static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
6921
{
6922
    virQEMUDriverPtr driver = dom->conn->privateData;
6923
    virDomainObjPtr vm = NULL;
6924
    virDomainDefPtr vmdef = NULL;
6925
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
6926
    int ret = -1;
6927
    unsigned int affect, parse_flags = 0;
6928
    virQEMUCapsPtr qemuCaps = NULL;
6929
    qemuDomainObjPrivatePtr priv;
6930
    virQEMUDriverConfigPtr cfg = NULL;
6931
    virCapsPtr caps = NULL;
6932

6933
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
6934
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6935

6936 6937
    cfg = virQEMUDriverGetConfig(driver);

6938 6939
    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);

6940 6941 6942
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

6943
    if (!(vm = qemuDomObjFromDomain(dom)))
6944
        goto cleanup;
6945

6946
    priv = vm->privateData;
6947

6948 6949 6950
    if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

6954
    if (virDomainObjIsActive(vm)) {
6955
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
6956
            flags |= VIR_DOMAIN_AFFECT_LIVE;
6957
    } else {
6958
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
6959
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
6960
        /* check consistency between flags and the vm state */
6961
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6962
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6963 6964
                           _("cannot do live update a device on "
                             "inactive domain"));
6965 6966
            goto endjob;
        }
6967
    }
6968

6969
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
6970 6971
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot modify device on transient domain"));
6972 6973
         goto endjob;
    }
6974

6975 6976 6977 6978
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) &&
        !(flags & VIR_DOMAIN_AFFECT_LIVE))
        parse_flags |= VIR_DOMAIN_XML_INACTIVE;

6979 6980
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
                                             caps, driver->xmlopt,
6981
                                             parse_flags);
6982 6983 6984 6985 6986 6987 6988 6989 6990
    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.
         */
6991
        dev_copy = virDomainDeviceDefCopy(dev, vm->def, caps, driver->xmlopt);
6992
        if (!dev_copy)
6993
            goto endjob;
6994
    }
6995

6996 6997 6998
    if (priv->qemuCaps)
        qemuCaps = virObjectRef(priv->qemuCaps);
    else if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, vm->def->emulator)))
6999 7000
        goto cleanup;

7001
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7002
        if (virDomainDefCompatibleDevice(vm->def, dev) < 0)
7003 7004
            goto endjob;

7005
        /* Make a copy for updated domain. */
7006
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
7007 7008
        if (!vmdef)
            goto endjob;
7009
        if ((ret = qemuDomainAttachDeviceConfig(qemuCaps, vmdef, dev)) < 0)
7010 7011 7012 7013
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7014 7015 7016
        if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
            goto endjob;

7017
        if ((ret = qemuDomainAttachDeviceLive(vm, dev_copy, dom)) < 0)
7018
            goto endjob;
7019 7020
        /*
         * update domain status forcibly because the domain status may be
7021 7022
         * changed even if we failed to attach the device. For example,
         * a new controller may be created.
7023
         */
7024
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
7025
            ret = -1;
7026 7027
            goto endjob;
        }
7028
    }
7029

7030
    /* Finally, if no error until here, we can save config. */
7031
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
7032
        ret = virDomainSaveConfig(cfg->configDir, vmdef);
7033
        if (!ret) {
7034
            virDomainObjAssignDef(vm, vmdef, false, NULL);
7035 7036 7037
            vmdef = NULL;
        }
    }
7038 7039

endjob:
E
Eric Blake 已提交
7040
    if (!qemuDomainObjEndJob(driver, vm))
7041 7042 7043
        vm = NULL;

cleanup:
7044
    virObjectUnref(qemuCaps);
7045
    virDomainDefFree(vmdef);
7046 7047
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
7048 7049
    virDomainDeviceDefFree(dev);
    if (vm)
7050
        virObjectUnlock(vm);
7051
    virObjectUnref(caps);
7052
    virObjectUnref(cfg);
7053 7054 7055
    return ret;
}

7056 7057 7058
static int qemuDomainAttachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainAttachDeviceFlags(dom, xml,
7059
                                       VIR_DOMAIN_AFFECT_LIVE);
7060
}
7061

7062

7063 7064 7065 7066
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
                                       const char *xml,
                                       unsigned int flags)
{
7067 7068 7069 7070 7071 7072 7073 7074 7075 7076 7077 7078 7079 7080 7081 7082 7083 7084 7085 7086 7087 7088 7089 7090 7091 7092 7093 7094
    virQEMUDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    bool force = (flags & VIR_DOMAIN_DEVICE_MODIFY_FORCE) != 0;
    int ret = -1;
    unsigned int affect;
    virQEMUCapsPtr qemuCaps = NULL;
    qemuDomainObjPrivatePtr priv;
    virQEMUDriverConfigPtr cfg = NULL;
    virCapsPtr caps = NULL;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_DOMAIN_DEVICE_MODIFY_FORCE, -1);

    cfg = virQEMUDriverGetConfig(driver);

    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);

    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

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

    priv = vm->privateData;

7095 7096 7097
    if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

7098 7099 7100 7101 7102 7103 7104 7105 7106 7107 7108 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 7136 7137 7138 7139 7140 7141 7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154 7155 7156 7157 7158 7159 7160 7161 7162 7163 7164 7165 7166 7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
            flags |= VIR_DOMAIN_AFFECT_LIVE;
    } else {
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
        /* check consistency between flags and the vm state */
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot do live update a device on "
                             "inactive domain"));
            goto endjob;
        }
    }

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

    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
                                             caps, driver->xmlopt,
                                             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(dev, vm->def, caps, driver->xmlopt);
        if (!dev_copy)
            goto endjob;
    }

    if (priv->qemuCaps)
        qemuCaps = virObjectRef(priv->qemuCaps);
    else if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, vm->def->emulator)))
        goto cleanup;

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

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

        if ((ret = qemuDomainUpdateDeviceConfig(qemuCaps, vmdef, dev)) < 0)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
            goto endjob;

        if ((ret = qemuDomainUpdateDeviceLive(dom->conn, vm, dev_copy, dom, force)) < 0)
            goto endjob;
        /*
         * update domain status forcibly because the domain status may be
         * changed even if we failed to attach the device. For example,
         * a new controller may be created.
         */
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
            ret = -1;
            goto endjob;
        }
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        ret = virDomainSaveConfig(cfg->configDir, vmdef);
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

endjob:
E
Eric Blake 已提交
7184
    if (!qemuDomainObjEndJob(driver, vm))
7185 7186 7187 7188 7189 7190 7191 7192 7193 7194 7195 7196 7197
        vm = NULL;

cleanup:
    virObjectUnref(qemuCaps);
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
    if (vm)
        virObjectUnlock(vm);
    virObjectUnref(caps);
    virObjectUnref(cfg);
    return ret;
7198 7199
}

7200

7201 7202 7203
static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
7204 7205 7206 7207 7208
    virQEMUDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
7209
    unsigned int affect, parse_flags = 0;
7210 7211 7212 7213 7214 7215 7216 7217 7218 7219 7220 7221 7222 7223 7224 7225 7226 7227 7228 7229
    virQEMUCapsPtr qemuCaps = NULL;
    qemuDomainObjPrivatePtr priv;
    virQEMUDriverConfigPtr cfg = NULL;
    virCapsPtr caps = NULL;

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

    cfg = virQEMUDriverGetConfig(driver);

    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);

    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

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

    priv = vm->privateData;

7230 7231 7232
    if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
            flags |= VIR_DOMAIN_AFFECT_LIVE;
    } else {
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
        /* check consistency between flags and the vm state */
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cannot do live update a device on "
                             "inactive domain"));
            goto endjob;
        }
    }

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

7257 7258 7259 7260
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) &&
        !(flags & VIR_DOMAIN_AFFECT_LIVE))
        parse_flags |= VIR_DOMAIN_XML_INACTIVE;

7261 7262
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
                                             caps, driver->xmlopt,
7263
                                             parse_flags);
7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278 7279 7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292 7293 7294 7295 7296 7297 7298 7299 7300 7301 7302 7303 7304 7305 7306 7307 7308 7309 7310 7311 7312 7313 7314 7315 7316 7317 7318 7319 7320 7321
    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(dev, vm->def, caps, driver->xmlopt);
        if (!dev_copy)
            goto endjob;
    }

    if (priv->qemuCaps)
        qemuCaps = virObjectRef(priv->qemuCaps);
    else if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, vm->def->emulator)))
        goto cleanup;

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

        /* Make a copy for updated domain. */
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
        if (!vmdef)
            goto endjob;
        if ((ret = qemuDomainDetachDeviceConfig(vmdef, dev)) < 0)
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
            goto endjob;

        if ((ret = qemuDomainDetachDeviceLive(vm, dev_copy, dom)) < 0)
            goto endjob;
        /*
         * update domain status forcibly because the domain status may be
         * changed even if we failed to attach the device. For example,
         * a new controller may be created.
         */
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
            ret = -1;
            goto endjob;
        }
    }

    /* Finally, if no error until here, we can save config. */
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        ret = virDomainSaveConfig(cfg->configDir, vmdef);
        if (!ret) {
            virDomainObjAssignDef(vm, vmdef, false, NULL);
            vmdef = NULL;
        }
    }

endjob:
E
Eric Blake 已提交
7322
    if (!qemuDomainObjEndJob(driver, vm))
7323 7324 7325 7326 7327 7328 7329 7330 7331 7332 7333 7334 7335
        vm = NULL;

cleanup:
    virObjectUnref(qemuCaps);
    virDomainDefFree(vmdef);
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
    virDomainDeviceDefFree(dev);
    if (vm)
        virObjectUnlock(vm);
    virObjectUnref(caps);
    virObjectUnref(cfg);
    return ret;
7336 7337
}

7338 7339 7340
static int qemuDomainDetachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainDetachDeviceFlags(dom, xml,
7341
                                       VIR_DOMAIN_AFFECT_LIVE);
7342 7343
}

7344 7345
static int qemuDomainGetAutostart(virDomainPtr dom,
                                  int *autostart) {
7346 7347
    virDomainObjPtr vm;
    int ret = -1;
7348

7349
    if (!(vm = qemuDomObjFromDomain(dom)))
7350
        goto cleanup;
7351

7352 7353 7354
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

7355
    *autostart = vm->autostart;
7356
    ret = 0;
7357

7358
cleanup:
7359
    if (vm)
7360
        virObjectUnlock(vm);
7361
    return ret;
7362 7363
}

7364 7365
static int qemuDomainSetAutostart(virDomainPtr dom,
                                  int autostart) {
7366
    virQEMUDriverPtr driver = dom->conn->privateData;
7367
    virDomainObjPtr vm;
7368 7369
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
7370
    virQEMUDriverConfigPtr cfg = NULL;
7371

7372 7373 7374
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;

7375
    cfg = virQEMUDriverGetConfig(driver);
7376

7377 7378 7379
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

7380
    if (!vm->persistent) {
7381 7382
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient domain"));
7383
        goto cleanup;
7384 7385
    }

7386 7387
    autostart = (autostart != 0);

7388
    if (vm->autostart != autostart) {
7389
        if ((configFile = virDomainConfigFile(cfg->configDir, vm->def->name)) == NULL)
7390
            goto cleanup;
7391
        if ((autostartLink = virDomainConfigFile(cfg->autostartDir, vm->def->name)) == NULL)
7392
            goto cleanup;
7393

7394
        if (autostart) {
7395
            if (virFileMakePath(cfg->autostartDir) < 0) {
7396
                virReportSystemError(errno,
7397
                                     _("cannot create autostart directory %s"),
7398
                                     cfg->autostartDir);
7399 7400
                goto cleanup;
            }
7401

7402
            if (symlink(configFile, autostartLink) < 0) {
7403
                virReportSystemError(errno,
7404 7405
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
7406 7407 7408 7409
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
7410
                virReportSystemError(errno,
7411 7412
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
7413 7414
                goto cleanup;
            }
7415 7416
        }

7417
        vm->autostart = autostart;
7418
    }
7419
    ret = 0;
7420

7421 7422 7423
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
7424
    if (vm)
7425
        virObjectUnlock(vm);
7426
    virObjectUnref(cfg);
7427
    return ret;
7428 7429
}

7430

7431 7432
static char *qemuDomainGetSchedulerType(virDomainPtr dom,
                                        int *nparams)
7433
{
7434
    char *ret = NULL;
7435 7436 7437
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;

7438
    if (!(vm = qemuDomObjFromDomain(dom)))
7439
        goto cleanup;
7440

7441
    priv = vm->privateData;
7442

7443 7444 7445
    if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

7446 7447 7448 7449 7450 7451 7452 7453
    /* Domain not running, thus no cgroups - return defaults */
    if (!virDomainObjIsActive(vm)) {
        if (nparams)
            *nparams = 5;
        ignore_value(VIR_STRDUP(ret, "posix"));
        goto cleanup;
    }

7454
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
7455 7456
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
7457
        goto cleanup;
7458 7459
    }

7460
    if (nparams) {
7461
        if (virCgroupSupportsCpuBW(priv->cgroup))
7462
            *nparams = 5;
7463 7464
        else
            *nparams = 1;
7465
    }
7466

7467
    ignore_value(VIR_STRDUP(ret, "posix"));
7468 7469

cleanup:
7470 7471
    if (vm)
        virObjectUnlock(vm);
7472 7473 7474
    return ret;
}

7475
/* blkioDeviceStr in the form of /device/path,weight,/device/path,weight
7476 7477 7478
 * for example, /dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0,800
 */
static int
7479 7480
qemuDomainParseBlkioDeviceStr(char *blkioDeviceStr, const char *type,
                              virBlkioDevicePtr *dev, size_t *size)
7481 7482 7483 7484
{
    char *temp;
    int ndevices = 0;
    int nsep = 0;
7485
    size_t i;
7486
    virBlkioDevicePtr result = NULL;
7487

7488
    *dev = NULL;
7489 7490
    *size = 0;

7491
    if (STREQ(blkioDeviceStr, ""))
7492 7493
        return 0;

7494
    temp = blkioDeviceStr;
7495 7496 7497 7498 7499 7500 7501 7502 7503 7504 7505 7506 7507 7508 7509
    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;

7510
    if (VIR_ALLOC_N(result, ndevices) < 0)
7511 7512 7513
        return -1;

    i = 0;
7514
    temp = blkioDeviceStr;
7515 7516 7517 7518 7519 7520 7521 7522
    while (temp) {
        char *p = temp;

        /* device path */
        p = strchr(p, ',');
        if (!p)
            goto error;

7523
        if (VIR_STRNDUP(result[i].path, temp, p - temp) < 0)
7524 7525
            goto cleanup;

7526
        /* value */
7527 7528
        temp = p + 1;

7529 7530 7531 7532 7533 7534 7535 7536 7537 7538 7539 7540 7541 7542 7543 7544
        if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
            if (virStrToLong_ui(temp, &p, 10, &result[i].weight) < 0)
                goto error;
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
            if (virStrToLong_ui(temp, &p, 10, &result[i].riops) < 0)
                goto error;
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
            if (virStrToLong_ui(temp, &p, 10, &result[i].wiops) < 0)
                goto error;
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
            if (virStrToLong_ull(temp, &p, 10, &result[i].rbps) < 0)
                goto error;
        } else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
            if (virStrToLong_ull(temp, &p, 10, &result[i].wbps) < 0)
                goto error;
        } else {
7545
            goto error;
7546
        }
7547 7548 7549 7550 7551 7552 7553 7554 7555 7556 7557 7558 7559

        i++;

        if (*p == '\0')
            break;
        else if (*p != ',')
            goto error;
        temp = p + 1;
    }

    if (!i)
        VIR_FREE(result);

7560
    *dev = result;
7561 7562 7563 7564 7565
    *size = i;

    return 0;

error:
7566
    virReportError(VIR_ERR_INVALID_ARG,
7567 7568
                   _("unable to parse blkio device '%s' '%s'"),
                   type, blkioDeviceStr);
7569
cleanup:
7570
    virBlkioDeviceArrayClear(result, ndevices);
7571 7572 7573 7574
    VIR_FREE(result);
    return -1;
}

7575
/* Modify dest_array to reflect all blkio device changes described in
7576
 * src_array.  */
7577
static int
7578 7579 7580 7581 7582
qemuDomainMergeBlkioDevice(virBlkioDevicePtr *dest_array,
                           size_t *dest_size,
                           virBlkioDevicePtr src_array,
                           size_t src_size,
                           const char *type)
7583
{
7584
    size_t i, j;
7585
    virBlkioDevicePtr dest, src;
7586

7587
    for (i = 0; i < src_size; i++) {
7588 7589
        bool found = false;

7590 7591 7592 7593
        src = &src_array[i];
        for (j = 0; j < *dest_size; j++) {
            dest = &(*dest_array)[j];
            if (STREQ(src->path, dest->path)) {
7594
                found = true;
7595 7596 7597 7598 7599 7600 7601 7602 7603 7604 7605 7606 7607 7608 7609 7610

                if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT))
                    dest->weight = src->weight;
                else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS))
                    dest->riops = src->riops;
                else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS))
                    dest->wiops = src->wiops;
                else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS))
                    dest->rbps = src->rbps;
                else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS))
                    dest->wbps = src->wbps;
                else {
                    virReportError(VIR_ERR_INVALID_ARG, _("Unknown parameter %s"),
                                   type);
                    return -1;
                }
7611 7612 7613 7614
                break;
            }
        }
        if (!found) {
7615
            if (!src->weight && !src->riops && !src->wiops && !src->rbps && !src->wbps)
7616
                continue;
7617
            if (VIR_EXPAND_N(*dest_array, *dest_size, 1) < 0)
7618
                return -1;
7619
            dest = &(*dest_array)[*dest_size - 1];
7620 7621 7622 7623 7624 7625 7626 7627 7628 7629 7630 7631 7632 7633 7634 7635

            if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT))
                dest->weight = src->weight;
            else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS))
                dest->riops = src->riops;
            else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS))
                dest->wiops = src->wiops;
            else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS))
                dest->rbps = src->rbps;
            else if (STREQ(type, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS))
                dest->wbps = src->wbps;
            else {
                *dest_size = *dest_size - 1;
                return -1;
            }

7636 7637
            dest->path = src->path;
            src->path = NULL;
7638 7639 7640 7641 7642 7643
        }
    }

    return 0;
}

7644 7645 7646 7647 7648
static int
qemuDomainSetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
7649
{
7650
    virQEMUDriverPtr driver = dom->conn->privateData;
7651
    size_t i;
7652
    virDomainObjPtr vm = NULL;
7653
    virDomainDefPtr persistentDef = NULL;
7654
    int ret = -1;
7655
    virQEMUDriverConfigPtr cfg = NULL;
7656
    virCapsPtr caps = NULL;
7657
    qemuDomainObjPrivatePtr priv;
7658

7659 7660
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7661 7662 7663 7664 7665
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_BLKIO_WEIGHT,
                               VIR_TYPED_PARAM_UINT,
                               VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                               VIR_TYPED_PARAM_STRING,
7666 7667 7668 7669 7670 7671 7672 7673
                               VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS,
                               VIR_TYPED_PARAM_STRING,
                               VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS,
                               VIR_TYPED_PARAM_STRING,
                               VIR_DOMAIN_BLKIO_DEVICE_READ_BPS,
                               VIR_TYPED_PARAM_STRING,
                               VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS,
                               VIR_TYPED_PARAM_STRING,
7674
                               NULL) < 0)
7675
        return -1;
7676

7677 7678 7679
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;

7680
    priv = vm->privateData;
7681
    cfg = virQEMUDriverGetConfig(driver);
7682 7683 7684 7685

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

7686 7687
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;
7688

7689
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
7690 7691
                                        &persistentDef) < 0)
        goto cleanup;
7692

7693
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7694
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
7695 7696
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
7697 7698 7699 7700
            goto cleanup;
        }
    }

7701
    ret = 0;
7702 7703 7704 7705 7706 7707
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        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) {
7708 7709
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
7710 7711 7712
                    ret = -1;
                    continue;
                }
7713

7714
                if (virCgroupSetBlkioWeight(priv->cgroup, params[i].value.ui) < 0)
7715
                    ret = -1;
7716 7717 7718 7719 7720
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
7721
                size_t ndevices;
7722
                virBlkioDevicePtr devices = NULL;
7723
                size_t j;
7724

7725 7726 7727 7728
                if (qemuDomainParseBlkioDeviceStr(params[i].value.s,
                                                  param->field,
                                                  &devices,
                                                  &ndevices) < 0) {
7729 7730 7731
                    ret = -1;
                    continue;
                }
7732 7733 7734 7735 7736 7737 7738 7739 7740 7741 7742 7743 7744 7745 7746 7747 7748 7749 7750 7751 7752 7753 7754 7755 7756 7757 7758 7759 7760 7761 7762 7763 7764 7765 7766 7767 7768 7769 7770 7771 7772 7773 7774 7775 7776

                if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT)) {
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceWeight(priv->cgroup,
                                                          devices[j].path,
                                                          devices[j].weight) < 0) {
                            ret = -1;
                            break;
                        }
                    }
                } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS)) {
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceReadIops(priv->cgroup,
                                                            devices[j].path,
                                                            devices[j].riops) < 0) {
                            ret = -1;
                            break;
                        }
                    }
                } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS)) {
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceWriteIops(priv->cgroup,
                                                             devices[j].path,
                                                             devices[j].wiops) < 0) {
                            ret = -1;
                            break;
                        }
                    }
                } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS)) {
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceReadBps(priv->cgroup,
                                                           devices[j].path,
                                                           devices[j].rbps) < 0) {
                            ret = -1;
                            break;
                        }
                    }
                } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)){
                    for (j = 0; j < ndevices; j++) {
                        if (virCgroupSetBlkioDeviceWriteBps(priv->cgroup,
                                                            devices[j].path,
                                                            devices[j].wbps) < 0) {
                            ret = -1;
                            break;
                        }
7777
                    }
7778 7779 7780 7781 7782 7783 7784 7785
                } else {
                    virReportError(VIR_ERR_INVALID_ARG, _("Unknown blkio parameter %s"),
                                   param->field);
                    ret = -1;
                    virBlkioDeviceArrayClear(devices, ndevices);
                    VIR_FREE(devices);

                    continue;
7786
                }
7787

7788
                if (j != ndevices ||
7789 7790 7791
                    qemuDomainMergeBlkioDevice(&vm->def->blkio.devices,
                                               &vm->def->blkio.ndevices,
                                               devices, ndevices, param->field) < 0)
7792
                    ret = -1;
7793
                virBlkioDeviceArrayClear(devices, ndevices);
7794
                VIR_FREE(devices);
7795
            }
7796
        }
E
Eric Blake 已提交
7797 7798 7799 7800
    }
    if (ret < 0)
        goto cleanup;
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
7801 7802 7803
        /* Clang can't see that if we get here, persistentDef was set.  */
        sa_assert(persistentDef);

7804 7805 7806 7807 7808
        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) {
7809 7810
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
7811 7812 7813 7814 7815
                    ret = -1;
                    continue;
                }

                persistentDef->blkio.weight = params[i].value.ui;
7816 7817 7818 7819 7820
            } else if (STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_READ_BPS) ||
                       STREQ(param->field, VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS)) {
7821
                virBlkioDevicePtr devices = NULL;
7822
                size_t ndevices;
7823

7824 7825 7826 7827
                if (qemuDomainParseBlkioDeviceStr(params[i].value.s,
                                                  params->field,
                                                  &devices,
                                                  &ndevices) < 0) {
7828 7829 7830
                    ret = -1;
                    continue;
                }
7831 7832 7833
                if (qemuDomainMergeBlkioDevice(&persistentDef->blkio.devices,
                                               &persistentDef->blkio.ndevices,
                                               devices, ndevices, param->field) < 0)
7834
                    ret = -1;
7835
                virBlkioDeviceArrayClear(devices, ndevices);
7836
                VIR_FREE(devices);
7837 7838
            }
        }
A
Alex Jia 已提交
7839

7840
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
A
Alex Jia 已提交
7841
            ret = -1;
7842 7843 7844 7845
    }

cleanup:
    if (vm)
7846
        virObjectUnlock(vm);
7847
    virObjectUnref(caps);
7848
    virObjectUnref(cfg);
7849 7850 7851
    return ret;
}

7852 7853 7854 7855 7856
static int
qemuDomainGetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
7857
{
7858
    virQEMUDriverPtr driver = dom->conn->privateData;
7859
    size_t i, j;
7860
    virDomainObjPtr vm = NULL;
7861
    virDomainDefPtr persistentDef = NULL;
7862 7863
    unsigned int val;
    int ret = -1;
7864
    virCapsPtr caps = NULL;
7865
    qemuDomainObjPrivatePtr priv;
7866

7867
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
7868 7869
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
7870

7871 7872 7873
    /* 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.  */
7874 7875
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

7876 7877
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
7878

7879 7880
    priv = vm->privateData;

7881 7882 7883
    if (virDomainGetBlkioParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

7884 7885 7886
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

7887 7888 7889 7890 7891 7892 7893
    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = QEMU_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
    }

7894
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
7895 7896
                                        &persistentDef) < 0)
        goto cleanup;
7897

7898
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7899
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
7900 7901
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
7902 7903 7904 7905 7906
            goto cleanup;
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7907
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
7908 7909 7910 7911 7912
            virTypedParameterPtr param = &params[i];
            val = 0;

            switch (i) {
            case 0: /* fill blkio weight here */
7913
                if (virCgroupGetBlkioWeight(priv->cgroup, &val) < 0)
7914
                    goto cleanup;
7915 7916
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT, val) < 0)
7917 7918
                    goto cleanup;
                break;
7919

7920 7921 7922 7923
            case 1: /* blkiotune.device_weight */
                if (vm->def->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;
7924

7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941
                    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);
                }
7942 7943 7944 7945
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                                            VIR_TYPED_PARAM_STRING,
                                            param->value.s) < 0)
7946 7947
                    goto cleanup;
                break;
7948

7949 7950 7951 7952 7953 7954 7955 7956 7957 7958 7959 7960 7961 7962 7963 7964 7965 7966 7967 7968 7969 7970 7971 7972 7973 7974 7975 7976 7977 7978 7979 7980 7981 7982 7983 7984 7985 7986 7987 7988 7989 7990 7991 7992 7993 7994 7995 7996 7997 7998 7999 8000 8001 8002 8003 8004 8005 8006 8007 8008 8009 8010 8011 8012 8013 8014 8015 8016 8017 8018 8019 8020 8021 8022 8023 8024 8025 8026 8027 8028 8029 8030 8031 8032 8033 8034 8035 8036 8037 8038 8039 8040 8041 8042 8043 8044 8045 8046 8047 8048 8049 8050 8051 8052 8053 8054 8055 8056 8057 8058 8059 8060 8061 8062 8063 8064
            case 2: /* blkiotune.device_read_iops */
                if (vm->def->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;

                    for (j = 0; j < vm->def->blkio.ndevices; j++) {
                        if (!vm->def->blkio.devices[j].riops)
                            continue;
                        if (comma)
                            virBufferAddChar(&buf, ',');
                        else
                            comma = true;
                        virBufferAsprintf(&buf, "%s,%u",
                                          vm->def->blkio.devices[j].path,
                                          vm->def->blkio.devices[j].riops);
                    }
                    if (virBufferError(&buf)) {
                        virReportOOMError();
                        goto cleanup;
                    }
                    param->value.s = virBufferContentAndReset(&buf);
                }
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS,
                                            VIR_TYPED_PARAM_STRING,
                                            param->value.s) < 0)
                    goto cleanup;
                break;

            case 3: /* blkiotune.device_write_iops */
                if (vm->def->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;

                    for (j = 0; j < vm->def->blkio.ndevices; j++) {
                        if (!vm->def->blkio.devices[j].wiops)
                            continue;
                        if (comma)
                            virBufferAddChar(&buf, ',');
                        else
                            comma = true;
                        virBufferAsprintf(&buf, "%s,%u",
                                          vm->def->blkio.devices[j].path,
                                          vm->def->blkio.devices[j].wiops);
                    }
                    if (virBufferError(&buf)) {
                        virReportOOMError();
                        goto cleanup;
                    }
                    param->value.s = virBufferContentAndReset(&buf);
                }
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS,
                                            VIR_TYPED_PARAM_STRING,
                                            param->value.s) < 0)
                    goto cleanup;
                break;

             case 4: /* blkiotune.device_read_bps */
                if (vm->def->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;

                    for (j = 0; j < vm->def->blkio.ndevices; j++) {
                        if (!vm->def->blkio.devices[j].rbps)
                            continue;
                        if (comma)
                            virBufferAddChar(&buf, ',');
                        else
                            comma = true;
                        virBufferAsprintf(&buf, "%s,%llu",
                                          vm->def->blkio.devices[j].path,
                                          vm->def->blkio.devices[j].rbps);
                    }
                    if (virBufferError(&buf)) {
                        virReportOOMError();
                        goto cleanup;
                    }
                    param->value.s = virBufferContentAndReset(&buf);
                }
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_BLKIO_DEVICE_READ_BPS,
                                            VIR_TYPED_PARAM_STRING,
                                            param->value.s) < 0)
                    goto cleanup;
                break;

             case 5: /* blkiotune.device_write_bps */
                if (vm->def->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;

                    for (j = 0; j < vm->def->blkio.ndevices; j++) {
                        if (!vm->def->blkio.devices[j].wbps)
                            continue;
                        if (comma)
                            virBufferAddChar(&buf, ',');
                        else
                            comma = true;
                        virBufferAsprintf(&buf, "%s,%llu",
                                          vm->def->blkio.devices[j].path,
                                          vm->def->blkio.devices[j].wbps);
                    }
                    if (virBufferError(&buf)) {
                        virReportOOMError();
                        goto cleanup;
                    }
                    param->value.s = virBufferContentAndReset(&buf);
                }
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS,
                                            VIR_TYPED_PARAM_STRING,
                                            param->value.s) < 0)
                    goto cleanup;
                break;

8065 8066 8067
            default:
                break;
                /* should not hit here */
8068
            }
8069 8070
        }
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8071
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
8072 8073 8074 8075 8076 8077 8078 8079
            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) {
8080 8081 8082
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_WEIGHT);
8083 8084 8085 8086
                    goto cleanup;
                }
                param->value.ui = persistentDef->blkio.weight;
                break;
8087

8088 8089 8090
            case 1: /* blkiotune.device_weight */
                if (persistentDef->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
8091 8092
                    bool comma = false;

8093
                    for (j = 0; j < persistentDef->blkio.ndevices; j++) {
8094 8095 8096
                        if (!persistentDef->blkio.devices[j].weight)
                            continue;
                        if (comma)
8097
                            virBufferAddChar(&buf, ',');
8098 8099
                        else
                            comma = true;
8100 8101 8102 8103 8104 8105 8106 8107 8108
                        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);
8109
                }
8110 8111
                if (!param->value.s && VIR_STRDUP(param->value.s, "") < 0)
                    goto cleanup;
8112 8113 8114
                param->type = VIR_TYPED_PARAM_STRING;
                if (virStrcpyStatic(param->field,
                                    VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) == NULL) {
8115 8116 8117
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_DEVICE_WEIGHT);
8118 8119 8120 8121
                    goto cleanup;
                }
                break;

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 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 8204 8205 8206 8207 8208 8209 8210 8211 8212 8213 8214 8215 8216 8217 8218 8219 8220 8221 8222 8223 8224 8225 8226 8227 8228 8229 8230 8231 8232 8233 8234 8235 8236 8237 8238 8239 8240 8241 8242 8243 8244 8245 8246 8247 8248 8249 8250 8251 8252 8253 8254 8255 8256
            case 2: /* blkiotune.device_read_iops */
                if (persistentDef->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;

                    for (j = 0; j < persistentDef->blkio.ndevices; j++) {
                        if (!persistentDef->blkio.devices[j].riops)
                            continue;
                        if (comma)
                            virBufferAddChar(&buf, ',');
                        else
                            comma = true;
                        virBufferAsprintf(&buf, "%s,%u",
                                          persistentDef->blkio.devices[j].path,
                                          persistentDef->blkio.devices[j].riops);
                    }
                    if (virBufferError(&buf)) {
                        virReportOOMError();
                        goto cleanup;
                    }
                    param->value.s = virBufferContentAndReset(&buf);
                }
                if (!param->value.s && VIR_STRDUP(param->value.s, "") < 0)
                    goto cleanup;
                param->type = VIR_TYPED_PARAM_STRING;
                if (virStrcpyStatic(param->field,
                                    VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS) == NULL) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_DEVICE_READ_IOPS);
                    goto cleanup;
                }
                break;
            case 3: /* blkiotune.device_write_iops */
                if (persistentDef->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;

                    for (j = 0; j < persistentDef->blkio.ndevices; j++) {
                        if (!persistentDef->blkio.devices[j].wiops)
                            continue;
                        if (comma)
                            virBufferAddChar(&buf, ',');
                        else
                            comma = true;
                        virBufferAsprintf(&buf, "%s,%u",
                                          persistentDef->blkio.devices[j].path,
                                          persistentDef->blkio.devices[j].wiops);
                    }
                    if (virBufferError(&buf)) {
                        virReportOOMError();
                        goto cleanup;
                    }
                    param->value.s = virBufferContentAndReset(&buf);
                }
                if (!param->value.s && VIR_STRDUP(param->value.s, "") < 0)
                    goto cleanup;
                param->type = VIR_TYPED_PARAM_STRING;
                if (virStrcpyStatic(param->field,
                                    VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS) == NULL) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_DEVICE_WRITE_IOPS);
                    goto cleanup;
                }
                break;
            case 4: /* blkiotune.device_read_bps */
                if (persistentDef->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;

                    for (j = 0; j < persistentDef->blkio.ndevices; j++) {
                        if (!persistentDef->blkio.devices[j].rbps)
                            continue;
                        if (comma)
                            virBufferAddChar(&buf, ',');
                        else
                            comma = true;
                        virBufferAsprintf(&buf, "%s,%llu",
                                          persistentDef->blkio.devices[j].path,
                                          persistentDef->blkio.devices[j].rbps);
                    }
                    if (virBufferError(&buf)) {
                        virReportOOMError();
                        goto cleanup;
                    }
                    param->value.s = virBufferContentAndReset(&buf);
                }
                if (!param->value.s && VIR_STRDUP(param->value.s, "") < 0)
                    goto cleanup;
                param->type = VIR_TYPED_PARAM_STRING;
                if (virStrcpyStatic(param->field,
                                    VIR_DOMAIN_BLKIO_DEVICE_READ_BPS) == NULL) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_DEVICE_READ_BPS);
                    goto cleanup;
                }
                break;

            case 5: /* blkiotune.device_write_bps */
                if (persistentDef->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;

                    for (j = 0; j < persistentDef->blkio.ndevices; j++) {
                        if (!persistentDef->blkio.devices[j].wbps)
                            continue;
                        if (comma)
                            virBufferAddChar(&buf, ',');
                        else
                            comma = true;
                        virBufferAsprintf(&buf, "%s,%llu",
                                          persistentDef->blkio.devices[j].path,
                                          persistentDef->blkio.devices[j].wbps);
                    }
                    if (virBufferError(&buf)) {
                        virReportOOMError();
                        goto cleanup;
                    }
                    param->value.s = virBufferContentAndReset(&buf);
                }
                if (!param->value.s && VIR_STRDUP(param->value.s, "") < 0)
                    goto cleanup;
                param->type = VIR_TYPED_PARAM_STRING;
                if (virStrcpyStatic(param->field,
                                    VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS) == NULL) {
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_DEVICE_WRITE_BPS);
                    goto cleanup;
                }
                break;


8257 8258 8259 8260
            default:
                break;
                /* should not hit here */
            }
8261 8262 8263
        }
    }

8264 8265
    if (QEMU_NB_BLKIO_PARAM < *nparams)
        *nparams = QEMU_NB_BLKIO_PARAM;
8266 8267 8268 8269
    ret = 0;

cleanup:
    if (vm)
8270
        virObjectUnlock(vm);
8271
    virObjectUnref(caps);
8272 8273
    return ret;
}
8274

8275 8276 8277 8278 8279
static int
qemuDomainSetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int nparams,
                              unsigned int flags)
8280
{
8281
    virQEMUDriverPtr driver = dom->conn->privateData;
8282
    virDomainDefPtr persistentDef = NULL;
8283
    virDomainObjPtr vm = NULL;
8284
    unsigned long long swap_hard_limit;
8285 8286
    unsigned long long hard_limit = 0;
    unsigned long long soft_limit = 0;
8287
    bool set_swap_hard_limit = false;
8288 8289
    bool set_hard_limit = false;
    bool set_soft_limit = false;
8290
    virQEMUDriverConfigPtr cfg = NULL;
8291
    int rc;
8292
    int ret = -1;
8293
    virCapsPtr caps = NULL;
8294
    qemuDomainObjPrivatePtr priv;
8295

8296 8297
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
8298

8299 8300 8301 8302 8303 8304 8305 8306
    if (virTypedParamsValidate(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)
8307
        return -1;
8308 8309


8310 8311
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
8312

8313
    priv = vm->privateData;
8314 8315
    cfg = virQEMUDriverGetConfig(driver);

8316 8317 8318
    if (virDomainSetMemoryParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

8319 8320 8321
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

8322
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8323 8324
                                        &persistentDef) < 0)
        goto cleanup;
8325

8326
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8327
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
8328 8329
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
8330 8331 8332 8333
            goto cleanup;
        }
    }

8334
#define VIR_GET_LIMIT_PARAMETER(PARAM, VALUE)                                \
8335
    if ((rc = virTypedParamsGetULLong(params, nparams, PARAM, &VALUE)) < 0)  \
8336 8337 8338 8339 8340 8341
        goto cleanup;                                                        \
                                                                             \
    if (rc == 1)                                                             \
        set_ ## VALUE = true;

    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT, swap_hard_limit)
8342 8343
    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_HARD_LIMIT, hard_limit)
    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_SOFT_LIMIT, soft_limit)
8344 8345 8346

#undef VIR_GET_LIMIT_PARAMETER

8347 8348 8349 8350 8351
    /* Swap hard limit must be greater than hard limit.
     * Note that limit of 0 denotes unlimited */
    if (set_swap_hard_limit || set_hard_limit) {
        unsigned long long mem_limit = vm->def->mem.hard_limit;
        unsigned long long swap_limit = vm->def->mem.swap_hard_limit;
8352

8353 8354
        if (set_swap_hard_limit)
            swap_limit = swap_hard_limit;
8355

8356 8357 8358 8359 8360 8361
        if (set_hard_limit)
            mem_limit = hard_limit;

        if (virCompareLimitUlong(mem_limit, swap_limit) > 0) {
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("memory hard_limit tunable value must be lower "
8362
                             "than or equal to swap_hard_limit"));
8363
            goto cleanup;
8364
        }
8365
    }
8366

8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380
#define QEMU_SET_MEM_PARAMETER(FUNC, VALUE)                                     \
    if (set_ ## VALUE) {                                                        \
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {                                   \
            if ((rc = FUNC(priv->cgroup, VALUE)) < 0) {                         \
                virReportSystemError(-rc, _("unable to set memory %s tunable"), \
                                     #VALUE);                                   \
                                                                                \
                goto cleanup;                                                   \
            }                                                                   \
            vm->def->mem.VALUE = VALUE;                                         \
        }                                                                       \
                                                                                \
        if (flags & VIR_DOMAIN_AFFECT_CONFIG)                                   \
            persistentDef->mem.VALUE = VALUE;                                   \
8381 8382
    }

8383 8384
    /* Soft limit doesn't clash with the others */
    QEMU_SET_MEM_PARAMETER(virCgroupSetMemorySoftLimit, soft_limit);
8385

8386 8387 8388 8389 8390
    /* set hard limit before swap hard limit if decreasing it */
    if (virCompareLimitUlong(vm->def->mem.hard_limit, hard_limit) > 0) {
        QEMU_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);
        /* inhibit changing the limit a second time */
        set_hard_limit = false;
8391
    }
8392

8393
    QEMU_SET_MEM_PARAMETER(virCgroupSetMemSwapHardLimit, swap_hard_limit);
8394

8395 8396 8397 8398
    /* otherwise increase it after swap hard limit */
    QEMU_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);

#undef QEMU_SET_MEM_PARAMETER
8399

8400 8401 8402 8403 8404 8405
    if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
        virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
        goto cleanup;

    ret = 0;

8406
cleanup:
8407
    virObjectUnlock(vm);
8408
    virObjectUnref(caps);
8409
    virObjectUnref(cfg);
8410 8411 8412
    return ret;
}

8413 8414 8415 8416 8417
static int
qemuDomainGetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int *nparams,
                              unsigned int flags)
8418
{
8419
    virQEMUDriverPtr driver = dom->conn->privateData;
8420
    size_t i;
8421
    virDomainObjPtr vm = NULL;
8422
    virDomainDefPtr persistentDef = NULL;
8423
    int ret = -1;
8424
    virCapsPtr caps = NULL;
8425
    qemuDomainObjPrivatePtr priv;
8426

8427
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
8428 8429
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
8430

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

8434 8435
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
8436

8437
    priv = vm->privateData;
8438 8439 8440 8441

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

8442 8443 8444
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

8445
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8446 8447
                                        &persistentDef) < 0)
        goto cleanup;
8448

8449
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8450
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
8451 8452
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
8453 8454 8455 8456
            goto cleanup;
        }
    }

8457 8458 8459 8460 8461 8462 8463
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = QEMU_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

8464
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8465
        for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
8466
            virMemoryParameterPtr param = &params[i];
8467
            unsigned long long value;
8468 8469 8470

            switch (i) {
            case 0: /* fill memory hard limit here */
8471 8472 8473 8474
                value = persistentDef->mem.hard_limit;
                value = value ? value : VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
                if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG, value) < 0)
8475 8476 8477 8478
                    goto cleanup;
                break;

            case 1: /* fill memory soft limit here */
8479 8480 8481 8482
                value = persistentDef->mem.soft_limit;
                value = value ? value : VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
                if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG, value) < 0)
8483 8484 8485 8486
                    goto cleanup;
                break;

            case 2: /* fill swap hard limit here */
8487 8488 8489 8490
                value = persistentDef->mem.swap_hard_limit;
                value = value ? value : VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
                if (virTypedParameterAssign(param, VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                            VIR_TYPED_PARAM_ULLONG, value) < 0)
8491 8492 8493 8494 8495 8496 8497 8498 8499
                    goto cleanup;
                break;

            default:
                break;
                /* should not hit here */
            }
        }
        goto out;
8500 8501
    }

8502
    for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
8503
        virTypedParameterPtr param = &params[i];
8504
        unsigned long long val = 0;
8505

8506
        switch (i) {
8507
        case 0: /* fill memory hard limit here */
8508
            if (virCgroupGetMemoryHardLimit(priv->cgroup, &val) < 0)
8509
                goto cleanup;
8510 8511 8512
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
8513
                goto cleanup;
8514 8515 8516
            break;

        case 1: /* fill memory soft limit here */
8517
            if (virCgroupGetMemorySoftLimit(priv->cgroup, &val) < 0)
8518
                goto cleanup;
8519 8520 8521
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
8522
                goto cleanup;
8523 8524 8525
            break;

        case 2: /* fill swap hard limit here */
8526 8527 8528
            if (virCgroupGetMemSwapHardLimit(priv->cgroup, &val) < 0) {
                if (!virLastErrorIsSystemErrno(ENOENT) &&
                    !virLastErrorIsSystemErrno(EOPNOTSUPP))
8529 8530
                    goto cleanup;
                val = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
8531
            }
8532 8533 8534
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
8535
                goto cleanup;
8536 8537 8538 8539 8540 8541 8542 8543
            break;

        default:
            break;
            /* should not hit here */
        }
    }

8544
out:
8545 8546
    if (QEMU_NB_MEM_PARAM < *nparams)
        *nparams = QEMU_NB_MEM_PARAM;
8547 8548
    ret = 0;

8549 8550
cleanup:
    if (vm)
8551
        virObjectUnlock(vm);
8552
    virObjectUnref(caps);
8553 8554 8555
    return ret;
}

8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574
static int
qemuDomainSetNumaParamsLive(virDomainObjPtr vm,
                            virCapsPtr caps,
                            virBitmapPtr nodeset)
{
    virCgroupPtr cgroup_temp = NULL;
    virBitmapPtr temp_nodeset = NULL;
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *nodeset_str = NULL;
    size_t i = 0;
    int ret = -1;

    if (vm->def->numatune.memory.mode != VIR_DOMAIN_NUMATUNE_MEM_STRICT) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("change of nodeset for running domain "
                         "requires strict numa mode"));
        goto cleanup;
    }

8575
    /* Get existing nodeset values */
8576 8577 8578 8579 8580 8581 8582 8583
    if (virCgroupGetCpusetMems(priv->cgroup, &nodeset_str) < 0 ||
        virBitmapParse(nodeset_str, 0, &temp_nodeset,
                       VIR_DOMAIN_CPUMASK_LEN) < 0)
        goto cleanup;
    VIR_FREE(nodeset_str);

    for (i = 0; i < caps->host.nnumaCell; i++) {
        bool result;
8584 8585
        virCapsHostNUMACellPtr cell = caps->host.numaCell[i];
        if (virBitmapGetBit(nodeset, cell->num, &result) < 0) {
8586 8587 8588 8589
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Failed to get cpuset bit values"));
            goto cleanup;
        }
8590
        if (result && (virBitmapSetBit(temp_nodeset, cell->num) < 0)) {
8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Failed to set temporary cpuset bit values"));
            goto cleanup;
        }
    }

    if (!(nodeset_str = virBitmapFormat(temp_nodeset))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to format nodeset"));
        goto cleanup;
    }

    if (virCgroupSetCpusetMems(priv->cgroup, nodeset_str) < 0)
        goto cleanup;
    VIR_FREE(nodeset_str);

8607
    /* Ensure the cpuset string is formatted before passing to cgroup */
8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634
    if (!(nodeset_str = virBitmapFormat(nodeset))) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Failed to format nodeset"));
        goto cleanup;
    }

    for (i = 0; i < priv->nvcpupids; i++) {
        if (virCgroupNewVcpu(priv->cgroup, i, false, &cgroup_temp) < 0 ||
            virCgroupSetCpusetMems(cgroup_temp, nodeset_str) < 0)
            goto cleanup;
        virCgroupFree(&cgroup_temp);
    }

    if (virCgroupNewEmulator(priv->cgroup, false, &cgroup_temp) < 0 ||
        virCgroupSetCpusetMems(cgroup_temp, nodeset_str) < 0 ||
        virCgroupSetCpusetMems(priv->cgroup, nodeset_str) < 0)
        goto cleanup;

    ret = 0;
 cleanup:
    VIR_FREE(nodeset_str);
    virBitmapFree(temp_nodeset);
    virCgroupFree(&cgroup_temp);

    return ret;
}

8635 8636 8637 8638 8639 8640
static int
qemuDomainSetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
{
8641
    virQEMUDriverPtr driver = dom->conn->privateData;
8642
    size_t i;
8643 8644 8645
    virDomainDefPtr persistentDef = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
8646
    virQEMUDriverConfigPtr cfg = NULL;
8647
    virCapsPtr caps = NULL;
8648
    qemuDomainObjPrivatePtr priv;
8649 8650 8651

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
8652

8653 8654 8655 8656 8657 8658
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_NUMA_MODE,
                               VIR_TYPED_PARAM_INT,
                               VIR_DOMAIN_NUMA_NODESET,
                               VIR_TYPED_PARAM_STRING,
                               NULL) < 0)
8659
        return -1;
8660

8661 8662
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
8663

8664
    priv = vm->privateData;
8665
    cfg = virQEMUDriverGetConfig(driver);
8666

8667 8668 8669
    if (virDomainSetNumaParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

8670 8671 8672
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

8673
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8674 8675 8676 8677
                                        &persistentDef) < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8678
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) {
8679 8680
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cgroup cpuset controller is not mounted"));
8681 8682 8683 8684 8685 8686 8687 8688
            goto cleanup;
        }
    }

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

        if (STREQ(param->field, VIR_DOMAIN_NUMA_MODE)) {
8689 8690
            int mode = param->value.i;

8691 8692 8693 8694 8695 8696 8697 8698
            if (mode >= VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_LAST ||
                mode < VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_DEFAULT)
            {
                virReportError(VIR_ERR_INVALID_ARG,
                               _("unsupported numa_mode: '%d'"), mode);
                goto cleanup;
            }

8699
            if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
8700
                vm->def->numatune.memory.mode != mode) {
8701 8702
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("can't change numa mode for running domain"));
8703 8704 8705
                goto cleanup;
            }

8706 8707 8708
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                persistentDef->numatune.memory.mode = mode;

8709
        } else if (STREQ(param->field, VIR_DOMAIN_NUMA_NODESET)) {
8710
            virBitmapPtr nodeset = NULL;
8711

8712
            if (virBitmapParse(param->value.s, 0, &nodeset,
8713
                               VIR_DOMAIN_CPUMASK_LEN) < 0) {
8714
                goto cleanup;
8715
            }
8716 8717

            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8718
                if (qemuDomainSetNumaParamsLive(vm, caps, nodeset) < 0) {
8719
                    virBitmapFree(nodeset);
8720
                    goto cleanup;
8721 8722 8723 8724
                }

                /* update vm->def here so that dumpxml can read the new
                 * values from vm->def. */
8725
                virBitmapFree(vm->def->numatune.memory.nodemask);
8726

8727
                vm->def->numatune.memory.placement_mode =
G
Gao feng 已提交
8728
                    VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC;
8729
                vm->def->numatune.memory.nodemask = virBitmapNewCopy(nodeset);
8730 8731 8732
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8733
                virBitmapFree(persistentDef->numatune.memory.nodemask);
8734 8735

                persistentDef->numatune.memory.nodemask = nodeset;
8736
                persistentDef->numatune.memory.placement_mode =
G
Gao feng 已提交
8737
                    VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC;
8738
                nodeset = NULL;
8739
            }
8740
            virBitmapFree(nodeset);
8741 8742 8743 8744
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8745 8746
        if (!persistentDef->numatune.memory.placement_mode)
            persistentDef->numatune.memory.placement_mode =
G
Gao feng 已提交
8747
                VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_AUTO;
8748
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
8749
            goto cleanup;
8750 8751
    }

8752 8753
    ret = 0;

8754 8755
cleanup:
    if (vm)
8756
        virObjectUnlock(vm);
8757
    virObjectUnref(caps);
8758
    virObjectUnref(cfg);
8759 8760 8761 8762 8763 8764 8765 8766 8767
    return ret;
}

static int
qemuDomainGetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
{
8768
    virQEMUDriverPtr driver = dom->conn->privateData;
8769
    size_t i;
8770 8771 8772 8773
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    char *nodeset = NULL;
    int ret = -1;
8774
    virCapsPtr caps = NULL;
8775
    qemuDomainObjPrivatePtr priv;
8776 8777 8778 8779 8780 8781 8782 8783 8784 8785

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

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

8786 8787
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
8788

8789 8790
    priv = vm->privateData;

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

8794 8795 8796
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

8797
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8798 8799 8800 8801 8802 8803 8804 8805 8806 8807
                                        &persistentDef) < 0)
        goto cleanup;

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

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8808
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
8809 8810
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
8811 8812 8813 8814 8815 8816 8817 8818 8819
            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 */
8820 8821
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_MODE,
                                        VIR_TYPED_PARAM_INT, 0) < 0)
8822 8823 8824 8825 8826 8827 8828 8829 8830
                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) {
8831
                nodeset = virBitmapFormat(persistentDef->numatune.memory.nodemask);
8832 8833
                if (!nodeset && VIR_STRDUP(nodeset, "") < 0)
                    goto cleanup;
8834
            } else {
8835
                if (virCgroupGetCpusetMems(priv->cgroup, &nodeset) < 0)
8836 8837
                    goto cleanup;
            }
8838 8839
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_NODESET,
                                        VIR_TYPED_PARAM_STRING, nodeset) < 0)
8840
                goto cleanup;
S
Stefan Berger 已提交
8841 8842 8843

            nodeset = NULL;

8844 8845 8846 8847 8848 8849 8850 8851 8852 8853 8854 8855 8856
            break;

        default:
            break;
            /* should not hit here */
        }
    }

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

cleanup:
S
Stefan Berger 已提交
8857
    VIR_FREE(nodeset);
8858
    if (vm)
8859
        virObjectUnlock(vm);
8860
    virObjectUnref(caps);
8861 8862 8863
    return ret;
}

8864 8865 8866 8867
static int
qemuSetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup,
                   unsigned long long period, long long quota)
{
8868
    size_t i;
8869 8870 8871 8872 8873 8874
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virCgroupPtr cgroup_vcpu = NULL;

    if (period == 0 && quota == 0)
        return 0;

W
Wen Congyang 已提交
8875 8876 8877 8878 8879 8880
    /* 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++) {
8881
            if (virCgroupNewVcpu(cgroup, i, false, &cgroup_vcpu) < 0)
W
Wen Congyang 已提交
8882 8883 8884 8885 8886 8887 8888
                goto cleanup;

            if (qemuSetupCgroupVcpuBW(cgroup_vcpu, period, quota) < 0)
                goto cleanup;

            virCgroupFree(&cgroup_vcpu);
        }
8889 8890 8891 8892 8893 8894 8895 8896 8897
    }

    return 0;

cleanup:
    virCgroupFree(&cgroup_vcpu);
    return -1;
}

8898 8899 8900 8901 8902 8903 8904 8905 8906 8907 8908 8909 8910 8911
static int
qemuSetEmulatorBandwidthLive(virDomainObjPtr vm, virCgroupPtr cgroup,
                             unsigned long long period, long long quota)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virCgroupPtr cgroup_emulator = NULL;

    if (period == 0 && quota == 0)
        return 0;

    if (priv->nvcpupids == 0 || priv->vcpupids[0] == vm->pid) {
        return 0;
    }

8912
    if (virCgroupNewEmulator(cgroup, false, &cgroup_emulator) < 0)
8913 8914 8915 8916 8917 8918 8919 8920 8921 8922 8923 8924 8925
        goto cleanup;

    if (qemuSetupCgroupVcpuBW(cgroup_emulator, period, quota) < 0)
        goto cleanup;

    virCgroupFree(&cgroup_emulator);
    return 0;

cleanup:
    virCgroupFree(&cgroup_emulator);
    return -1;
}

8926 8927 8928 8929 8930 8931 8932 8933 8934
#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;                                                       \
    }

8935
static int
8936 8937 8938 8939
qemuDomainSetSchedulerParametersFlags(virDomainPtr dom,
                                      virTypedParameterPtr params,
                                      int nparams,
                                      unsigned int flags)
8940
{
8941
    virQEMUDriverPtr driver = dom->conn->privateData;
8942
    size_t i;
8943
    virDomainObjPtr vm = NULL;
8944
    virDomainDefPtr vmdef = NULL;
8945 8946
    unsigned long long value_ul;
    long long value_l;
8947
    int ret = -1;
8948
    int rc;
8949
    virQEMUDriverConfigPtr cfg = NULL;
8950
    virCapsPtr caps = NULL;
8951
    qemuDomainObjPrivatePtr priv;
8952

8953 8954
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
8955 8956 8957 8958 8959 8960 8961 8962 8963 8964 8965 8966
    if (virTypedParamsValidate(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,
                               VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
                               VIR_TYPED_PARAM_ULLONG,
                               VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
                               VIR_TYPED_PARAM_LLONG,
                               NULL) < 0)
8967
        return -1;
8968

8969 8970
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
8971

8972
    priv = vm->privateData;
8973 8974
    cfg = virQEMUDriverGetConfig(driver);

8975 8976 8977
    if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

8978 8979 8980
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

8981
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8982 8983
                                        &vmdef) < 0)
        goto cleanup;
8984

8985 8986
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
8987
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
8988 8989
        if (!vmdef)
            goto cleanup;
8990 8991
    }

8992
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8993
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
8994 8995
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup CPU controller is not mounted"));
8996 8997 8998 8999
            goto cleanup;
        }
    }

9000
    for (i = 0; i < nparams; i++) {
9001
        virTypedParameterPtr param = &params[i];
9002 9003
        value_ul = param->value.ul;
        value_l = param->value.l;
9004

9005
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
9006
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
9007
                if (virCgroupSetCpuShares(priv->cgroup, value_ul) < 0)
9008
                    goto cleanup;
9009
                vm->def->cputune.shares = value_ul;
9010
            }
9011

9012 9013 9014
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.shares = value_ul;

9015
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
9016 9017 9018
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

9019
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
9020
                if ((rc = qemuSetVcpusBWLive(vm, priv->cgroup, value_ul, 0)))
9021
                    goto cleanup;
9022

9023
                vm->def->cputune.period = value_ul;
9024 9025
            }

9026
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
9027
                vmdef->cputune.period = params[i].value.ul;
9028

9029
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
9030 9031 9032
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

9033
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
9034
                if ((rc = qemuSetVcpusBWLive(vm, priv->cgroup, 0, value_l)))
9035
                    goto cleanup;
9036

9037
                vm->def->cputune.quota = value_l;
9038 9039
            }

9040 9041 9042
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.quota = value_l;

9043
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD)) {
9044 9045 9046
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

9047
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
9048 9049
                if ((rc = qemuSetEmulatorBandwidthLive(vm, priv->cgroup,
                                                       value_ul, 0)))
9050 9051
                    goto cleanup;

9052
                vm->def->cputune.emulator_period = value_ul;
9053 9054
            }

9055 9056 9057
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_period = value_ul;

9058
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA)) {
9059 9060 9061
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

9062
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
9063 9064
                if ((rc = qemuSetEmulatorBandwidthLive(vm, priv->cgroup,
                                                       0, value_l)))
9065 9066
                    goto cleanup;

9067
                vm->def->cputune.emulator_quota = value_l;
9068 9069
            }

9070 9071
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_quota = value_l;
9072 9073
        }
    }
9074

9075
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
9076 9077 9078 9079
        goto cleanup;


    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
9080
        rc = virDomainSaveConfig(cfg->configDir, vmdef);
9081 9082 9083
        if (rc < 0)
            goto cleanup;

9084
        virDomainObjAssignDef(vm, vmdef, false, NULL);
9085 9086 9087
        vmdef = NULL;
    }

9088 9089 9090
    ret = 0;

cleanup:
9091
    virDomainDefFree(vmdef);
9092
    if (vm)
9093
        virObjectUnlock(vm);
9094
    virObjectUnref(caps);
9095
    virObjectUnref(cfg);
9096 9097
    return ret;
}
9098
#undef SCHED_RANGE_CHECK
9099

9100
static int
9101 9102 9103
qemuDomainSetSchedulerParameters(virDomainPtr dom,
                                 virTypedParameterPtr params,
                                 int nparams)
9104
{
9105 9106 9107 9108
    return qemuDomainSetSchedulerParametersFlags(dom,
                                                 params,
                                                 nparams,
                                                 VIR_DOMAIN_AFFECT_CURRENT);
9109 9110
}

9111 9112 9113 9114
static int
qemuGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
                  long long *quota)
{
9115
    if (virCgroupGetCpuCfsPeriod(cgroup, period) < 0)
9116 9117
        return -1;

9118
    if (virCgroupGetCpuCfsQuota(cgroup, quota) < 0)
9119 9120 9121 9122 9123 9124
        return -1;

    return 0;
}

static int
9125
qemuGetVcpusBWLive(virDomainObjPtr vm,
9126 9127 9128 9129 9130 9131 9132 9133 9134 9135
                   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 */
9136
        rc = qemuGetVcpuBWLive(priv->cgroup, period, quota);
9137 9138 9139 9140 9141 9142 9143 9144 9145
        if (rc < 0)
            goto cleanup;

        if (*quota > 0)
            *quota /= vm->def->vcpus;
        goto out;
    }

    /* get period and quota for vcpu0 */
9146
    if (virCgroupNewVcpu(priv->cgroup, 0, false, &cgroup_vcpu) < 0)
9147 9148 9149 9150 9151 9152 9153 9154 9155 9156 9157 9158 9159 9160
        goto cleanup;

    rc = qemuGetVcpuBWLive(cgroup_vcpu, period, quota);
    if (rc < 0)
        goto cleanup;

out:
    ret = 0;

cleanup:
    virCgroupFree(&cgroup_vcpu);
    return ret;
}

9161 9162 9163 9164 9165 9166 9167 9168 9169 9170 9171 9172 9173 9174 9175 9176 9177 9178
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 */
9179
    if (virCgroupNewEmulator(cgroup, false, &cgroup_emulator) < 0)
9180 9181 9182 9183 9184 9185 9186 9187 9188 9189 9190 9191 9192
        goto cleanup;

    rc = qemuGetVcpuBWLive(cgroup_emulator, period, quota);
    if (rc < 0)
        goto cleanup;

    ret = 0;

cleanup:
    virCgroupFree(&cgroup_emulator);
    return ret;
}

9193
static int
9194 9195 9196 9197
qemuDomainGetSchedulerParametersFlags(virDomainPtr dom,
                                      virTypedParameterPtr params,
                                      int *nparams,
                                      unsigned int flags)
9198
{
9199
    virQEMUDriverPtr driver = dom->conn->privateData;
9200
    virDomainObjPtr vm = NULL;
9201 9202 9203
    unsigned long long shares;
    unsigned long long period;
    long long quota;
9204 9205
    unsigned long long emulator_period;
    long long emulator_quota;
9206 9207
    int ret = -1;
    int rc;
9208
    bool cpu_bw_status = false;
9209
    int saved_nparams = 0;
9210
    virDomainDefPtr persistentDef;
9211
    virCapsPtr caps = NULL;
9212
    qemuDomainObjPrivatePtr priv;
9213

9214
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
9215 9216
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
9217

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

9221 9222 9223 9224 9225
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;

    priv = vm->privateData;

9226 9227 9228
    if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

9229 9230
    if (*nparams > 1)
        cpu_bw_status = virCgroupSupportsCpuBW(priv->cgroup);
9231

9232 9233 9234
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

9235
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
9236 9237
                                        &persistentDef) < 0)
        goto cleanup;
9238

9239
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
9240
        shares = persistentDef->cputune.shares;
9241
        if (*nparams > 1) {
9242 9243
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
9244 9245
            emulator_period = persistentDef->cputune.emulator_period;
            emulator_quota = persistentDef->cputune.emulator_quota;
9246
            cpu_bw_status = true; /* Allow copy of data to params[] */
9247
        }
9248
        goto out;
9249 9250
    }

9251
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
9252 9253
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
9254 9255 9256
        goto cleanup;
    }

9257
    if (virCgroupGetCpuShares(priv->cgroup, &shares) < 0)
9258
        goto cleanup;
9259 9260

    if (*nparams > 1 && cpu_bw_status) {
9261
        rc = qemuGetVcpusBWLive(vm, &period, &quota);
9262 9263 9264
        if (rc != 0)
            goto cleanup;
    }
9265 9266

    if (*nparams > 3 && cpu_bw_status) {
9267
        rc = qemuGetEmulatorBandwidthLive(vm, priv->cgroup, &emulator_period,
9268 9269 9270 9271 9272
                                          &emulator_quota);
        if (rc != 0)
            goto cleanup;
    }

9273
out:
9274 9275
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
9276
        goto cleanup;
9277 9278 9279 9280
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
9281 9282 9283
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
9284 9285 9286 9287 9288
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
9289 9290 9291
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
9292 9293 9294
                goto cleanup;
            saved_nparams++;
        }
9295 9296 9297 9298 9299 9300 9301 9302 9303 9304 9305 9306 9307 9308 9309 9310 9311 9312

        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++;
        }
9313 9314 9315 9316
    }

    *nparams = saved_nparams;

9317 9318 9319 9320
    ret = 0;

cleanup:
    if (vm)
9321
        virObjectUnlock(vm);
9322
    virObjectUnref(caps);
9323 9324 9325
    return ret;
}

9326
static int
9327 9328 9329
qemuDomainGetSchedulerParameters(virDomainPtr dom,
                                 virTypedParameterPtr params,
                                 int *nparams)
9330
{
9331 9332
    return qemuDomainGetSchedulerParametersFlags(dom, params, nparams,
                                                 VIR_DOMAIN_AFFECT_CURRENT);
9333
}
9334

9335 9336 9337 9338 9339 9340 9341
/**
 * 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 已提交
9342 9343 9344 9345
qemuDomainBlockResize(virDomainPtr dom,
                      const char *path,
                      unsigned long long size,
                      unsigned int flags)
9346
{
9347
    virQEMUDriverPtr driver = dom->conn->privateData;
9348 9349
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
9350
    int ret = -1, idx;
9351 9352 9353
    char *device = NULL;
    virDomainDiskDefPtr disk = NULL;

E
Eric Blake 已提交
9354
    virCheckFlags(VIR_DOMAIN_BLOCK_RESIZE_BYTES, -1);
9355 9356

    if (path[0] == '\0') {
9357 9358
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("empty path"));
9359 9360 9361
        return -1;
    }

E
Eric Blake 已提交
9362 9363 9364
    /* We prefer operating on bytes.  */
    if ((flags & VIR_DOMAIN_BLOCK_RESIZE_BYTES) == 0) {
        if (size > ULLONG_MAX / 1024) {
9365 9366 9367
            virReportError(VIR_ERR_OVERFLOW,
                           _("size must be less than %llu"),
                           ULLONG_MAX / 1024);
E
Eric Blake 已提交
9368 9369 9370
            return -1;
        }
        size *= 1024;
9371 9372
    }

9373
    if (!(vm = qemuDomObjFromDomain(dom)))
9374 9375 9376 9377
        goto cleanup;

    priv = vm->privateData;

9378 9379 9380
    if (virDomainBlockResizeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

9381 9382 9383 9384
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

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

9390
    if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
9391 9392
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
9393
        goto endjob;
9394
    }
9395
    disk = vm->def->disks[idx];
9396 9397

    if (virAsprintf(&device, "%s%s", QEMU_DRIVE_HOST_PREFIX,
9398
                    disk->info.alias) < 0)
9399 9400 9401 9402 9403 9404 9405 9406 9407 9408 9409 9410
        goto endjob;

    qemuDomainObjEnterMonitor(driver, vm);
    if (qemuMonitorBlockResize(priv->mon, device, size) < 0) {
        qemuDomainObjExitMonitor(driver, vm);
        goto endjob;
    }
    qemuDomainObjExitMonitor(driver, vm);

    ret = 0;

endjob:
E
Eric Blake 已提交
9411
    if (!qemuDomainObjEndJob(driver, vm))
9412 9413 9414 9415 9416
        vm = NULL;

cleanup:
    VIR_FREE(device);
    if (vm)
9417
        virObjectUnlock(vm);
9418 9419 9420
    return ret;
}

9421 9422 9423 9424 9425
/* 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
9426 9427 9428
qemuDomainBlockStats(virDomainPtr dom,
                     const char *path,
                     struct _virDomainBlockStats *stats)
9429
{
9430
    virQEMUDriverPtr driver = dom->conn->privateData;
9431 9432
    int idx;
    int ret = -1;
9433
    virDomainObjPtr vm;
9434
    virDomainDiskDefPtr disk = NULL;
9435
    qemuDomainObjPrivatePtr priv;
9436

9437
    if (!(vm = qemuDomObjFromDomain(dom)))
9438
        goto cleanup;
9439

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

9443 9444 9445
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;

9446
    if (!virDomainObjIsActive(vm)) {
9447 9448
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9449
        goto endjob;
9450 9451
    }

9452
    if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
9453 9454
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
9455
        goto endjob;
9456
    }
9457
    disk = vm->def->disks[idx];
9458

9459
    if (!disk->info.alias) {
9460 9461
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing disk device alias name for %s"), disk->dst);
9462
        goto endjob;
9463
    }
9464

9465
    priv = vm->privateData;
9466

9467
    qemuDomainObjEnterMonitor(driver, vm);
9468 9469 9470 9471
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
                                       disk->info.alias,
                                       &stats->rd_req,
                                       &stats->rd_bytes,
9472
                                       NULL,
9473 9474
                                       &stats->wr_req,
                                       &stats->wr_bytes,
9475 9476 9477
                                       NULL,
                                       NULL,
                                       NULL,
9478 9479
                                       &stats->errs);
    qemuDomainObjExitMonitor(driver, vm);
9480

9481
endjob:
E
Eric Blake 已提交
9482
    if (!qemuDomainObjEndJob(driver, vm))
9483
        vm = NULL;
9484

9485
cleanup:
9486
    if (vm)
9487
        virObjectUnlock(vm);
9488
    return ret;
9489 9490
}

9491
static int
9492 9493 9494 9495 9496
qemuDomainBlockStatsFlags(virDomainPtr dom,
                          const char *path,
                          virTypedParameterPtr params,
                          int *nparams,
                          unsigned int flags)
9497
{
9498
    virQEMUDriverPtr driver = dom->conn->privateData;
9499 9500
    int idx;
    int tmp, ret = -1;
9501 9502 9503 9504 9505
    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;
9506
    virTypedParameterPtr param;
9507

9508 9509 9510 9511
    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

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

9513
    if (!(vm = qemuDomObjFromDomain(dom)))
9514 9515
        goto cleanup;

9516 9517 9518
    if (virDomainBlockStatsFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

9519 9520 9521
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;

9522
    if (!virDomainObjIsActive(vm)) {
9523 9524
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9525
        goto endjob;
9526 9527 9528
    }

    if (*nparams != 0) {
9529
        if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
9530 9531
            virReportError(VIR_ERR_INVALID_ARG,
                           _("invalid path: %s"), path);
9532
            goto endjob;
9533
        }
9534
        disk = vm->def->disks[idx];
9535 9536

        if (!disk->info.alias) {
9537 9538 9539
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("missing disk device alias name for %s"),
                            disk->dst);
9540
             goto endjob;
9541 9542 9543 9544 9545 9546 9547 9548 9549 9550
        }
    }

    priv = vm->privateData;
    VIR_DEBUG("priv=%p, params=%p, flags=%x", priv, params, flags);

    qemuDomainObjEnterMonitor(driver, vm);
    tmp = *nparams;
    ret = qemuMonitorGetBlockStatsParamsNumber(priv->mon, nparams);

9551
    if (tmp == 0 || ret < 0) {
9552 9553 9554 9555 9556 9557 9558 9559 9560 9561 9562 9563 9564 9565 9566 9567 9568 9569 9570 9571 9572
        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;

9573 9574
    tmp = 0;
    ret = -1;
9575

9576 9577
    if (tmp < *nparams && wr_bytes != -1) {
        param = &params[tmp];
9578 9579
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES,
                                    VIR_TYPED_PARAM_LLONG, wr_bytes) < 0)
9580 9581 9582
            goto endjob;
        tmp++;
    }
9583

9584
    if (tmp < *nparams && wr_req != -1) {
9585
        param = &params[tmp];
9586 9587
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ,
                                    VIR_TYPED_PARAM_LLONG, wr_req) < 0)
9588 9589 9590
            goto endjob;
        tmp++;
    }
9591

9592
    if (tmp < *nparams && rd_bytes != -1) {
9593
        param = &params[tmp];
9594 9595
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_BYTES,
                                    VIR_TYPED_PARAM_LLONG, rd_bytes) < 0)
9596 9597 9598
            goto endjob;
        tmp++;
    }
9599

9600
    if (tmp < *nparams && rd_req != -1) {
9601
        param = &params[tmp];
9602 9603
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_REQ,
                                    VIR_TYPED_PARAM_LLONG, rd_req) < 0)
9604 9605 9606
            goto endjob;
        tmp++;
    }
9607

9608
    if (tmp < *nparams && flush_req != -1) {
9609
        param = &params[tmp];
9610 9611
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ,
                                    VIR_TYPED_PARAM_LLONG, flush_req) < 0)
9612 9613 9614
            goto endjob;
        tmp++;
    }
9615

9616
    if (tmp < *nparams && wr_total_times != -1) {
9617
        param = &params[tmp];
9618 9619 9620
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, wr_total_times) < 0)
9621 9622 9623
            goto endjob;
        tmp++;
    }
9624

9625
    if (tmp < *nparams && rd_total_times != -1) {
9626
        param = &params[tmp];
9627 9628 9629
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, rd_total_times) < 0)
9630 9631 9632
            goto endjob;
        tmp++;
    }
9633

9634
    if (tmp < *nparams && flush_total_times != -1) {
9635
        param = &params[tmp];
9636 9637 9638 9639
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_FLUSH_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG,
                                    flush_total_times) < 0)
9640 9641
            goto endjob;
        tmp++;
9642 9643
    }

9644 9645 9646 9647 9648
    /* Field 'errs' is meaningless for QEMU, won't set it. */

    ret = 0;
    *nparams = tmp;

9649
endjob:
E
Eric Blake 已提交
9650
    if (!qemuDomainObjEndJob(driver, vm))
9651 9652 9653 9654
        vm = NULL;

cleanup:
    if (vm)
9655
        virObjectUnlock(vm);
9656 9657 9658
    return ret;
}

9659
#ifdef __linux__
9660
static int
9661 9662 9663
qemuDomainInterfaceStats(virDomainPtr dom,
                         const char *path,
                         struct _virDomainInterfaceStats *stats)
9664
{
9665
    virDomainObjPtr vm;
9666
    size_t i;
9667
    int ret = -1;
9668

9669
    if (!(vm = qemuDomObjFromDomain(dom)))
9670
        goto cleanup;
9671

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

D
Daniel P. Berrange 已提交
9675
    if (!virDomainObjIsActive(vm)) {
9676 9677
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9678
        goto cleanup;
9679 9680 9681
    }

    /* Check the path is one of the domain's network interfaces. */
9682
    for (i = 0; i < vm->def->nnets; i++) {
9683
        if (vm->def->nets[i]->ifname &&
9684
            STREQ(vm->def->nets[i]->ifname, path)) {
9685 9686 9687
            ret = 0;
            break;
        }
9688 9689
    }

9690
    if (ret == 0)
9691
        ret = linuxDomainInterfaceStats(path, stats);
9692
    else
9693 9694
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path, '%s' is not a known interface"), path);
9695

9696
cleanup:
9697
    if (vm)
9698
        virObjectUnlock(vm);
9699 9700
    return ret;
}
9701
#else
9702
static int
E
Eric Blake 已提交
9703
qemuDomainInterfaceStats(virDomainPtr dom ATTRIBUTE_UNUSED,
9704 9705
                         const char *path ATTRIBUTE_UNUSED,
                         struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
9706
{
9707 9708
    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("interface stats not implemented on this platform"));
9709 9710
    return -1;
}
9711
#endif
9712

9713 9714 9715 9716 9717 9718 9719
static int
qemuDomainSetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 unsigned int flags)
{
9720
    virQEMUDriverPtr driver = dom->conn->privateData;
9721
    size_t i;
9722 9723 9724 9725
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    virDomainNetDefPtr net = NULL, persistentNet = NULL;
9726
    virNetDevBandwidthPtr bandwidth = NULL, newBandwidth = NULL;
9727
    virQEMUDriverConfigPtr cfg = NULL;
9728
    virCapsPtr caps = NULL;
9729 9730 9731

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
9732 9733 9734 9735 9736 9737 9738 9739 9740 9741 9742 9743 9744 9745
    if (virTypedParamsValidate(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)
9746
        return -1;
9747

9748 9749
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
9750

9751 9752
    cfg = virQEMUDriverGetConfig(driver);

9753 9754 9755
    if (virDomainSetInterfaceParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

9756 9757 9758
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

9759
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
9760 9761 9762 9763 9764 9765
                                        &persistentDef) < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        net = virDomainNetFind(vm->def, device);
        if (!net) {
9766 9767
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
9768 9769 9770 9771 9772 9773
            goto cleanup;
        }
    }
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        persistentNet = virDomainNetFind(persistentDef, device);
        if (!persistentNet) {
9774 9775
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
9776 9777 9778 9779
            goto cleanup;
        }
    }

9780 9781
    if ((VIR_ALLOC(bandwidth) < 0) ||
        (VIR_ALLOC(bandwidth->in) < 0) ||
9782
        (VIR_ALLOC(bandwidth->out) < 0))
9783 9784 9785 9786 9787 9788 9789 9790 9791 9792 9793 9794 9795 9796 9797 9798 9799 9800 9801 9802
        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;
        }
    }

9803
    /* average is mandatory, peak and burst are optional. So if no
9804
     * average is given, we free inbound/outbound here which causes
9805
     * inbound/outbound to not be set. */
9806 9807 9808 9809 9810 9811 9812 9813
    if (!bandwidth->in->average) {
        VIR_FREE(bandwidth->in);
    }
    if (!bandwidth->out->average) {
        VIR_FREE(bandwidth->out);
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
9814
        if (VIR_ALLOC(newBandwidth) < 0)
9815 9816 9817 9818
            goto cleanup;

        /* virNetDevBandwidthSet() will clear any previous value of
         * bandwidth parameters, so merge with old bandwidth parameters
9819
         * here to prevent them from being lost. */
9820 9821
        if (bandwidth->in ||
            (net->bandwidth && net->bandwidth->in)) {
9822
            if (VIR_ALLOC(newBandwidth->in) < 0)
9823
                goto cleanup;
9824 9825 9826 9827 9828 9829 9830

            memcpy(newBandwidth->in,
                   bandwidth->in ? bandwidth->in : net->bandwidth->in,
                   sizeof(*newBandwidth->in));
        }
        if (bandwidth->out ||
            (net->bandwidth && net->bandwidth->out)) {
9831
            if (VIR_ALLOC(newBandwidth->out) < 0)
9832
                goto cleanup;
9833 9834 9835 9836

            memcpy(newBandwidth->out,
                   bandwidth->out ? bandwidth->out : net->bandwidth->out,
                   sizeof(*newBandwidth->out));
9837 9838
        }

9839
        if (virNetDevBandwidthSet(net->ifname, newBandwidth, false) < 0) {
9840 9841 9842
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot set bandwidth limits on %s"),
                           device);
9843 9844 9845 9846 9847
            goto cleanup;
        }

        virNetDevBandwidthFree(net->bandwidth);
        net->bandwidth = newBandwidth;
E
Eric Blake 已提交
9848
        newBandwidth = NULL;
9849 9850 9851 9852 9853 9854 9855 9856 9857 9858 9859 9860 9861 9862 9863 9864 9865 9866
    }
    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;
            }
        }

9867
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
9868 9869 9870 9871 9872 9873
            goto cleanup;
    }

    ret = 0;
cleanup:
    virNetDevBandwidthFree(bandwidth);
9874
    virNetDevBandwidthFree(newBandwidth);
9875
    if (vm)
9876
        virObjectUnlock(vm);
9877
    virObjectUnref(caps);
9878
    virObjectUnref(cfg);
9879 9880 9881 9882 9883 9884 9885 9886 9887 9888
    return ret;
}

static int
qemuDomainGetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int *nparams,
                                 unsigned int flags)
{
9889
    virQEMUDriverPtr driver = dom->conn->privateData;
9890
    size_t i;
9891 9892 9893 9894 9895
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainDefPtr persistentDef = NULL;
    virDomainNetDefPtr net = NULL;
    int ret = -1;
9896
    virCapsPtr caps = NULL;
9897 9898 9899 9900 9901 9902 9903

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

9904 9905
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
9906

9907 9908 9909
    if (virDomainGetInterfaceParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

9910 9911 9912
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

9913
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
9914 9915 9916 9917 9918 9919 9920 9921 9922 9923 9924 9925 9926 9927 9928
                                        &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) {
9929 9930
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Can't find device %s"), device);
9931 9932 9933 9934
        goto cleanup;
    }

    for (i = 0; i < *nparams && i < QEMU_NB_BANDWIDTH_PARAM; i++) {
9935
        switch (i) {
9936
        case 0: /* inbound.average */
9937 9938 9939
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9940 9941 9942 9943 9944
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->average;
            break;
        case 1: /* inbound.peak */
9945 9946 9947
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9948 9949 9950 9951 9952
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->peak;
            break;
        case 2: /* inbound.burst */
9953 9954 9955
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9956 9957 9958 9959 9960
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->burst;
            break;
        case 3: /* outbound.average */
9961 9962 9963
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9964 9965 9966 9967 9968
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->average;
            break;
        case 4: /* outbound.peak */
9969 9970 9971
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9972 9973 9974 9975 9976
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->peak;
            break;
        case 5: /* outbound.burst */
9977 9978 9979
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9980 9981 9982 9983 9984 9985 9986 9987 9988 9989 9990 9991 9992 9993 9994 9995
                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 (vm)
9996
        virObjectUnlock(vm);
9997
    virObjectUnref(caps);
9998 9999 10000
    return ret;
}

10001
static int
10002 10003 10004 10005
qemuDomainMemoryStats(virDomainPtr dom,
                      struct _virDomainMemoryStat *stats,
                      unsigned int nr_stats,
                      unsigned int flags)
10006
{
10007
    virQEMUDriverPtr driver = dom->conn->privateData;
10008
    virDomainObjPtr vm;
M
Martin Kletzander 已提交
10009
    int ret = -1;
10010

10011 10012
    virCheckFlags(0, -1);

10013
    if (!(vm = qemuDomObjFromDomain(dom)))
10014 10015
        goto cleanup;

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

10019
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
10020 10021
        goto cleanup;

M
Martin Kletzander 已提交
10022
    if (!virDomainObjIsActive(vm)) {
10023 10024
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
M
Martin Kletzander 已提交
10025
    } else {
10026
        qemuDomainObjPrivatePtr priv = vm->privateData;
10027
        qemuDomainObjEnterMonitor(driver, vm);
10028
        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
10029
        qemuDomainObjExitMonitor(driver, vm);
M
Martin Kletzander 已提交
10030 10031 10032

        if (ret >= 0 && ret < nr_stats) {
            long rss;
10033
            if (qemuGetProcessInfo(NULL, NULL, &rss, vm->pid, 0) < 0) {
10034 10035
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("cannot get RSS for domain"));
M
Martin Kletzander 已提交
10036 10037 10038 10039 10040 10041 10042
            } else {
                stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_RSS;
                stats[ret].val = rss;
                ret++;
            }

        }
10043 10044
    }

E
Eric Blake 已提交
10045
    if (!qemuDomainObjEndJob(driver, vm))
10046 10047
        vm = NULL;

10048 10049
cleanup:
    if (vm)
10050
        virObjectUnlock(vm);
10051 10052 10053
    return ret;
}

10054
static int
10055 10056 10057 10058 10059
qemuDomainBlockPeek(virDomainPtr dom,
                    const char *path,
                    unsigned long long offset, size_t size,
                    void *buffer,
                    unsigned int flags)
10060
{
10061
    virQEMUDriverPtr driver = dom->conn->privateData;
10062
    virDomainObjPtr vm;
10063 10064
    int fd = -1, ret = -1;
    const char *actual;
10065

E
Eric Blake 已提交
10066 10067
    virCheckFlags(0, -1);

10068
    if (!(vm = qemuDomObjFromDomain(dom)))
10069
        goto cleanup;
10070

10071 10072 10073
    if (virDomainBlockPeekEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

10074
    if (!path || path[0] == '\0') {
10075 10076
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("NULL or empty path"));
10077
        goto cleanup;
10078 10079
    }

10080 10081
    /* Check the path belongs to this domain.  */
    if (!(actual = virDomainDiskPathByName(vm->def, path))) {
10082 10083
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path '%s'"), path);
10084
        goto cleanup;
10085
    }
10086
    path = actual;
10087

10088 10089
    fd = qemuOpenFile(driver, vm, path, O_RDONLY, NULL, NULL);
    if (fd == -1)
10090
        goto cleanup;
10091

10092 10093 10094 10095 10096 10097 10098 10099 10100
    /* 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;
10101 10102
    }

10103 10104
    ret = 0;

10105
cleanup:
10106
    VIR_FORCE_CLOSE(fd);
10107
    if (vm)
10108
        virObjectUnlock(vm);
10109 10110 10111
    return ret;
}

R
Richard W.M. Jones 已提交
10112
static int
10113 10114 10115 10116
qemuDomainMemoryPeek(virDomainPtr dom,
                     unsigned long long offset, size_t size,
                     void *buffer,
                     unsigned int flags)
R
Richard W.M. Jones 已提交
10117
{
10118
    virQEMUDriverPtr driver = dom->conn->privateData;
10119
    virDomainObjPtr vm;
10120
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
10121
    int fd = -1, ret = -1;
10122
    qemuDomainObjPrivatePtr priv;
10123
    virQEMUDriverConfigPtr cfg = NULL;
R
Richard W.M. Jones 已提交
10124

10125 10126
    virCheckFlags(VIR_MEMORY_VIRTUAL | VIR_MEMORY_PHYSICAL, -1);

10127
    if (!(vm = qemuDomObjFromDomain(dom)))
10128 10129
        goto cleanup;

10130 10131
    cfg = virQEMUDriverGetConfig(driver);

10132 10133 10134
    if (virDomainMemoryPeekEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

10135
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
10136 10137
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
10138
        goto cleanup;
R
Richard W.M. Jones 已提交
10139 10140
    }

10141
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
10142 10143
        goto cleanup;

D
Daniel P. Berrange 已提交
10144
    if (!virDomainObjIsActive(vm)) {
10145 10146
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10147
        goto endjob;
R
Richard W.M. Jones 已提交
10148 10149
    }

10150
    if (virAsprintf(&tmp, "%s/qemu.mem.XXXXXX", cfg->cacheDir) < 0)
10151
        goto endjob;
10152

R
Richard W.M. Jones 已提交
10153
    /* Create a temporary filename. */
10154
    if ((fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
10155
        virReportSystemError(errno,
10156
                             _("mkostemp(\"%s\") failed"), tmp);
10157
        goto endjob;
R
Richard W.M. Jones 已提交
10158 10159
    }

10160
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
10161

10162
    priv = vm->privateData;
10163
    qemuDomainObjEnterMonitor(driver, vm);
10164
    if (flags == VIR_MEMORY_VIRTUAL) {
10165
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
10166
            qemuDomainObjExitMonitor(driver, vm);
10167
            goto endjob;
10168
        }
10169
    } else {
10170
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
10171
            qemuDomainObjExitMonitor(driver, vm);
10172
            goto endjob;
10173
        }
R
Richard W.M. Jones 已提交
10174
    }
10175
    qemuDomainObjExitMonitor(driver, vm);
R
Richard W.M. Jones 已提交
10176 10177

    /* Read the memory file into buffer. */
10178
    if (saferead(fd, buffer, size) == (ssize_t) -1) {
10179 10180 10181
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
10182
        goto endjob;
R
Richard W.M. Jones 已提交
10183 10184 10185
    }

    ret = 0;
10186

10187
endjob:
E
Eric Blake 已提交
10188
    if (!qemuDomainObjEndJob(driver, vm))
10189
        vm = NULL;
10190

10191
cleanup:
10192
    VIR_FORCE_CLOSE(fd);
10193 10194
    if (tmp)
        unlink(tmp);
W
Wen Congyang 已提交
10195
    VIR_FREE(tmp);
10196
    if (vm)
10197
        virObjectUnlock(vm);
10198
    virObjectUnref(cfg);
R
Richard W.M. Jones 已提交
10199 10200 10201
    return ret;
}

10202

10203 10204 10205 10206 10207 10208
static int
qemuDomainGetBlockInfo(virDomainPtr dom,
                       const char *path,
                       virDomainBlockInfoPtr info,
                       unsigned int flags)
{
10209
    virQEMUDriverPtr driver = dom->conn->privateData;
10210 10211 10212 10213
    virDomainObjPtr vm;
    int ret = -1;
    int fd = -1;
    off_t end;
10214
    virStorageFileMetadata *meta = NULL;
10215
    virDomainDiskDefPtr disk = NULL;
10216
    struct stat sb;
10217
    int idx;
10218
    int format;
10219
    int activeFail = false;
10220
    virQEMUDriverConfigPtr cfg = NULL;
10221
    char *alias = NULL;
10222 10223 10224

    virCheckFlags(0, -1);

10225
    if (!(vm = qemuDomObjFromDomain(dom)))
10226 10227
        goto cleanup;

10228 10229
    cfg = virQEMUDriverGetConfig(driver);

10230 10231 10232
    if (virDomainGetBlockInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

10233
    if (!path || path[0] == '\0') {
10234 10235
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("NULL or empty path"));
10236 10237 10238 10239
        goto cleanup;
    }

    /* Check the path belongs to this domain. */
10240
    if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
10241 10242
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path %s not assigned to domain"), path);
10243 10244
        goto cleanup;
    }
10245
    disk = vm->def->disks[idx];
10246
    if (!disk->src) {
10247 10248 10249
        virReportError(VIR_ERR_INVALID_ARG,
                       _("disk %s does not currently have a source assigned"),
                       path);
10250 10251 10252
        goto cleanup;
    }
    path = disk->src;
10253 10254

    /* The path is correct, now try to open it and get its size. */
10255 10256
    fd = qemuOpenFile(driver, vm, path, O_RDONLY, NULL, NULL);
    if (fd == -1)
10257 10258 10259
        goto cleanup;

    /* Probe for magic formats */
10260 10261
    if (disk->format) {
        format = disk->format;
10262
    } else {
10263 10264 10265 10266
        if (cfg->allowDiskFormatProbing) {
            if ((format = virStorageFileProbeFormat(disk->src,
                                                    cfg->user,
                                                    cfg->group)) < 0)
10267 10268
                goto cleanup;
        } else {
10269 10270 10271
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no disk format for %s and probing is disabled"),
                           disk->src);
10272
            goto cleanup;
10273
        }
10274 10275
    }

10276
    if (!(meta = virStorageFileGetMetadataFromFD(path, fd, format)))
10277 10278 10279 10280 10281 10282 10283 10284 10285 10286
        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)) {
10287
#ifndef WIN32
10288 10289 10290 10291 10292 10293 10294 10295 10296 10297 10298 10299 10300
        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.
         */
10301
        end = lseek(fd, 0, SEEK_END);
10302 10303 10304 10305 10306 10307 10308 10309 10310 10311 10312
        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 */
10313 10314
    if (meta->capacity)
        info->capacity = meta->capacity;
10315

10316
    /* Set default value .. */
10317 10318
    info->allocation = info->physical;

10319 10320 10321
    /* ..but if guest is not using raw disk format and on a block device,
     * then query highest allocated extent from QEMU
     */
10322
    if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
10323
        format != VIR_STORAGE_FILE_RAW &&
10324
        S_ISBLK(sb.st_mode)) {
10325
        qemuDomainObjPrivatePtr priv = vm->privateData;
10326

10327 10328 10329 10330 10331 10332 10333 10334 10335
        /* If the guest is not running, then success/failure return
         * depends on whether domain is persistent
         */
        if (!virDomainObjIsActive(vm)) {
            activeFail = true;
            ret = 0;
            goto cleanup;
        }

10336 10337 10338
        if (VIR_STRDUP(alias, disk->info.alias) < 0)
            goto cleanup;

10339 10340
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
            goto cleanup;
10341

10342
        if (virDomainObjIsActive(vm)) {
10343
            qemuDomainObjEnterMonitor(driver, vm);
10344
            ret = qemuMonitorGetBlockExtent(priv->mon,
10345
                                            alias,
10346 10347
                                            &info->allocation);
            qemuDomainObjExitMonitor(driver, vm);
10348
        } else {
10349
            activeFail = true;
10350
            ret = 0;
10351
        }
10352

E
Eric Blake 已提交
10353
        if (!qemuDomainObjEndJob(driver, vm))
10354
            vm = NULL;
10355 10356 10357
    } else {
        ret = 0;
    }
10358 10359

cleanup:
10360
    VIR_FREE(alias);
10361
    virStorageFileFreeMetadata(meta);
10362
    VIR_FORCE_CLOSE(fd);
10363 10364 10365 10366 10367 10368 10369 10370 10371

    /* If we failed to get data from a domain because it's inactive and
     * it's not a persistent domain, then force failure.
     */
    if (activeFail && vm && !vm->persistent) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
        ret = -1;
    }
10372
    if (vm)
10373
        virObjectUnlock(vm);
10374
    virObjectUnref(cfg);
10375 10376 10377 10378
    return ret;
}


10379
static int
10380 10381 10382 10383
qemuConnectDomainEventRegister(virConnectPtr conn,
                               virConnectDomainEventCallback callback,
                               void *opaque,
                               virFreeCallback freecb)
10384
{
10385
    virQEMUDriverPtr driver = conn->privateData;
10386
    int ret = -1;
10387

10388 10389 10390 10391 10392 10393 10394
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        goto cleanup;

    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        goto cleanup;
10395

10396 10397 10398
    ret = 0;

cleanup:
10399
    return ret;
10400 10401
}

10402

10403
static int
10404 10405
qemuConnectDomainEventDeregister(virConnectPtr conn,
                                 virConnectDomainEventCallback callback)
10406
{
10407
    virQEMUDriverPtr driver = conn->privateData;
10408
    int ret = -1;
10409

10410 10411 10412 10413 10414 10415 10416 10417 10418
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        goto cleanup;

    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        goto cleanup;

    ret = 0;
10419

10420
cleanup:
10421
    return ret;
10422 10423
}

10424 10425

static int
10426 10427 10428 10429 10430 10431
qemuConnectDomainEventRegisterAny(virConnectPtr conn,
                                  virDomainPtr dom,
                                  int eventID,
                                  virConnectDomainEventGenericCallback callback,
                                  void *opaque,
                                  virFreeCallback freecb)
10432
{
10433
    virQEMUDriverPtr driver = conn->privateData;
10434 10435 10436 10437
    int ret = -1;

    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        goto cleanup;
10438

10439 10440 10441 10442
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
10443
        ret = -1;
10444 10445

cleanup:
10446 10447 10448 10449 10450
    return ret;
}


static int
10451 10452
qemuConnectDomainEventDeregisterAny(virConnectPtr conn,
                                    int callbackID)
10453
{
10454
    virQEMUDriverPtr driver = conn->privateData;
10455
    int ret = -1;
10456

10457 10458
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        goto cleanup;
10459

10460
    if (virObjectEventStateDeregisterID(conn,
10461 10462 10463 10464 10465 10466 10467
                                        driver->domainEventState,
                                        callbackID) < 0)
        goto cleanup;

    ret = 0;

cleanup:
10468 10469 10470 10471
    return ret;
}


10472 10473 10474
/*******************************************************************
 * Migration Protocol Version 2
 *******************************************************************/
D
Daniel Veillard 已提交
10475

C
Chris Lalancette 已提交
10476 10477 10478 10479 10480 10481
/* 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
10482 10483 10484 10485 10486 10487
qemuDomainMigratePrepareTunnel(virConnectPtr dconn,
                               virStreamPtr st,
                               unsigned long flags,
                               const char *dname,
                               unsigned long resource ATTRIBUTE_UNUSED,
                               const char *dom_xml)
C
Chris Lalancette 已提交
10488
{
10489
    virQEMUDriverPtr driver = dconn->privateData;
10490
    virDomainDefPtr def = NULL;
10491
    char *origname = NULL;
C
Chris Lalancette 已提交
10492
    int ret = -1;
10493

10494
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
10495

C
Chris Lalancette 已提交
10496
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
10497 10498
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("PrepareTunnel called but no TUNNELLED flag set"));
C
Chris Lalancette 已提交
10499 10500 10501
        goto cleanup;
    }

10502
    if (virLockManagerPluginUsesState(driver->lockManager)) {
10503 10504 10505
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
10506 10507 10508
        goto cleanup;
    }

10509
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
10510 10511
        goto cleanup;

10512 10513 10514
    if (virDomainMigratePrepareTunnelEnsureACL(dconn, def) < 0)
        goto cleanup;

10515 10516
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     NULL, 0, NULL, NULL, /* No cookies in v2 */
10517
                                     st, &def, origname, flags);
10518

C
Chris Lalancette 已提交
10519
cleanup:
10520
    VIR_FREE(origname);
10521
    virDomainDefFree(def);
C
Chris Lalancette 已提交
10522 10523 10524
    return ret;
}

D
Daniel Veillard 已提交
10525 10526 10527 10528
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
10529
static int ATTRIBUTE_NONNULL(5)
10530 10531 10532 10533 10534 10535 10536 10537 10538
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 已提交
10539
{
10540
    virQEMUDriverPtr driver = dconn->privateData;
10541
    virDomainDefPtr def = NULL;
10542
    char *origname = NULL;
10543
    int ret = -1;
10544

10545
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
10546

C
Chris Lalancette 已提交
10547 10548 10549 10550
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
10551 10552 10553
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Tunnelled migration requested but invalid "
                         "RPC method called"));
C
Chris Lalancette 已提交
10554 10555 10556
        goto cleanup;
    }

10557
    if (virLockManagerPluginUsesState(driver->lockManager)) {
10558
        virReportError(VIR_ERR_INTERNAL_ERROR,
10559 10560
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
10561
        goto cleanup;
D
Daniel Veillard 已提交
10562 10563
    }

10564
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
10565 10566
        goto cleanup;

10567 10568 10569
    if (virDomainMigratePrepare2EnsureACL(dconn, def) < 0)
        goto cleanup;

10570 10571 10572 10573
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
10574
    ret = qemuMigrationPrepareDirect(driver, dconn,
10575
                                     NULL, 0, NULL, NULL, /* No cookies */
10576
                                     uri_in, uri_out,
10577
                                     &def, origname, NULL, flags);
D
Daniel Veillard 已提交
10578

10579
cleanup:
10580
    VIR_FREE(origname);
10581
    virDomainDefFree(def);
10582 10583
    return ret;
}
C
Chris Lalancette 已提交
10584

D
Daniel Veillard 已提交
10585

10586 10587
/* Perform is the second step, and it runs on the source host. */
static int
10588 10589 10590 10591 10592 10593 10594
qemuDomainMigratePerform(virDomainPtr dom,
                         const char *cookie,
                         int cookielen,
                         const char *uri,
                         unsigned long flags,
                         const char *dname,
                         unsigned long resource)
10595
{
10596
    virQEMUDriverPtr driver = dom->conn->privateData;
10597 10598
    virDomainObjPtr vm;
    int ret = -1;
10599
    const char *dconnuri = NULL;
10600

10601
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
10602

10603
    if (virLockManagerPluginUsesState(driver->lockManager)) {
10604 10605 10606
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
10607 10608 10609
        goto cleanup;
    }

10610
    if (!(vm = qemuDomObjFromDomain(dom)))
10611
        goto cleanup;
D
Daniel Veillard 已提交
10612

10613 10614 10615
    if (virDomainMigratePerformEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

10616 10617 10618 10619 10620
    if (flags & VIR_MIGRATE_PEER2PEER) {
        dconnuri = uri;
        uri = NULL;
    }

10621 10622 10623 10624 10625 10626
    /* 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
     */
10627
    ret = qemuMigrationPerform(driver, dom->conn, vm,
10628 10629
                               NULL, dconnuri, uri, NULL, NULL,
                               cookie, cookielen,
10630
                               NULL, NULL, /* No output cookies in v2 */
10631
                               flags, dname, resource, false);
10632

10633
cleanup:
10634
    return ret;
D
Daniel Veillard 已提交
10635 10636
}

10637

D
Daniel Veillard 已提交
10638 10639
/* Finish is the third and final step, and it runs on the destination host. */
static virDomainPtr
10640 10641 10642 10643 10644 10645 10646
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 已提交
10647
{
10648
    virQEMUDriverPtr driver = dconn->privateData;
10649 10650
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
10651

10652
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
C
Chris Lalancette 已提交
10653

10654
    vm = virDomainObjListFindByName(driver->domains, dname);
D
Daniel Veillard 已提交
10655
    if (!vm) {
10656 10657
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), dname);
10658
        goto cleanup;
D
Daniel Veillard 已提交
10659 10660
    }

10661 10662 10663
    if (virDomainMigrateFinish2EnsureACL(dconn, vm->def) < 0)
        goto cleanup;

10664 10665 10666 10667
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
10668
    dom = qemuMigrationFinish(driver, dconn, vm,
10669
                              NULL, 0, NULL, NULL, /* No cookies */
10670
                              flags, retcode, false);
10671

10672 10673
cleanup:
    return dom;
D
Daniel Veillard 已提交
10674 10675
}

10676

10677 10678 10679 10680 10681 10682
/*******************************************************************
 * Migration Protocol Version 3
 *******************************************************************/

static char *
qemuDomainMigrateBegin3(virDomainPtr domain,
10683
                        const char *xmlin,
10684 10685 10686
                        char **cookieout,
                        int *cookieoutlen,
                        unsigned long flags,
10687
                        const char *dname,
10688 10689 10690 10691
                        unsigned long resource ATTRIBUTE_UNUSED)
{
    virDomainObjPtr vm;

10692
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
10693

10694 10695
    if (!(vm = qemuDomObjFromDomain(domain)))
        return NULL;
10696

10697
    if (virDomainMigrateBegin3EnsureACL(domain->conn, vm->def) < 0) {
10698
        virObjectUnlock(vm);
10699
        return NULL;
10700
    }
10701 10702 10703

    return qemuMigrationBegin(domain->conn, vm, xmlin, dname,
                              cookieout, cookieoutlen, flags);
10704 10705
}

10706 10707 10708 10709 10710 10711 10712 10713 10714 10715 10716 10717 10718 10719 10720 10721 10722 10723 10724 10725 10726 10727 10728 10729 10730 10731 10732 10733 10734 10735 10736 10737 10738 10739 10740 10741 10742
static char *
qemuDomainMigrateBegin3Params(virDomainPtr domain,
                              virTypedParameterPtr params,
                              int nparams,
                              char **cookieout,
                              int *cookieoutlen,
                              unsigned int flags)
{
    const char *xmlin = NULL;
    const char *dname = NULL;
    virDomainObjPtr vm;

    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
        return NULL;

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

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

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

    return qemuMigrationBegin(domain->conn, vm, xmlin, dname,
                              cookieout, cookieoutlen, flags);
}


10743 10744 10745 10746 10747 10748 10749 10750 10751 10752 10753 10754 10755
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)
{
10756
    virQEMUDriverPtr driver = dconn->privateData;
10757
    virDomainDefPtr def = NULL;
10758
    char *origname = NULL;
10759 10760
    int ret = -1;

10761
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
10762 10763 10764 10765 10766

    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
10767 10768 10769
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Tunnelled migration requested but invalid "
                         "RPC method called"));
10770 10771 10772
        goto cleanup;
    }

10773
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
10774 10775
        goto cleanup;

10776 10777 10778
    if (virDomainMigratePrepare3EnsureACL(dconn, def) < 0)
        goto cleanup;

10779 10780 10781 10782
    ret = qemuMigrationPrepareDirect(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
                                     uri_in, uri_out,
10783
                                     &def, origname, NULL, flags);
10784 10785

cleanup:
10786
    VIR_FREE(origname);
10787
    virDomainDefFree(def);
10788 10789 10790
    return ret;
}

10791 10792 10793 10794 10795 10796 10797 10798 10799 10800 10801 10802
static int
qemuDomainMigratePrepare3Params(virConnectPtr dconn,
                                virTypedParameterPtr params,
                                int nparams,
                                const char *cookiein,
                                int cookieinlen,
                                char **cookieout,
                                int *cookieoutlen,
                                char **uri_out,
                                unsigned int flags)
{
    virQEMUDriverPtr driver = dconn->privateData;
10803
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
10804 10805 10806 10807
    virDomainDefPtr def = NULL;
    const char *dom_xml = NULL;
    const char *dname = NULL;
    const char *uri_in = NULL;
10808
    const char *listenAddress = cfg->migrationAddress;
10809
    char *origname = NULL;
10810 10811
    int ret = -1;

10812
    virCheckFlagsGoto(QEMU_MIGRATION_FLAGS, cleanup);
10813
    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
10814
        goto cleanup;
10815 10816 10817 10818 10819 10820 10821 10822 10823

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_XML,
                                &dom_xml) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_NAME,
                                &dname) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_URI,
10824 10825 10826 10827
                                &uri_in) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_LISTEN_ADDRESS,
                                &listenAddress) < 0)
10828
        goto cleanup;
10829 10830 10831 10832 10833 10834 10835 10836 10837 10838 10839

    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Tunnelled migration requested but invalid "
                         "RPC method called"));
        goto cleanup;
    }

10840
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
10841 10842 10843 10844 10845 10846 10847 10848 10849
        goto cleanup;

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

    ret = qemuMigrationPrepareDirect(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
                                     uri_in, uri_out,
10850
                                     &def, origname, listenAddress, flags);
10851 10852

cleanup:
10853
    VIR_FREE(origname);
10854
    virDomainDefFree(def);
10855
    virObjectUnref(cfg);
10856 10857 10858
    return ret;
}

10859 10860 10861 10862 10863 10864 10865 10866 10867 10868 10869 10870 10871

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)
{
10872
    virQEMUDriverPtr driver = dconn->privateData;
10873
    virDomainDefPtr def = NULL;
10874
    char *origname = NULL;
10875 10876
    int ret = -1;

10877
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
10878 10879

    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
10880 10881
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("PrepareTunnel called but no TUNNELLED flag set"));
10882 10883 10884
        goto cleanup;
    }

10885
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
10886 10887
        goto cleanup;

10888 10889 10890
    if (virDomainMigratePrepareTunnel3EnsureACL(dconn, def) < 0)
        goto cleanup;

10891 10892 10893
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
10894
                                     st, &def, origname, flags);
10895 10896

cleanup:
10897
    VIR_FREE(origname);
10898
    virDomainDefFree(def);
10899 10900 10901
    return ret;
}

10902 10903 10904 10905 10906 10907 10908 10909 10910 10911 10912 10913 10914 10915 10916
static int
qemuDomainMigratePrepareTunnel3Params(virConnectPtr dconn,
                                      virStreamPtr st,
                                      virTypedParameterPtr params,
                                      int nparams,
                                      const char *cookiein,
                                      int cookieinlen,
                                      char **cookieout,
                                      int *cookieoutlen,
                                      unsigned int flags)
{
    virQEMUDriverPtr driver = dconn->privateData;
    virDomainDefPtr def = NULL;
    const char *dom_xml = NULL;
    const char *dname = NULL;
10917
    char *origname = NULL;
10918 10919 10920 10921 10922 10923 10924 10925 10926 10927 10928 10929 10930 10931 10932 10933 10934 10935 10936 10937
    int ret = -1;

    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
        return -1;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_XML,
                                &dom_xml) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_NAME,
                                &dname) < 0)
        return -1;

    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("PrepareTunnel called but no TUNNELLED flag set"));
        goto cleanup;
    }

10938
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
10939 10940 10941 10942 10943 10944 10945 10946
        goto cleanup;

    if (virDomainMigratePrepareTunnel3ParamsEnsureACL(dconn, def) < 0)
        goto cleanup;

    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
10947
                                     st, &def, origname, flags);
10948 10949

cleanup:
10950
    VIR_FREE(origname);
10951 10952 10953 10954
    virDomainDefFree(def);
    return ret;
}

10955 10956 10957

static int
qemuDomainMigratePerform3(virDomainPtr dom,
10958
                          const char *xmlin,
10959 10960 10961 10962
                          const char *cookiein,
                          int cookieinlen,
                          char **cookieout,
                          int *cookieoutlen,
10963
                          const char *dconnuri,
10964 10965 10966 10967 10968
                          const char *uri,
                          unsigned long flags,
                          const char *dname,
                          unsigned long resource)
{
10969
    virQEMUDriverPtr driver = dom->conn->privateData;
10970 10971
    virDomainObjPtr vm;

10972
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
10973

10974 10975
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
10976

10977 10978 10979 10980 10981
    if (virDomainMigratePerform3EnsureACL(dom->conn, vm->def) < 0) {
        virObjectUnlock(vm);
        return -1;
    }

10982
    return qemuMigrationPerform(driver, dom->conn, vm, xmlin,
10983 10984
                                dconnuri, uri, NULL, NULL,
                                cookiein, cookieinlen,
10985 10986
                                cookieout, cookieoutlen,
                                flags, dname, resource, true);
10987 10988
}

10989 10990 10991 10992 10993 10994 10995 10996 10997 10998 10999 11000 11001 11002 11003 11004
static int
qemuDomainMigratePerform3Params(virDomainPtr dom,
                                const char *dconnuri,
                                virTypedParameterPtr params,
                                int nparams,
                                const char *cookiein,
                                int cookieinlen,
                                char **cookieout,
                                int *cookieoutlen,
                                unsigned int flags)
{
    virQEMUDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    const char *dom_xml = NULL;
    const char *dname = NULL;
    const char *uri = NULL;
11005
    const char *graphicsuri = NULL;
11006
    const char *listenAddress = NULL;
11007 11008 11009 11010 11011 11012 11013 11014 11015 11016 11017 11018 11019 11020 11021 11022 11023
    unsigned long long bandwidth = 0;

    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
        return -1;

    if (virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_XML,
                                &dom_xml) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_DEST_NAME,
                                &dname) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_URI,
                                &uri) < 0 ||
        virTypedParamsGetULLong(params, nparams,
                                VIR_MIGRATE_PARAM_BANDWIDTH,
11024 11025 11026
                                &bandwidth) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_GRAPHICS_URI,
11027 11028 11029 11030
                                &graphicsuri) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_LISTEN_ADDRESS,
                                &listenAddress) < 0)
11031 11032 11033 11034 11035 11036 11037 11038 11039 11040 11041
        return -1;

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

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

    return qemuMigrationPerform(driver, dom->conn, vm, dom_xml,
11042
                                dconnuri, uri, graphicsuri, listenAddress,
11043
                                cookiein, cookieinlen, cookieout, cookieoutlen,
11044 11045 11046
                                flags, dname, bandwidth, true);
}

11047

11048
static virDomainPtr
11049 11050 11051 11052 11053 11054
qemuDomainMigrateFinish3(virConnectPtr dconn,
                         const char *dname,
                         const char *cookiein,
                         int cookieinlen,
                         char **cookieout,
                         int *cookieoutlen,
11055
                         const char *dconnuri ATTRIBUTE_UNUSED,
11056 11057
                         const char *uri ATTRIBUTE_UNUSED,
                         unsigned long flags,
11058
                         int cancelled)
11059
{
11060
    virQEMUDriverPtr driver = dconn->privateData;
11061 11062
    virDomainObjPtr vm;

11063
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
11064

11065 11066
    if (!dname ||
        !(vm = virDomainObjListFindByName(driver->domains, dname))) {
11067
        virReportError(VIR_ERR_NO_DOMAIN,
11068 11069 11070
                       _("no domain with matching name '%s'"),
                       NULLSTR(dname));
        return NULL;
11071 11072
    }

11073 11074 11075 11076
    if (virDomainMigrateFinish3EnsureACL(dconn, vm->def) < 0) {
        virObjectUnlock(vm);
        return NULL;
    }
11077

11078 11079 11080 11081 11082
    return qemuMigrationFinish(driver, dconn, vm,
                               cookiein, cookieinlen,
                               cookieout, cookieoutlen,
                               flags, cancelled, true);
}
11083

11084 11085 11086 11087 11088 11089 11090 11091 11092 11093 11094 11095 11096 11097 11098 11099 11100 11101 11102 11103 11104 11105 11106 11107 11108 11109 11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124
static virDomainPtr
qemuDomainMigrateFinish3Params(virConnectPtr dconn,
                               virTypedParameterPtr params,
                               int nparams,
                               const char *cookiein,
                               int cookieinlen,
                               char **cookieout,
                               int *cookieoutlen,
                               unsigned int flags,
                               int cancelled)
{
    virQEMUDriverPtr driver = dconn->privateData;
    virDomainObjPtr vm;
    const char *dname = NULL;

    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
        return NULL;

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

    if (!dname ||
        !(vm = virDomainObjListFindByName(driver->domains, dname))) {
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"),
                       NULLSTR(dname));
        return NULL;
    }

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

    return qemuMigrationFinish(driver, dconn, vm,
                               cookiein, cookieinlen,
                               cookieout, cookieoutlen,
                               flags, cancelled, true);
11125 11126
}

11127

11128 11129 11130 11131 11132 11133 11134 11135 11136
static int
qemuDomainMigrateConfirm3(virDomainPtr domain,
                          const char *cookiein,
                          int cookieinlen,
                          unsigned long flags,
                          int cancelled)
{
    virDomainObjPtr vm;

11137
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
11138

11139 11140
    if (!(vm = qemuDomObjFromDomain(domain)))
        return -1;
11141

11142 11143 11144
    if (virDomainMigrateConfirm3EnsureACL(domain->conn, vm->def) < 0) {
        virObjectUnlock(vm);
        return -1;
11145 11146
    }

11147 11148
    return qemuMigrationConfirm(domain->conn, vm, cookiein, cookieinlen,
                                flags, cancelled);
11149 11150
}

11151 11152 11153 11154 11155 11156 11157 11158 11159 11160 11161 11162 11163 11164 11165 11166 11167 11168 11169 11170 11171 11172 11173 11174 11175 11176 11177 11178
static int
qemuDomainMigrateConfirm3Params(virDomainPtr domain,
                                virTypedParameterPtr params,
                                int nparams,
                                const char *cookiein,
                                int cookieinlen,
                                unsigned int flags,
                                int cancelled)
{
    virDomainObjPtr vm;

    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);

    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
        return -1;

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

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

    return qemuMigrationConfirm(domain->conn, vm, cookiein, cookieinlen,
                                flags, cancelled);
}

11179

11180
static int
11181
qemuNodeDeviceGetPciInfo(virNodeDeviceDefPtr def,
11182 11183 11184 11185
                         unsigned *domain,
                         unsigned *bus,
                         unsigned *slot,
                         unsigned *function)
11186 11187 11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198 11199 11200 11201 11202 11203
{
    virNodeDevCapsDefPtr cap;
    int ret = -1;

    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) {
11204
        virReportError(VIR_ERR_INVALID_ARG,
11205
                       _("device %s is not a PCI device"), def->name);
11206 11207 11208 11209 11210 11211 11212 11213 11214
        goto out;
    }

    ret = 0;
out:
    return ret;
}

static int
11215 11216 11217
qemuNodeDeviceDetachFlags(virNodeDevicePtr dev,
                          const char *driverName,
                          unsigned int flags)
11218
{
11219
    virQEMUDriverPtr driver = dev->conn->privateData;
11220
    virPCIDevicePtr pci = NULL;
11221
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
11222
    int ret = -1;
11223 11224
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
11225 11226
    bool legacy = qemuHostdevHostSupportsPassthroughLegacy();
    bool vfio = qemuHostdevHostSupportsPassthroughVFIO();
11227

11228 11229
    virCheckFlags(0, -1);

11230 11231 11232 11233 11234 11235 11236 11237 11238 11239 11240 11241 11242
    xml = virNodeDeviceGetXMLDesc(dev, 0);
    if (!xml)
        goto cleanup;

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

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

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

11244
    pci = virPCIDeviceNew(domain, bus, slot, function);
11245
    if (!pci)
11246
        goto cleanup;
11247

11248
    if (!driverName) {
11249
        if (vfio) {
11250
            driverName = "vfio";
11251
        } else if (legacy) {
11252
            driverName = "kvm";
11253 11254 11255 11256 11257 11258
        } else {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("neither VFIO nor KVM device assignment is "
                             "currently supported on this system"));
            goto cleanup;
        }
11259 11260
    }

11261 11262 11263 11264 11265 11266 11267
    if (STREQ(driverName, "vfio")) {
        if (!vfio) {
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("VFIO device assignment is currently not "
                             "supported on this system"));
            goto cleanup;
        }
11268 11269
        if (virPCIDeviceSetStubDriver(pci, "vfio-pci") < 0)
            goto cleanup;
11270
    } else if (STREQ(driverName, "kvm")) {
11271 11272 11273 11274 11275 11276
        if (!legacy) {
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("KVM device assignment is currently not "
                             "supported on this system"));
            goto cleanup;
        }
11277 11278
        if (virPCIDeviceSetStubDriver(pci, "pci-stub") < 0)
            goto cleanup;
11279 11280 11281
    } else {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown driver name '%s'"), driverName);
11282
        goto cleanup;
11283 11284
    }

11285 11286
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);
11287

11288
    if (virPCIDeviceDetach(pci, driver->activePciHostdevs,
11289
                           driver->inactivePciHostdevs) < 0) {
11290
        goto out;
11291
    }
11292 11293 11294

    ret = 0;
out:
11295 11296
    virObjectUnlock(driver->inactivePciHostdevs);
    virObjectUnlock(driver->activePciHostdevs);
11297
cleanup:
11298
    virPCIDeviceFree(pci);
11299 11300
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
11301 11302 11303
    return ret;
}

11304 11305 11306 11307 11308 11309
static int
qemuNodeDeviceDettach(virNodeDevicePtr dev)
{
    return qemuNodeDeviceDetachFlags(dev, NULL, 0);
}

11310
static int
11311
qemuNodeDeviceReAttach(virNodeDevicePtr dev)
11312
{
11313
    virQEMUDriverPtr driver = dev->conn->privateData;
11314
    virPCIDevicePtr pci = NULL;
11315
    virPCIDevicePtr other;
11316
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
11317
    int ret = -1;
11318 11319
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
11320

11321 11322 11323 11324 11325 11326 11327 11328 11329 11330 11331 11332 11333
    xml = virNodeDeviceGetXMLDesc(dev, 0);
    if (!xml)
        goto cleanup;

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

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

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

11335
    pci = virPCIDeviceNew(domain, bus, slot, function);
11336
    if (!pci)
11337
        goto cleanup;
11338

11339 11340
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);
11341
    other = virPCIDeviceListFind(driver->activePciHostdevs, pci);
11342
    if (other) {
11343
        const char *other_name = virPCIDeviceGetUsedBy(other);
11344 11345

        if (other_name)
11346 11347
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is still in use by domain %s"),
11348
                           virPCIDeviceGetName(pci), other_name);
11349
        else
11350 11351
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is still in use"),
11352
                           virPCIDeviceGetName(pci));
11353
        goto out;
11354 11355
    }

11356
    virPCIDeviceReattachInit(pci);
11357

11358
    if (virPCIDeviceReattach(pci, driver->activePciHostdevs,
11359
                             driver->inactivePciHostdevs) < 0)
11360 11361 11362 11363
        goto out;

    ret = 0;
out:
11364 11365
    virObjectUnlock(driver->inactivePciHostdevs);
    virObjectUnlock(driver->activePciHostdevs);
11366
    virPCIDeviceFree(pci);
11367 11368 11369
cleanup:
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
11370 11371 11372 11373
    return ret;
}

static int
11374
qemuNodeDeviceReset(virNodeDevicePtr dev)
11375
{
11376
    virQEMUDriverPtr driver = dev->conn->privateData;
11377
    virPCIDevicePtr pci;
11378
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
11379
    int ret = -1;
11380 11381
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
11382

11383 11384 11385 11386 11387 11388 11389 11390 11391 11392 11393 11394 11395
    xml = virNodeDeviceGetXMLDesc(dev, 0);
    if (!xml)
        goto cleanup;

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

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

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

11397
    pci = virPCIDeviceNew(domain, bus, slot, function);
11398
    if (!pci)
11399
        goto cleanup;
11400

11401 11402
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);
11403

11404 11405
    if (virPCIDeviceReset(pci, driver->activePciHostdevs,
                          driver->inactivePciHostdevs) < 0)
11406 11407 11408 11409
        goto out;

    ret = 0;
out:
11410 11411
    virObjectUnlock(driver->inactivePciHostdevs);
    virObjectUnlock(driver->activePciHostdevs);
11412
    virPCIDeviceFree(pci);
11413 11414 11415
cleanup:
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
11416 11417 11418
    return ret;
}

11419
static int
11420 11421 11422
qemuConnectCompareCPU(virConnectPtr conn,
                      const char *xmlDesc,
                      unsigned int flags)
11423
{
11424
    virQEMUDriverPtr driver = conn->privateData;
11425
    int ret = VIR_CPU_COMPARE_ERROR;
11426
    virCapsPtr caps = NULL;
11427

E
Eric Blake 已提交
11428 11429
    virCheckFlags(0, VIR_CPU_COMPARE_ERROR);

11430 11431 11432
    if (virConnectCompareCPUEnsureACL(conn) < 0)
        goto cleanup;

11433 11434 11435 11436 11437
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (!caps->host.cpu ||
        !caps->host.cpu->model) {
11438 11439
        VIR_WARN("cannot get host CPU capabilities");
        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
E
Eric Blake 已提交
11440
    } else {
11441
        ret = cpuCompareXML(caps->host.cpu, xmlDesc);
E
Eric Blake 已提交
11442
    }
11443

11444 11445
cleanup:
    virObjectUnref(caps);
11446 11447 11448
    return ret;
}

11449

11450
static char *
11451 11452 11453 11454
qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED,
                       const char **xmlCPUs,
                       unsigned int ncpus,
                       unsigned int flags)
11455
{
11456
    char *cpu = NULL;
11457

11458
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);
E
Eric Blake 已提交
11459

11460 11461 11462
    if (virConnectBaselineCPUEnsureACL(conn) < 0)
        goto cleanup;

11463
    cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags);
11464

11465
cleanup:
11466 11467 11468
    return cpu;
}

11469 11470 11471 11472 11473 11474 11475

static int qemuDomainGetJobInfo(virDomainPtr dom,
                                virDomainJobInfoPtr info) {
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

11476
    if (!(vm = qemuDomObjFromDomain(dom)))
11477 11478 11479 11480
        goto cleanup;

    priv = vm->privateData;

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

11484
    if (virDomainObjIsActive(vm)) {
11485
        if (priv->job.asyncJob && !priv->job.dump_memory_only) {
11486
            memcpy(info, &priv->job.info, sizeof(*info));
11487 11488 11489 11490 11491 11492

            /* 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
             */
11493
            if (virTimeMillisNow(&info->timeElapsed) < 0)
11494
                goto cleanup;
11495
            info->timeElapsed -= priv->job.start;
11496 11497 11498 11499 11500
        } else {
            memset(info, 0, sizeof(*info));
            info->type = VIR_DOMAIN_JOB_NONE;
        }
    } else {
11501 11502
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
11503 11504 11505 11506 11507 11508 11509
        goto cleanup;
    }

    ret = 0;

cleanup:
    if (vm)
11510
        virObjectUnlock(vm);
11511 11512 11513 11514
    return ret;
}


11515 11516 11517 11518 11519 11520 11521 11522 11523 11524 11525 11526 11527 11528 11529 11530 11531 11532 11533 11534 11535
static int
qemuDomainGetJobStats(virDomainPtr dom,
                      int *type,
                      virTypedParameterPtr *params,
                      int *nparams,
                      unsigned int flags)
{
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    virTypedParameterPtr par = NULL;
    int maxpar = 0;
    int npar = 0;
    int ret = -1;

    virCheckFlags(0, -1);

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

    priv = vm->privateData;

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

11539 11540 11541 11542 11543 11544 11545 11546 11547 11548 11549 11550 11551 11552 11553 11554 11555 11556 11557 11558 11559 11560 11561 11562 11563 11564 11565 11566 11567 11568 11569 11570 11571 11572 11573 11574 11575 11576 11577 11578 11579 11580 11581 11582 11583 11584 11585 11586 11587 11588 11589 11590 11591 11592 11593 11594 11595 11596 11597 11598 11599 11600 11601 11602 11603 11604 11605 11606 11607 11608 11609 11610 11611 11612 11613 11614 11615 11616 11617 11618 11619 11620 11621 11622 11623 11624 11625 11626 11627 11628 11629 11630 11631 11632 11633 11634 11635 11636 11637 11638 11639 11640 11641 11642 11643 11644 11645 11646 11647 11648 11649 11650 11651 11652 11653 11654 11655 11656 11657
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto cleanup;
    }

    if (!priv->job.asyncJob || priv->job.dump_memory_only) {
        *type = VIR_DOMAIN_JOB_NONE;
        *params = NULL;
        *nparams = 0;
        ret = 0;
        goto cleanup;
    }

    /* 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
     */
    if (virTimeMillisNow(&priv->job.info.timeElapsed) < 0)
        goto cleanup;
    priv->job.info.timeElapsed -= priv->job.start;

    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_TIME_ELAPSED,
                                priv->job.info.timeElapsed) < 0)
        goto cleanup;

    if (priv->job.info.type == VIR_DOMAIN_JOB_BOUNDED &&
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_TIME_REMAINING,
                                priv->job.info.timeRemaining) < 0)
        goto cleanup;

    if (priv->job.status.downtime_set &&
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DOWNTIME,
                                priv->job.status.downtime) < 0)
        goto cleanup;

    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DATA_TOTAL,
                                priv->job.info.dataTotal) < 0 ||
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DATA_PROCESSED,
                                priv->job.info.dataProcessed) < 0 ||
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DATA_REMAINING,
                                priv->job.info.dataRemaining) < 0)
        goto cleanup;

    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_MEMORY_TOTAL,
                                priv->job.info.memTotal) < 0 ||
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_MEMORY_PROCESSED,
                                priv->job.info.memProcessed) < 0 ||
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_MEMORY_REMAINING,
                                priv->job.info.memRemaining) < 0)
        goto cleanup;

    if (priv->job.status.ram_duplicate_set) {
        if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_MEMORY_CONSTANT,
                                    priv->job.status.ram_duplicate) < 0 ||
            virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_MEMORY_NORMAL,
                                    priv->job.status.ram_normal) < 0 ||
            virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_MEMORY_NORMAL_BYTES,
                                    priv->job.status.ram_normal_bytes) < 0)
            goto cleanup;
    }

    if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DISK_TOTAL,
                                priv->job.info.fileTotal) < 0 ||
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DISK_PROCESSED,
                                priv->job.info.fileProcessed) < 0 ||
        virTypedParamsAddULLong(&par, &npar, &maxpar,
                                VIR_DOMAIN_JOB_DISK_REMAINING,
                                priv->job.info.fileRemaining) < 0)
        goto cleanup;

    if (priv->job.status.xbzrle_set) {
        if (virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_COMPRESSION_CACHE,
                                    priv->job.status.xbzrle_cache_size) < 0 ||
            virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_COMPRESSION_BYTES,
                                    priv->job.status.xbzrle_bytes) < 0 ||
            virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_COMPRESSION_PAGES,
                                    priv->job.status.xbzrle_pages) < 0 ||
            virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_COMPRESSION_CACHE_MISSES,
                                    priv->job.status.xbzrle_cache_miss) < 0 ||
            virTypedParamsAddULLong(&par, &npar, &maxpar,
                                    VIR_DOMAIN_JOB_COMPRESSION_OVERFLOW,
                                    priv->job.status.xbzrle_overflow) < 0)
            goto cleanup;
    }

    *type = priv->job.info.type;
    *params = par;
    *nparams = npar;
    ret = 0;

cleanup:
    if (vm)
        virObjectUnlock(vm);
    if (ret < 0)
        virTypedParamsFree(par, npar);
    return ret;
}


11658
static int qemuDomainAbortJob(virDomainPtr dom) {
11659
    virQEMUDriverPtr driver = dom->conn->privateData;
11660 11661 11662 11663
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

11664
    if (!(vm = qemuDomObjFromDomain(dom)))
11665 11666
        goto cleanup;

11667 11668 11669
    if (virDomainAbortJobEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

11670 11671
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_ABORT) < 0)
        goto cleanup;
11672

11673
    if (!virDomainObjIsActive(vm)) {
11674 11675
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
11676
        goto endjob;
11677 11678
    }

11679 11680
    priv = vm->privateData;

11681
    if (!priv->job.asyncJob || priv->job.dump_memory_only) {
11682 11683
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("no job is active on the domain"));
11684 11685
        goto endjob;
    } else if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) {
11686 11687 11688
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot abort incoming migration;"
                         " use virDomainDestroy instead"));
11689 11690 11691 11692
        goto endjob;
    }

    VIR_DEBUG("Cancelling job at client request");
11693
    qemuDomainObjAbortAsyncJob(vm);
11694
    qemuDomainObjEnterMonitor(driver, vm);
11695 11696 11697 11698
    ret = qemuMonitorMigrateCancel(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);

endjob:
E
Eric Blake 已提交
11699
    if (!qemuDomainObjEndJob(driver, vm))
11700
        vm = NULL;
11701 11702 11703

cleanup:
    if (vm)
11704
        virObjectUnlock(vm);
11705 11706 11707 11708
    return ret;
}


11709 11710 11711 11712 11713
static int
qemuDomainMigrateSetMaxDowntime(virDomainPtr dom,
                                unsigned long long downtime,
                                unsigned int flags)
{
11714
    virQEMUDriverPtr driver = dom->conn->privateData;
11715 11716 11717 11718
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

11719
    virCheckFlags(0, -1);
11720

11721 11722
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
11723

11724 11725 11726
    if (virDomainMigrateSetMaxDowntimeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

11727 11728 11729
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
        goto cleanup;

11730
    if (!virDomainObjIsActive(vm)) {
11731 11732
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
11733
        goto endjob;
11734 11735 11736 11737
    }

    priv = vm->privateData;

11738
    if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
11739 11740
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not being migrated"));
11741
        goto endjob;
11742 11743
    }

11744
    VIR_DEBUG("Setting migration downtime to %llums", downtime);
11745
    qemuDomainObjEnterMonitor(driver, vm);
11746 11747 11748 11749
    ret = qemuMonitorSetMigrationDowntime(priv->mon, downtime);
    qemuDomainObjExitMonitor(driver, vm);

endjob:
E
Eric Blake 已提交
11750
    if (!qemuDomainObjEndJob(driver, vm))
11751
        vm = NULL;
11752 11753 11754

cleanup:
    if (vm)
11755
        virObjectUnlock(vm);
11756 11757 11758
    return ret;
}

11759 11760 11761 11762 11763 11764 11765 11766 11767 11768 11769 11770 11771 11772 11773
static int
qemuDomainMigrateGetCompressionCache(virDomainPtr dom,
                                     unsigned long long *cacheSize,
                                     unsigned int flags)
{
    virQEMUDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

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

11774 11775 11776
    if (virDomainMigrateGetCompressionCacheEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

11777 11778 11779 11780 11781 11782 11783 11784 11785 11786 11787 11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 11798 11799 11800 11801 11802 11803 11804
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;

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

    priv = vm->privateData;

    qemuDomainObjEnterMonitor(driver, vm);

    ret = qemuMonitorGetMigrationCapability(
                priv->mon,
                QEMU_MONITOR_MIGRATION_CAPS_XBZRLE);
    if (ret == 0) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("Compressed migration is not supported by "
                         "QEMU binary"));
        ret = -1;
    } else if (ret > 0) {
        ret = qemuMonitorGetMigrationCacheSize(priv->mon, cacheSize);
    }

    qemuDomainObjExitMonitor(driver, vm);

endjob:
E
Eric Blake 已提交
11805
    if (!qemuDomainObjEndJob(driver, vm))
11806 11807 11808 11809 11810 11811 11812 11813 11814 11815 11816 11817 11818 11819 11820 11821 11822 11823 11824 11825 11826 11827 11828
        vm = NULL;

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

static int
qemuDomainMigrateSetCompressionCache(virDomainPtr dom,
                                     unsigned long long cacheSize,
                                     unsigned int flags)
{
    virQEMUDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

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

11829 11830 11831
    if (virDomainMigrateSetCompressionCacheEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

11832 11833 11834 11835 11836 11837 11838 11839 11840 11841 11842 11843 11844 11845 11846 11847 11848 11849 11850 11851 11852 11853 11854 11855 11856 11857 11858 11859 11860
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
        goto cleanup;

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

    priv = vm->privateData;

    qemuDomainObjEnterMonitor(driver, vm);

    ret = qemuMonitorGetMigrationCapability(
                priv->mon,
                QEMU_MONITOR_MIGRATION_CAPS_XBZRLE);
    if (ret == 0) {
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("Compressed migration is not supported by "
                         "QEMU binary"));
        ret = -1;
    } else if (ret > 0) {
        VIR_DEBUG("Setting compression cache to %llu B", cacheSize);
        ret = qemuMonitorSetMigrationCacheSize(priv->mon, cacheSize);
    }

    qemuDomainObjExitMonitor(driver, vm);

endjob:
E
Eric Blake 已提交
11861
    if (!qemuDomainObjEndJob(driver, vm))
11862 11863 11864 11865 11866 11867 11868 11869
        vm = NULL;

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

11870 11871 11872 11873 11874
static int
qemuDomainMigrateSetMaxSpeed(virDomainPtr dom,
                             unsigned long bandwidth,
                             unsigned int flags)
{
11875
    virQEMUDriverPtr driver = dom->conn->privateData;
11876 11877 11878 11879 11880 11881
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

11882 11883
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
11884 11885

    priv = vm->privateData;
11886 11887 11888 11889

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

11890 11891 11892
    if (virDomainObjIsActive(vm)) {
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
            goto cleanup;
11893

11894
        if (!virDomainObjIsActive(vm)) {
11895 11896
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("domain is not running"));
11897 11898 11899
            goto endjob;
        }

11900 11901 11902 11903
        VIR_DEBUG("Setting migration bandwidth to %luMbs", bandwidth);
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSetMigrationSpeed(priv->mon, bandwidth);
        qemuDomainObjExitMonitor(driver, vm);
11904

11905 11906
        if (ret == 0)
            priv->migMaxBandwidth = bandwidth;
11907

11908
endjob:
E
Eric Blake 已提交
11909
        if (!qemuDomainObjEndJob(driver, vm))
11910 11911 11912 11913 11914
            vm = NULL;
    } else {
        priv->migMaxBandwidth = bandwidth;
        ret = 0;
    }
11915 11916 11917

cleanup:
    if (vm)
11918
        virObjectUnlock(vm);
11919 11920 11921
    return ret;
}

11922 11923 11924 11925 11926 11927
static int
qemuDomainMigrateGetMaxSpeed(virDomainPtr dom,
                             unsigned long *bandwidth,
                             unsigned int flags)
{
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
11928
    qemuDomainObjPrivatePtr priv;
11929 11930 11931 11932
    int ret = -1;

    virCheckFlags(0, -1);

11933
    if (!(vm = qemuDomObjFromDomain(dom)))
11934 11935
        goto cleanup;

J
Jim Fehlig 已提交
11936
    priv = vm->privateData;
11937 11938 11939 11940

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

J
Jim Fehlig 已提交
11941
    *bandwidth = priv->migMaxBandwidth;
11942 11943 11944 11945
    ret = 0;

cleanup:
    if (vm)
11946
        virObjectUnlock(vm);
11947 11948 11949
    return ret;
}

11950 11951 11952 11953 11954 11955 11956 11957 11958 11959 11960 11961 11962 11963 11964 11965 11966 11967

static int
qemuDomainSnapshotDiskGetSourceString(virDomainSnapshotDiskDefPtr disk,
                                      char **source)
{
    *source = NULL;

    return qemuGetDriveSourceString(virDomainSnapshotDiskGetActualType(disk),
                                    disk->file,
                                    disk->protocol,
                                    disk->nhosts,
                                    disk->hosts,
                                    NULL,
                                    NULL,
                                    source);
}


11968 11969 11970 11971 11972 11973 11974 11975 11976 11977 11978 11979
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
11980
qemuDomainPrepareDiskChainElement(virQEMUDriverPtr driver,
11981 11982
                                  virDomainObjPtr vm,
                                  virDomainDiskDefPtr disk,
11983
                                  const char *file,
11984 11985 11986 11987 11988 11989 11990 11991 11992 11993
                                  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;
11994
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
11995

11996
    disk->src = (char *) file; /* casting away const is safe here */
11997 11998 11999 12000 12001 12002 12003 12004
    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);
12005
        if (qemuTeardownDiskCgroup(vm, disk) < 0)
12006 12007 12008
            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);
12009
    } else if (virDomainLockDiskAttach(driver->lockManager, cfg->uri,
12010
                                       vm, disk) < 0 ||
12011
               qemuSetupDiskCgroup(vm, disk) < 0 ||
12012 12013 12014 12015 12016 12017 12018 12019 12020 12021 12022 12023
               virSecurityManagerSetImageLabel(driver->securityManager,
                                               vm->def, disk) < 0) {
        goto cleanup;
    }

    ret = 0;

cleanup:
    disk->src = origsrc;
    disk->format = origformat;
    disk->backingChain = origchain;
    disk->readonly = origreadonly;
12024
    virObjectUnref(cfg);
12025 12026 12027 12028
    return ret;
}


12029
static int
12030
qemuDomainSnapshotFSFreeze(virDomainObjPtr vm) {
12031 12032 12033 12034
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int freezed;

    if (priv->agentError) {
12035
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
12036 12037
                       _("QEMU guest agent is not "
                         "available due to an error"));
12038 12039 12040
        return -1;
    }
    if (!priv->agent) {
12041 12042
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("QEMU guest agent is not configured"));
12043 12044 12045
        return -1;
    }

12046
    qemuDomainObjEnterAgent(vm);
12047
    freezed = qemuAgentFSFreeze(priv->agent);
12048
    qemuDomainObjExitAgent(vm);
12049 12050 12051 12052 12053

    return freezed;
}

static int
12054
qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report)
E
Eric Blake 已提交
12055
{
12056 12057
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int thawed;
E
Eric Blake 已提交
12058
    virErrorPtr err = NULL;
12059 12060

    if (priv->agentError) {
E
Eric Blake 已提交
12061
        if (report)
12062
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
12063 12064
                           _("QEMU guest agent is not "
                             "available due to an error"));
12065 12066 12067
        return -1;
    }
    if (!priv->agent) {
E
Eric Blake 已提交
12068
        if (report)
12069 12070
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
12071 12072 12073
        return -1;
    }

12074
    qemuDomainObjEnterAgent(vm);
E
Eric Blake 已提交
12075
    if (!report)
12076
        err = virSaveLastError();
12077
    thawed = qemuAgentFSThaw(priv->agent);
12078 12079
    if (!report)
        virSetError(err);
12080
    qemuDomainObjExitAgent(vm);
12081

12082
    virFreeError(err);
12083 12084 12085
    return thawed;
}

12086 12087
/* The domain is expected to be locked and inactive. */
static int
12088
qemuDomainSnapshotCreateInactiveInternal(virQEMUDriverPtr driver,
12089 12090
                                         virDomainObjPtr vm,
                                         virDomainSnapshotObjPtr snap)
12091
{
E
Eric Blake 已提交
12092
    return qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-c", false);
12093 12094
}

12095 12096
/* The domain is expected to be locked and inactive. */
static int
12097
qemuDomainSnapshotCreateInactiveExternal(virQEMUDriverPtr driver,
12098 12099 12100 12101
                                         virDomainObjPtr vm,
                                         virDomainSnapshotObjPtr snap,
                                         bool reuse)
{
12102
    size_t i;
12103 12104 12105 12106
    virDomainSnapshotDiskDefPtr snapdisk;
    virDomainDiskDefPtr defdisk;
    virCommandPtr cmd = NULL;
    const char *qemuImgPath;
12107 12108
    virBitmapPtr created = NULL;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
12109 12110 12111
    int ret = -1;

    if (!(qemuImgPath = qemuFindQemuImgBinary(driver)))
12112
        goto cleanup;
12113

12114
    if (!(created = virBitmapNew(snap->def->ndisks)))
12115
        goto cleanup;
12116 12117 12118 12119 12120 12121 12122 12123 12124 12125 12126 12127 12128 12129 12130 12131 12132 12133 12134 12135 12136 12137 12138 12139 12140 12141 12142 12143

    /* 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 {
12144
            if (!cfg->allowDiskFormatProbing) {
12145 12146 12147 12148 12149 12150 12151 12152 12153 12154 12155 12156 12157 12158 12159 12160 12161 12162 12163 12164 12165 12166 12167 12168 12169 12170 12171 12172 12173 12174 12175 12176
                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);
12177
            if (VIR_STRDUP(defdisk->src, snapdisk->file) < 0) {
12178 12179 12180 12181 12182 12183 12184 12185 12186 12187 12188 12189 12190
                /* we cannot rollback here in a sane way */
                goto cleanup;
            }
            defdisk->format = snapdisk->format;
        }
    }

    ret = 0;

cleanup:
    virCommandFree(cmd);

    /* unlink images if creation has failed */
12191
    if (ret < 0 && created) {
12192 12193 12194 12195 12196 12197 12198 12199 12200
        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);
12201
    virObjectUnref(cfg);
12202 12203 12204 12205

    return ret;
}

12206

12207 12208
/* The domain is expected to be locked and active. */
static int
12209
qemuDomainSnapshotCreateActiveInternal(virConnectPtr conn,
12210
                                       virQEMUDriverPtr driver,
12211 12212 12213
                                       virDomainObjPtr *vmptr,
                                       virDomainSnapshotObjPtr snap,
                                       unsigned int flags)
12214 12215 12216
{
    virDomainObjPtr vm = *vmptr;
    qemuDomainObjPrivatePtr priv = vm->privateData;
12217
    virObjectEventPtr event = NULL;
12218 12219
    bool resume = false;
    int ret = -1;
12220

12221
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
12222 12223
        return -1;

12224
    if (!virDomainObjIsActive(vm)) {
12225 12226
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
12227 12228 12229
        goto endjob;
    }

J
Jiri Denemark 已提交
12230
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
12231 12232 12233 12234
        /* 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.
         */
12235 12236
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_NONE) < 0)
12237 12238 12239 12240
            goto cleanup;

        resume = true;
        if (!virDomainObjIsActive(vm)) {
12241 12242
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
12243 12244 12245 12246
            goto cleanup;
        }
    }

12247
    qemuDomainObjEnterMonitor(driver, vm);
12248
    ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name);
12249
    qemuDomainObjExitMonitor(driver, vm);
12250 12251 12252 12253
    if (ret < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
12254
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
12255
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
12256
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
12257 12258 12259 12260 12261 12262 12263
        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;
    }
12264

12265 12266
cleanup:
    if (resume && virDomainObjIsActive(vm) &&
J
Jiri Denemark 已提交
12267
        qemuProcessStartCPUs(driver, vm, conn,
12268
                             VIR_DOMAIN_RUNNING_UNPAUSED,
12269
                             QEMU_ASYNC_JOB_NONE) < 0) {
12270
        event = virDomainEventLifecycleNewFromObj(vm,
12271 12272 12273 12274 12275 12276
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
        if (virGetLastError() == NULL) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("resuming after snapshot failed"));
        }
12277 12278
    }

12279
endjob:
E
Eric Blake 已提交
12280
    if (vm && !qemuDomainObjEndJob(driver, vm)) {
12281 12282
        /* Only possible if a transient vm quit while our locks were down,
         * in which case we don't want to save snapshot metadata.  */
12283
        *vmptr = NULL;
12284 12285
        ret = -1;
    }
12286

12287 12288 12289
    if (event)
        qemuDomainEventQueue(driver, event);

12290 12291 12292
    return ret;
}

12293
static int
12294
qemuDomainSnapshotPrepareDiskExternalBackingInactive(virDomainDiskDefPtr disk)
12295
{
12296
    int actualType = virDomainDiskGetActualType(disk);
12297 12298 12299 12300 12301 12302 12303 12304 12305 12306 12307 12308 12309 12310 12311 12312 12313 12314 12315 12316 12317 12318 12319 12320 12321 12322 12323 12324 12325 12326 12327 12328 12329 12330 12331 12332 12333 12334 12335 12336

    switch ((enum virDomainDiskType) actualType) {
    case VIR_DOMAIN_DISK_TYPE_BLOCK:
    case VIR_DOMAIN_DISK_TYPE_FILE:
        return 0;

    case VIR_DOMAIN_DISK_TYPE_NETWORK:
        switch ((enum virDomainDiskProtocol) disk->protocol) {
        case VIR_DOMAIN_DISK_PROTOCOL_NBD:
        case VIR_DOMAIN_DISK_PROTOCOL_RBD:
        case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
        case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER:
        case VIR_DOMAIN_DISK_PROTOCOL_ISCSI:
        case VIR_DOMAIN_DISK_PROTOCOL_HTTP:
        case VIR_DOMAIN_DISK_PROTOCOL_HTTPS:
        case VIR_DOMAIN_DISK_PROTOCOL_FTP:
        case VIR_DOMAIN_DISK_PROTOCOL_FTPS:
        case VIR_DOMAIN_DISK_PROTOCOL_TFTP:
        case VIR_DOMAIN_DISK_PROTOCOL_LAST:
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("external inactive snapshots are not supported on "
                             "'network' disks using '%s' protocol"),
                           virDomainDiskProtocolTypeToString(disk->protocol));
            return -1;
        }
        break;

    case VIR_DOMAIN_DISK_TYPE_DIR:
    case VIR_DOMAIN_DISK_TYPE_VOLUME:
    case VIR_DOMAIN_DISK_TYPE_LAST:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("external inactive snapshots are not supported on "
                         "'%s' disks"), virDomainDiskTypeToString(actualType));
        return -1;
    }

    return 0;
}


12337 12338 12339
static int
qemuDomainSnapshotPrepareDiskExternalBackingActive(virDomainDiskDefPtr disk)
{
12340
    int actualType = virDomainDiskGetActualType(disk);
12341 12342 12343 12344 12345 12346 12347 12348 12349 12350 12351 12352 12353

    if (actualType == VIR_DOMAIN_DISK_TYPE_BLOCK &&
        disk->device == VIR_DOMAIN_DISK_DEVICE_LUN) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("external active snapshots are not supported on scsi "
                         "passthrough devices"));
        return -1;
    }

    return 0;
}


12354 12355 12356
static int
qemuDomainSnapshotPrepareDiskExternalOverlayActive(virDomainSnapshotDiskDefPtr disk)
{
12357
    int actualType = virDomainSnapshotDiskGetActualType(disk);
12358 12359 12360 12361 12362 12363 12364

    switch ((enum virDomainDiskType) actualType) {
    case VIR_DOMAIN_DISK_TYPE_BLOCK:
    case VIR_DOMAIN_DISK_TYPE_FILE:
        return 0;

    case VIR_DOMAIN_DISK_TYPE_NETWORK:
12365 12366 12367 12368 12369 12370 12371 12372 12373 12374 12375 12376 12377 12378 12379 12380 12381 12382 12383 12384 12385 12386 12387
        switch ((enum virDomainDiskProtocol) disk->protocol) {
        case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER:
            return 0;

        case VIR_DOMAIN_DISK_PROTOCOL_NBD:
        case VIR_DOMAIN_DISK_PROTOCOL_RBD:
        case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
        case VIR_DOMAIN_DISK_PROTOCOL_ISCSI:
        case VIR_DOMAIN_DISK_PROTOCOL_HTTP:
        case VIR_DOMAIN_DISK_PROTOCOL_HTTPS:
        case VIR_DOMAIN_DISK_PROTOCOL_FTP:
        case VIR_DOMAIN_DISK_PROTOCOL_FTPS:
        case VIR_DOMAIN_DISK_PROTOCOL_TFTP:
        case VIR_DOMAIN_DISK_PROTOCOL_LAST:
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("external active snapshots are not supported on "
                             "'network' disks using '%s' protocol"),
                           virDomainDiskProtocolTypeToString(disk->protocol));
            return -1;

        }
        break;

12388 12389 12390 12391 12392 12393 12394 12395 12396 12397 12398 12399 12400 12401 12402 12403
    case VIR_DOMAIN_DISK_TYPE_DIR:
    case VIR_DOMAIN_DISK_TYPE_VOLUME:
    case VIR_DOMAIN_DISK_TYPE_LAST:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("external active snapshots are not supported on "
                         "'%s' disks"), virDomainDiskTypeToString(actualType));
        return -1;
    }

    return 0;
}


static int
qemuDomainSnapshotPrepareDiskExternalOverlayInactive(virDomainSnapshotDiskDefPtr disk)
{
12404
    int actualType = virDomainSnapshotDiskGetActualType(disk);
12405 12406 12407 12408 12409 12410 12411 12412 12413 12414 12415 12416 12417 12418 12419 12420 12421 12422 12423 12424 12425 12426 12427 12428 12429 12430 12431

    switch ((enum virDomainDiskType) actualType) {
    case VIR_DOMAIN_DISK_TYPE_BLOCK:
    case VIR_DOMAIN_DISK_TYPE_FILE:
        return 0;

    case VIR_DOMAIN_DISK_TYPE_NETWORK:
    case VIR_DOMAIN_DISK_TYPE_DIR:
    case VIR_DOMAIN_DISK_TYPE_VOLUME:
    case VIR_DOMAIN_DISK_TYPE_LAST:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("external inactive snapshots are not supported on "
                         "'%s' disks"), virDomainDiskTypeToString(actualType));
        return -1;
    }

    return 0;
}


static int
qemuDomainSnapshotPrepareDiskExternal(virConnectPtr conn,
                                      virDomainDiskDefPtr disk,
                                      virDomainSnapshotDiskDefPtr snapdisk,
                                      bool active,
                                      bool reuse)
{
12432 12433
    virStorageFilePtr snapfile = NULL;
    int ret = -1;
12434 12435 12436 12437 12438 12439 12440 12441 12442
    struct stat st;

    if (qemuTranslateSnapshotDiskSourcePool(conn, snapdisk) < 0)
        return -1;

    if (!active) {
        if (qemuTranslateDiskSourcePool(conn, disk) < 0)
            return -1;

12443
        if (qemuDomainSnapshotPrepareDiskExternalBackingInactive(disk) < 0)
12444 12445 12446 12447 12448
            return -1;

        if (qemuDomainSnapshotPrepareDiskExternalOverlayInactive(snapdisk) < 0)
            return -1;
    } else {
12449 12450 12451
        if (qemuDomainSnapshotPrepareDiskExternalBackingActive(disk) < 0)
            return -1;

12452 12453 12454 12455
        if (qemuDomainSnapshotPrepareDiskExternalOverlayActive(snapdisk) < 0)
            return -1;
    }

12456 12457
    if (!(snapfile = virStorageFileInitFromSnapshotDef(snapdisk)))
        return -1;
12458

12459 12460 12461 12462 12463 12464 12465 12466 12467 12468 12469
    if (virStorageFileStat(snapfile, &st) < 0) {
        if (errno != ENOENT) {
            virReportSystemError(errno,
                                 _("unable to stat for disk %s: %s"),
                                 snapdisk->name, snapdisk->file);
            goto cleanup;
        } else if (reuse) {
            virReportSystemError(errno,
                                 _("missing existing file for disk %s: %s"),
                                 snapdisk->name, snapdisk->file);
            goto cleanup;
12470
        }
12471 12472 12473 12474 12475 12476
    } else if (!S_ISBLK(st.st_mode) && st.st_size && !reuse) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("external snapshot file for disk %s already "
                         "exists and is not a block device: %s"),
                       snapdisk->name, snapdisk->file);
        goto cleanup;
12477 12478
    }

12479 12480 12481 12482 12483
    ret = 0;

cleanup:
    virStorageFileFree(snapfile);
    return ret;
12484 12485 12486 12487 12488 12489 12490 12491 12492 12493 12494 12495 12496 12497 12498 12499 12500
}


static int
qemuDomainSnapshotPrepareDiskInternal(virConnectPtr conn,
                                      virDomainDiskDefPtr disk,
                                      bool active)
{
    int actualType;

    /* active disks are handeled by qemu itself so no need to worry about those */
    if (active)
        return 0;

    if (qemuTranslateDiskSourcePool(conn, disk) < 0)
        return -1;

12501
    actualType = virDomainDiskGetActualType(disk);
12502 12503 12504 12505 12506 12507 12508 12509 12510 12511 12512 12513 12514 12515 12516 12517 12518 12519 12520 12521 12522 12523 12524 12525 12526 12527 12528 12529 12530 12531 12532 12533 12534 12535 12536 12537 12538 12539 12540 12541 12542 12543 12544 12545

    switch ((enum virDomainDiskType) actualType) {
    case VIR_DOMAIN_DISK_TYPE_BLOCK:
    case VIR_DOMAIN_DISK_TYPE_FILE:
        return 0;

    case VIR_DOMAIN_DISK_TYPE_NETWORK:
        switch ((enum virDomainDiskProtocol) disk->protocol) {
        case VIR_DOMAIN_DISK_PROTOCOL_NBD:
        case VIR_DOMAIN_DISK_PROTOCOL_RBD:
        case VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG:
        case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER:
        case VIR_DOMAIN_DISK_PROTOCOL_ISCSI:
        case VIR_DOMAIN_DISK_PROTOCOL_HTTP:
        case VIR_DOMAIN_DISK_PROTOCOL_HTTPS:
        case VIR_DOMAIN_DISK_PROTOCOL_FTP:
        case VIR_DOMAIN_DISK_PROTOCOL_FTPS:
        case VIR_DOMAIN_DISK_PROTOCOL_TFTP:
        case VIR_DOMAIN_DISK_PROTOCOL_LAST:
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("internal inactive snapshots are not supported on "
                             "'network' disks using '%s' protocol"),
                           virDomainDiskProtocolTypeToString(disk->protocol));
            return -1;
        }
        break;

    case VIR_DOMAIN_DISK_TYPE_DIR:
    case VIR_DOMAIN_DISK_TYPE_VOLUME:
    case VIR_DOMAIN_DISK_TYPE_LAST:
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("internal inactive snapshots are not supported on "
                         "'%s' disks"), virDomainDiskTypeToString(actualType));
        return -1;
    }

    return 0;
}


static int
qemuDomainSnapshotPrepare(virConnectPtr conn,
                          virDomainObjPtr vm,
                          virDomainSnapshotDefPtr def,
E
Eric Blake 已提交
12546
                          unsigned int *flags)
12547 12548
{
    int ret = -1;
12549
    size_t i;
12550
    bool active = virDomainObjIsActive(vm);
12551
    bool reuse = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
12552
    bool atomic = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC) != 0;
12553
    bool found_internal = false;
12554 12555
    int external = 0;
    qemuDomainObjPrivatePtr priv = vm->privateData;
12556

E
Eric Blake 已提交
12557
    if (def->state == VIR_DOMAIN_DISK_SNAPSHOT &&
12558
        reuse && !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
12559 12560
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("reuse is not supported with this QEMU binary"));
12561 12562 12563
        goto cleanup;
    }

12564 12565
    for (i = 0; i < def->ndisks; i++) {
        virDomainSnapshotDiskDefPtr disk = &def->disks[i];
E
Eric Blake 已提交
12566
        virDomainDiskDefPtr dom_disk = vm->def->disks[i];
12567 12568

        switch (disk->snapshot) {
E
Eric Blake 已提交
12569
        case VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL:
12570 12571
            found_internal = true;

12572 12573 12574 12575 12576 12577 12578 12579 12580 12581 12582 12583 12584
            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;
            }

            if (qemuDomainSnapshotPrepareDiskInternal(conn, dom_disk,
                                                      active) < 0)
                goto cleanup;

            if (dom_disk->type == VIR_DOMAIN_DISK_TYPE_NETWORK &&
E
Eric Blake 已提交
12585 12586 12587
                (dom_disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG ||
                 dom_disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD)) {
                break;
12588
            }
12589 12590
            if (vm->def->disks[i]->format > 0 &&
                vm->def->disks[i]->format != VIR_STORAGE_FILE_QCOW2) {
12591 12592 12593 12594
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("internal snapshot for disk %s unsupported "
                                 "for storage type %s"),
                               disk->name,
12595 12596
                               virStorageFileFormatTypeToString(
                                   vm->def->disks[i]->format));
12597 12598 12599 12600
                goto cleanup;
            }
            break;

E
Eric Blake 已提交
12601
        case VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL:
12602 12603 12604 12605
            if (!disk->format) {
                disk->format = VIR_STORAGE_FILE_QCOW2;
            } else if (disk->format != VIR_STORAGE_FILE_QCOW2 &&
                       disk->format != VIR_STORAGE_FILE_QED) {
12606 12607 12608
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("external snapshot format for disk %s "
                                 "is unsupported: %s"),
12609 12610
                               disk->name,
                               virStorageFileFormatTypeToString(disk->format));
12611 12612
                goto cleanup;
            }
12613 12614 12615

            if (qemuDomainSnapshotPrepareDiskExternal(conn, dom_disk, disk,
                                                      active, reuse) < 0)
12616
                goto cleanup;
12617

12618
            external++;
12619 12620
            break;

E
Eric Blake 已提交
12621
        case VIR_DOMAIN_SNAPSHOT_LOCATION_NONE:
12622 12623
            break;

E
Eric Blake 已提交
12624
        case VIR_DOMAIN_SNAPSHOT_LOCATION_DEFAULT:
12625
        default:
12626 12627
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("unexpected code path"));
12628 12629 12630 12631
            goto cleanup;
        }
    }

12632 12633 12634
    /* internal snapshot requires a disk image to store the memory image to */
    if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL &&
        !found_internal) {
12635
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
12636
                       _("internal checkpoints require at least "
12637
                         "one disk to be selected for snapshot"));
12638 12639
        goto cleanup;
    }
12640

12641 12642 12643 12644 12645 12646 12647 12648 12649 12650 12651 12652 12653
    /* 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",
12654 12655
                       _("mixing internal and external targets for a snapshot "
                         "is not yet supported"));
12656 12657 12658 12659 12660 12661 12662
        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 已提交
12663
    if (def->state != VIR_DOMAIN_DISK_SNAPSHOT && active) {
12664
        if (external == 1 ||
12665
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
12666 12667
            *flags |= VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC;
        } else if (atomic && external > 1) {
12668 12669 12670
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("atomic live snapshot of multiple disks "
                             "is unsupported"));
12671 12672 12673
            goto cleanup;
        }
    }
12674 12675 12676 12677 12678 12679 12680 12681 12682

    ret = 0;

cleanup:
    return ret;
}

/* The domain is expected to hold monitor lock.  */
static int
12683
qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver,
12684
                                         virDomainObjPtr vm,
12685
                                         virDomainSnapshotDiskDefPtr snap,
12686
                                         virDomainDiskDefPtr disk,
12687
                                         virDomainDiskDefPtr persistDisk,
12688
                                         virJSONValuePtr actions,
12689 12690
                                         bool reuse,
                                         enum qemuDomainAsyncJob asyncJob)
12691 12692 12693 12694
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *device = NULL;
    char *source = NULL;
12695 12696 12697
    char *newsource = NULL;
    virDomainDiskHostDefPtr newhosts = NULL;
    virDomainDiskHostDefPtr persistHosts = NULL;
12698 12699
    int format = snap->format;
    const char *formatStr = NULL;
12700
    char *persistSource = NULL;
12701
    int ret = -1;
12702 12703
    int fd = -1;
    bool need_unlink = false;
12704
    virStorageFilePtr snapfile = NULL;
12705

E
Eric Blake 已提交
12706
    if (snap->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
12707 12708
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected code path"));
12709 12710 12711
        return -1;
    }

12712
    if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0)
12713 12714
        goto cleanup;

12715
    /* XXX Here, we know we are about to alter disk->backingChain if
12716 12717 12718 12719
     * 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.  */
12720 12721
    virStorageFileFreeMetadata(disk->backingChain);
    disk->backingChain = NULL;
12722

12723 12724 12725
    if (!(snapfile = virStorageFileInitFromSnapshotDef(snap)))
        goto cleanup;

12726 12727 12728 12729 12730 12731 12732 12733 12734 12735
    if (qemuDomainSnapshotDiskGetSourceString(snap, &source) < 0)
        goto cleanup;

    if (VIR_STRDUP(newsource, snap->file) < 0)
        goto cleanup;

    if (persistDisk &&
        VIR_STRDUP(persistSource, snap->file) < 0)
        goto cleanup;

12736 12737 12738 12739 12740 12741 12742 12743 12744 12745 12746 12747 12748 12749 12750 12751 12752 12753 12754 12755 12756 12757 12758 12759
    switch (snap->type) {
    case VIR_DOMAIN_DISK_TYPE_BLOCK:
        reuse = true;
        /* fallthrough */
    case VIR_DOMAIN_DISK_TYPE_FILE:

        /* create the stub file and set selinux labels; manipulate disk in
         * place, in a way that can be reverted on failure. */
        if (!reuse) {
            fd = qemuOpenFile(driver, vm, source, O_WRONLY | O_TRUNC | O_CREAT,
                              &need_unlink, NULL);
            if (fd < 0)
                goto cleanup;
            VIR_FORCE_CLOSE(fd);
        }

        if (qemuDomainPrepareDiskChainElement(driver, vm, disk, source,
                                              VIR_DISK_CHAIN_READ_WRITE) < 0) {
            qemuDomainPrepareDiskChainElement(driver, vm, disk, source,
                                              VIR_DISK_CHAIN_NO_ACCESS);
            goto cleanup;
        }
        break;

12760 12761 12762 12763 12764 12765 12766 12767 12768 12769 12770 12771 12772 12773 12774 12775 12776 12777 12778 12779 12780
    case VIR_DOMAIN_DISK_TYPE_NETWORK:
        switch (snap->protocol) {
        case VIR_DOMAIN_DISK_PROTOCOL_GLUSTER:
            if (!(newhosts = virDomainDiskHostDefCopy(snap->nhosts, snap->hosts)))
                goto cleanup;

            if (persistDisk &&
                !(persistHosts = virDomainDiskHostDefCopy(snap->nhosts, snap->hosts)))
                goto cleanup;

            break;

        default:
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                           _("snapshots on volumes using '%s' protocol "
                             "are not supported"),
                           virDomainDiskProtocolTypeToString(snap->protocol));
            goto cleanup;
        }
        break;

12781 12782 12783 12784
    default:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("snapshots are not supported on '%s' volumes"),
                       virDomainDiskTypeToString(snap->type));
12785 12786 12787 12788
        goto cleanup;
    }

    /* create the actual snapshot */
12789 12790
    if (snap->format)
        formatStr = virStorageFileFormatTypeToString(snap->format);
12791 12792 12793 12794 12795 12796 12797 12798

    /* The monitor is only accessed if qemu doesn't support transactions.
     * Otherwise the following monitor command only constructs the command.
     */
    if (!actions &&
        qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) < 0)
        goto cleanup;

12799
    ret = qemuMonitorDiskSnapshot(priv->mon, actions, device, source,
12800
                                  formatStr, reuse);
12801 12802 12803 12804 12805 12806 12807 12808 12809
    if (!actions) {
        qemuDomainObjExitMonitor(driver, vm);
        if (!virDomainObjIsActive(vm)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("domain crashed while taking the snapshot"));
            ret = -1;
        }
    }

12810 12811 12812 12813 12814
    virDomainAuditDisk(vm, disk->src, source, "snapshot", ret >= 0);
    if (ret < 0)
        goto cleanup;

    /* Update vm in place to match changes.  */
12815
    need_unlink = false;
12816

12817
    VIR_FREE(disk->src);
12818 12819 12820
    virDomainDiskHostDefFree(disk->nhosts, disk->hosts);

    disk->src = newsource;
12821
    disk->format = format;
12822
    disk->type = snap->type;
12823 12824 12825 12826 12827 12828 12829
    disk->protocol = snap->protocol;
    disk->nhosts = snap->nhosts;
    disk->hosts = newhosts;

    newsource = NULL;
    newhosts = NULL;

12830 12831
    if (persistDisk) {
        VIR_FREE(persistDisk->src);
12832 12833
        virDomainDiskHostDefFree(persistDisk->nhosts, persistDisk->hosts);

12834
        persistDisk->src = persistSource;
12835
        persistDisk->format = format;
12836
        persistDisk->type = snap->type;
12837 12838 12839 12840 12841 12842
        persistDisk->protocol = snap->protocol;
        persistDisk->nhosts = snap->nhosts;
        persistDisk->hosts = persistHosts;

        persistSource = NULL;
        persistHosts = NULL;
12843
    }
12844 12845

cleanup:
12846
    if (need_unlink && virStorageFileUnlink(snapfile))
12847
        VIR_WARN("unable to unlink just-created %s", source);
12848
    virStorageFileFree(snapfile);
12849 12850
    VIR_FREE(device);
    VIR_FREE(source);
12851
    VIR_FREE(newsource);
12852
    VIR_FREE(persistSource);
12853 12854
    virDomainDiskHostDefFree(snap->nhosts, newhosts);
    virDomainDiskHostDefFree(snap->nhosts, persistHosts);
12855 12856 12857
    return ret;
}

12858 12859 12860 12861
/* The domain is expected to hold monitor lock.  This is the
 * counterpart to qemuDomainSnapshotCreateSingleDiskActive, called
 * only on a failed transaction. */
static void
12862
qemuDomainSnapshotUndoSingleDiskActive(virQEMUDriverPtr driver,
12863 12864 12865 12866 12867 12868 12869 12870
                                       virDomainObjPtr vm,
                                       virDomainDiskDefPtr origdisk,
                                       virDomainDiskDefPtr disk,
                                       virDomainDiskDefPtr persistDisk,
                                       bool need_unlink)
{
    char *source = NULL;
    char *persistSource = NULL;
12871
    virStorageFilePtr diskfile = NULL;
12872 12873
    struct stat st;

12874 12875
    diskfile = virStorageFileInitFromDiskDef(disk);

12876 12877
    if (VIR_STRDUP(source, origdisk->src) < 0 ||
        (persistDisk && VIR_STRDUP(persistSource, source) < 0))
12878 12879
        goto cleanup;

12880
    qemuDomainPrepareDiskChainElement(driver, vm, disk, disk->src,
12881
                                      VIR_DISK_CHAIN_NO_ACCESS);
12882 12883 12884
    if (need_unlink && diskfile &&
        virStorageFileStat(diskfile, &st) == 0 && S_ISREG(st.st_mode) &&
        virStorageFileUnlink(diskfile) < 0)
12885 12886 12887 12888 12889 12890
        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;
12891
    disk->format = origdisk->format;
12892
    disk->type = origdisk->type;
12893 12894 12895 12896
    disk->protocol = origdisk->protocol;
    virDomainDiskHostDefFree(disk->nhosts, disk->hosts);
    disk->nhosts = origdisk->nhosts;
    disk->hosts = virDomainDiskHostDefCopy(origdisk->nhosts, origdisk->hosts);
12897 12898 12899 12900
    if (persistDisk) {
        VIR_FREE(persistDisk->src);
        persistDisk->src = persistSource;
        persistSource = NULL;
12901
        persistDisk->format = origdisk->format;
12902
        persistDisk->type = origdisk->type;
12903 12904 12905 12906
        persistDisk->protocol = origdisk->protocol;
        virDomainDiskHostDefFree(persistDisk->nhosts, persistDisk->hosts);
        persistDisk->nhosts = origdisk->nhosts;
        persistDisk->hosts = virDomainDiskHostDefCopy(origdisk->nhosts, origdisk->hosts);
12907 12908 12909
    }

cleanup:
12910
    virStorageFileFree(diskfile);
12911 12912 12913 12914
    VIR_FREE(source);
    VIR_FREE(persistSource);
}

12915 12916
/* The domain is expected to be locked and active. */
static int
12917
qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver,
12918
                                   virDomainObjPtr vm,
12919
                                   virDomainSnapshotObjPtr snap,
12920 12921
                                   unsigned int flags,
                                   enum qemuDomainAsyncJob asyncJob)
12922
{
12923 12924
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virJSONValuePtr actions = NULL;
12925
    int ret = -1;
12926
    size_t i;
12927
    bool persist = false;
12928
    bool reuse = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
12929
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
12930

12931
    if (!virDomainObjIsActive(vm)) {
12932 12933
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
12934
        goto cleanup;
12935 12936
    }

12937
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
12938
        if (!(actions = virJSONValueNewArray()))
12939
            goto cleanup;
12940
    } else if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DISK_SNAPSHOT)) {
12941 12942 12943 12944
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("live disk snapshot not supported with this "
                         "QEMU binary"));
        goto cleanup;
12945
    }
12946 12947

    /* No way to roll back if first disk succeeds but later disks
12948
     * fail, unless we have transaction support.
E
Eric Blake 已提交
12949
     * Based on earlier qemuDomainSnapshotPrepare, all
12950 12951 12952
     * disks in this list are now either SNAPSHOT_NO, or
     * SNAPSHOT_EXTERNAL with a valid file name and qcow2 format.  */
    for (i = 0; i < snap->def->ndisks; i++) {
12953 12954
        virDomainDiskDefPtr persistDisk = NULL;

E
Eric Blake 已提交
12955
        if (snap->def->disks[i].snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
12956
            continue;
12957 12958 12959 12960
        if (vm->newDef) {
            int indx = virDomainDiskIndexByName(vm->newDef,
                                                vm->def->disks[i]->dst,
                                                false);
12961
            if (indx >= 0)
12962 12963
                persistDisk = vm->newDef->disks[indx];
        }
12964

12965
        ret = qemuDomainSnapshotCreateSingleDiskActive(driver, vm,
12966
                                                       &snap->def->disks[i],
12967
                                                       vm->def->disks[i],
12968
                                                       persistDisk, actions,
12969
                                                       reuse, asyncJob);
12970 12971 12972
        if (ret < 0)
            break;
    }
12973
    if (actions) {
12974 12975 12976 12977 12978 12979 12980 12981 12982 12983 12984 12985 12986 12987 12988
        if (ret == 0) {
            if (qemuDomainObjEnterMonitorAsync(driver, vm, asyncJob) == 0) {
                ret = qemuMonitorTransaction(priv->mon, actions);
                qemuDomainObjExitMonitor(driver, vm);
                if (!virDomainObjIsActive(vm)) {
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("domain crashed while taking the snapshot"));
                    ret = -1;
                }
            } else {
                /* failed to enter monitor, clean stuff up and quit */
                ret = -1;
            }
        }

E
Eric Blake 已提交
12989
        virJSONValueFree(actions);
12990

12991 12992 12993
        if (ret < 0) {
            /* Transaction failed; undo the changes to vm.  */
            bool need_unlink = !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT);
12994
            while (i-- > 0) {
12995 12996
                virDomainDiskDefPtr persistDisk = NULL;

E
Eric Blake 已提交
12997 12998
                if (snap->def->disks[i].snapshot ==
                    VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
12999 13000 13001 13002 13003
                    continue;
                if (vm->newDef) {
                    int indx = virDomainDiskIndexByName(vm->newDef,
                                                        vm->def->disks[i]->dst,
                                                        false);
13004
                    if (indx >= 0) {
13005
                        persistDisk = vm->newDef->disks[indx];
13006 13007 13008
                        persist = true;
                    }

13009 13010
                }

13011
                qemuDomainSnapshotUndoSingleDiskActive(driver, vm,
13012 13013 13014 13015 13016 13017 13018
                                                       snap->def->dom->disks[i],
                                                       vm->def->disks[i],
                                                       persistDisk,
                                                       need_unlink);
            }
        }
    }
13019 13020 13021

cleanup:

13022
    if (ret == 0 || !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
13023
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0 ||
13024
            (persist && virDomainSaveConfig(cfg->configDir, vm->newDef) < 0))
13025 13026
            ret = -1;
    }
13027
    virObjectUnref(cfg);
13028 13029 13030 13031 13032 13033 13034

    return ret;
}


static int
qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
13035
                                       virQEMUDriverPtr driver,
13036 13037 13038 13039 13040 13041 13042 13043 13044 13045
                                       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;
13046
    bool memory_unlink = false;
13047
    bool atomic = !!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC);
13048
    bool transaction = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION);
13049
    int thaw = 0; /* 1 if freeze succeeded, -1 if freeze failed */
13050
    bool pmsuspended = false;
13051 13052
    virQEMUDriverConfigPtr cfg = NULL;
    int compressed = QEMU_SAVE_FORMAT_RAW;
13053

P
Peter Krempa 已提交
13054
    if (qemuDomainObjBeginAsyncJob(driver, vm, QEMU_ASYNC_JOB_SNAPSHOT) < 0)
13055 13056
        goto cleanup;

13057 13058 13059 13060 13061
    /* 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) {
13062
        if (qemuDomainSnapshotFSFreeze(vm) < 0) {
13063 13064 13065 13066 13067 13068 13069 13070
            /* helper reported the error */
            thaw = -1;
            goto endjob;
        } else {
            thaw = 1;
        }
    }

13071 13072 13073 13074 13075
    /* 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) {
13076 13077 13078 13079 13080 13081 13082 13083 13084 13085 13086 13087 13088 13089 13090 13091 13092 13093 13094 13095 13096 13097 13098 13099 13100 13101 13102 13103 13104
        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) {
13105
        /* check if migration is possible */
13106
        if (!qemuMigrationIsAllowed(driver, vm, vm->def, false, false))
13107 13108
            goto endjob;

13109 13110 13111 13112 13113
        /* 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));

13114 13115 13116 13117 13118 13119 13120 13121 13122 13123 13124 13125 13126 13127 13128 13129 13130
        cfg = virQEMUDriverGetConfig(driver);
        if (cfg->snapshotImageFormat) {
            compressed = qemuSaveCompressionTypeFromString(cfg->snapshotImageFormat);
            if (compressed < 0) {
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("Invalid snapshot image format specified "
                                 "in configuration file"));
                goto cleanup;
            }
            if (!qemuCompressProgramAvailable(compressed)) {
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("Compression program for image format "
                                 "in configuration file isn't available"));
                goto cleanup;
            }
        }

13131
        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)))
13132 13133 13134
            goto endjob;

        if ((ret = qemuDomainSaveMemory(driver, vm, snap->def->file,
13135
                                        xml, compressed, resume, 0,
13136 13137 13138
                                        QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
            goto endjob;

13139 13140 13141
        /* the memory image was created, remove it on errors */
        memory_unlink = true;

13142 13143 13144 13145 13146 13147 13148 13149 13150 13151 13152 13153 13154 13155 13156 13157
        /* 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 */
13158
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
13159
        virObjectEventPtr event;
13160

13161
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
13162
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
13163
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
13164 13165 13166
        virDomainAuditStop(vm, "from-snapshot");
        /* We already filtered the _HALT flag for persistent domains
         * only, so this end job never drops the last reference.  */
13167
        ignore_value(qemuDomainObjEndAsyncJob(driver, vm));
13168
        resume = false;
E
Eric Blake 已提交
13169
        thaw = 0;
13170 13171 13172
        vm = NULL;
        if (event)
            qemuDomainEventQueue(driver, event);
13173 13174 13175 13176
    } 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.  */
13177
        virObjectEventPtr event;
13178 13179 13180

        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
                             VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
13181
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
13182 13183 13184
                                         VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
        if (event)
            qemuDomainEventQueue(driver, event);
13185 13186
    }

13187
    ret = 0;
13188 13189

endjob:
13190 13191 13192
    if (resume && vm && virDomainObjIsActive(vm) &&
        qemuProcessStartCPUs(driver, vm, conn,
                             VIR_DOMAIN_RUNNING_UNPAUSED,
13193
                             QEMU_ASYNC_JOB_SNAPSHOT) < 0) {
13194
        virObjectEventPtr event = NULL;
13195
        event = virDomainEventLifecycleNewFromObj(vm,
13196 13197 13198 13199 13200 13201 13202 13203
                                         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"));
        }
13204

13205 13206
        ret = -1;
        goto cleanup;
13207
    }
E
Eric Blake 已提交
13208
    if (vm && thaw != 0 &&
13209
        qemuDomainSnapshotFSThaw(vm, thaw > 0) < 0) {
E
Eric Blake 已提交
13210 13211 13212 13213
        /* helper reported the error, if it was needed */
        if (thaw > 0)
            ret = -1;
    }
13214
    if (vm && !qemuDomainObjEndAsyncJob(driver, vm)) {
13215
        /* Only possible if a transient vm quit while our locks were down,
13216 13217
         * in which case we don't want to save snapshot metadata.
         */
13218 13219
        *vmptr = NULL;
        ret = -1;
13220 13221
    }

13222 13223
cleanup:
    VIR_FREE(xml);
13224
    virObjectUnref(cfg);
13225 13226
    if (memory_unlink && ret < 0)
        unlink(snap->def->file);
13227

13228 13229 13230
    return ret;
}

13231

13232 13233 13234 13235
static virDomainSnapshotPtr
qemuDomainSnapshotCreateXML(virDomainPtr domain,
                            const char *xmlDesc,
                            unsigned int flags)
C
Chris Lalancette 已提交
13236
{
13237
    virConnectPtr conn = domain->conn;
13238
    virQEMUDriverPtr driver = domain->conn->privateData;
C
Chris Lalancette 已提交
13239
    virDomainObjPtr vm = NULL;
13240
    char *xml = NULL;
C
Chris Lalancette 已提交
13241 13242
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;
13243
    virDomainSnapshotDefPtr def = NULL;
13244
    bool update_current = true;
13245
    bool redefine = flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE;
13246
    unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
13247
    virDomainSnapshotObjPtr other = NULL;
13248 13249
    int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
    int align_match = true;
13250
    virQEMUDriverConfigPtr cfg = NULL;
13251
    virCapsPtr caps = NULL;
C
Chris Lalancette 已提交
13252

13253 13254
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
13255
                  VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
13256
                  VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
13257
                  VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
13258
                  VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT |
13259
                  VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
13260 13261
                  VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
                  VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, NULL);
13262 13263 13264

    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) &&
        !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)) {
13265 13266
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("quiesce requires disk-only"));
13267 13268
        return NULL;
    }
13269

13270
    if ((redefine && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) ||
13271 13272
        (flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA))
        update_current = false;
13273
    if (redefine)
13274
        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE;
13275

13276
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
13277 13278
        goto cleanup;

13279 13280
    cfg = virQEMUDriverGetConfig(driver);

13281
    if (virDomainSnapshotCreateXMLEnsureACL(domain->conn, vm->def, flags) < 0)
13282 13283
        goto cleanup;

13284 13285 13286
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

13287
    if (qemuProcessAutoDestroyActive(driver, vm)) {
13288 13289
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is marked for auto destroy"));
13290 13291
        goto cleanup;
    }
E
Eric Blake 已提交
13292 13293 13294 13295 13296 13297
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
        goto cleanup;
    }

13298
    if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
13299 13300
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot halt after transient domain snapshot"));
13301 13302
        goto cleanup;
    }
13303 13304 13305
    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) ||
        !virDomainObjIsActive(vm))
        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_OFFLINE;
13306

13307
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, caps, driver->xmlopt,
13308 13309
                                                QEMU_EXPECTED_VIRT_TYPES,
                                                parse_flags)))
C
Chris Lalancette 已提交
13310 13311
        goto cleanup;

13312 13313 13314 13315 13316 13317 13318 13319 13320 13321 13322 13323 13324 13325 13326 13327 13328 13329
    /* 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;
        }
13330 13331
    }

13332 13333 13334 13335
    /* 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 ||
13336
         redefine)) {
13337 13338 13339 13340 13341 13342
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("live snapshot creation is supported only "
                         "with external checkpoints"));
        goto cleanup;
    }

13343
    if (redefine) {
13344 13345
        if (!virDomainSnapshotRedefinePrep(domain, vm, &def, &snap,
                                           &update_current, flags) < 0)
13346 13347 13348 13349
            goto cleanup;
    } else {
        /* Easiest way to clone inactive portion of vm->def is via
         * conversion in and back out of xml.  */
13350
        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)) ||
13351
            !(def->dom = virDomainDefParseString(xml, caps, driver->xmlopt,
13352 13353 13354 13355
                                                 QEMU_EXPECTED_VIRT_TYPES,
                                                 VIR_DOMAIN_XML_INACTIVE)))
            goto cleanup;

13356
        if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
13357 13358
            align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
            align_match = false;
13359 13360 13361 13362
            if (virDomainObjIsActive(vm))
                def->state = VIR_DOMAIN_DISK_SNAPSHOT;
            else
                def->state = VIR_DOMAIN_SHUTOFF;
13363
            def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
13364 13365 13366 13367
        } else if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
            def->state = virDomainObjGetState(vm, NULL);
            align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
            align_match = false;
13368 13369
        } else {
            def->state = virDomainObjGetState(vm, NULL);
13370 13371 13372
            def->memory = (def->state == VIR_DOMAIN_SHUTOFF ?
                           VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
                           VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL);
13373
        }
E
Eric Blake 已提交
13374 13375
        if (virDomainSnapshotAlignDisks(def, align_location,
                                        align_match) < 0 ||
13376
            qemuDomainSnapshotPrepare(conn, vm, def, &flags) < 0)
E
Eric Blake 已提交
13377
            goto cleanup;
13378 13379
    }

13380 13381 13382 13383 13384 13385
    if (!snap) {
        if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
            goto cleanup;

        def = NULL;
    }
C
Chris Lalancette 已提交
13386

13387 13388
    if (update_current)
        snap->def->current = true;
13389
    if (vm->current_snapshot) {
13390
        if (!redefine &&
13391
            VIR_STRDUP(snap->def->parent, vm->current_snapshot->def->name) < 0)
13392 13393
                goto cleanup;
        if (update_current) {
13394 13395
            vm->current_snapshot->def->current = false;
            if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
13396
                                                cfg->snapshotDir) < 0)
13397 13398 13399
                goto cleanup;
            vm->current_snapshot = NULL;
        }
13400
    }
13401

C
Chris Lalancette 已提交
13402
    /* actually do the snapshot */
13403
    if (redefine) {
13404
        /* XXX Should we validate that the redefined snapshot even
13405 13406
         * makes sense, such as checking that qemu-img recognizes the
         * snapshot name in at least one of the domain's disks?  */
13407 13408 13409 13410 13411 13412 13413 13414 13415 13416 13417 13418 13419
    } 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 已提交
13420
    } else {
13421 13422 13423 13424 13425 13426 13427 13428 13429 13430 13431 13432 13433
        /* 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 已提交
13434 13435
    }

13436
    /* If we fail after this point, there's not a whole lot we can
C
Chris Lalancette 已提交
13437 13438 13439 13440 13441 13442
     * 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:
13443
    if (vm) {
13444
        if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
13445
            if (qemuDomainSnapshotWriteMetadata(vm, snap,
13446
                                                cfg->snapshotDir) < 0) {
13447 13448 13449 13450 13451 13452 13453 13454
                /* 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);
13455 13456 13457
            } else {
                if (update_current)
                    vm->current_snapshot = snap;
13458
                other = virDomainSnapshotFindByName(vm->snapshots,
13459 13460 13461 13462 13463
                                                    snap->def->parent);
                snap->parent = other;
                other->nchildren++;
                snap->sibling = other->first_child;
                other->first_child = snap;
13464
            }
13465
        } else if (snap) {
13466
            virDomainSnapshotObjListRemove(vm->snapshots, snap);
13467
        }
13468
        virObjectUnlock(vm);
13469 13470
    }
    virDomainSnapshotDefFree(def);
13471
    VIR_FREE(xml);
13472
    virObjectUnref(caps);
13473
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
13474 13475 13476 13477 13478
    return snapshot;
}

static int qemuDomainSnapshotListNames(virDomainPtr domain, char **names,
                                       int nameslen,
13479
                                       unsigned int flags)
C
Chris Lalancette 已提交
13480 13481 13482 13483
{
    virDomainObjPtr vm = NULL;
    int n = -1;

13484
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
13485
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
13486

13487
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
13488 13489
        goto cleanup;

13490 13491 13492
    if (virDomainSnapshotListNamesEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

13493
    n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen,
13494
                                         flags);
C
Chris Lalancette 已提交
13495 13496 13497

cleanup:
    if (vm)
13498
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
13499 13500 13501 13502
    return n;
}

static int qemuDomainSnapshotNum(virDomainPtr domain,
13503
                                 unsigned int flags)
C
Chris Lalancette 已提交
13504 13505 13506 13507
{
    virDomainObjPtr vm = NULL;
    int n = -1;

13508
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
13509
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
13510

13511
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
13512 13513
        goto cleanup;

13514 13515 13516
    if (virDomainSnapshotNumEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

13517
    n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags);
C
Chris Lalancette 已提交
13518 13519 13520

cleanup:
    if (vm)
13521
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
13522 13523 13524
    return n;
}

13525 13526 13527 13528 13529 13530 13531 13532 13533 13534
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);

13535
    if (!(vm = qemuDomObjFromDomain(domain)))
13536 13537
        goto cleanup;

13538 13539 13540
    if (virDomainListAllSnapshotsEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

13541
    n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags);
13542 13543 13544

cleanup:
    if (vm)
13545
        virObjectUnlock(vm);
13546 13547 13548
    return n;
}

13549 13550 13551 13552 13553 13554 13555 13556 13557 13558 13559
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 |
13560
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
13561

13562
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
13563 13564
        goto cleanup;

13565 13566 13567
    if (virDomainSnapshotListChildrenNamesEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13568
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
13569 13570
        goto cleanup;

13571
    n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen,
13572
                                         flags);
13573 13574 13575

cleanup:
    if (vm)
13576
        virObjectUnlock(vm);
13577 13578 13579 13580 13581 13582 13583 13584 13585 13586 13587 13588
    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 |
13589
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
13590

13591
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
13592 13593
        goto cleanup;

13594 13595 13596
    if (virDomainSnapshotNumChildrenEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13597
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
13598 13599
        goto cleanup;

13600
    n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags);
13601 13602 13603

cleanup:
    if (vm)
13604
        virObjectUnlock(vm);
13605 13606 13607
    return n;
}

13608 13609 13610 13611 13612 13613 13614 13615 13616 13617 13618 13619
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);

13620
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
13621 13622
        goto cleanup;

13623 13624 13625
    if (virDomainSnapshotListAllChildrenEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13626
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
13627 13628
        goto cleanup;

13629
    n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps,
13630 13631 13632 13633
                               flags);

cleanup:
    if (vm)
13634
        virObjectUnlock(vm);
13635 13636 13637
    return n;
}

C
Chris Lalancette 已提交
13638 13639
static virDomainSnapshotPtr qemuDomainSnapshotLookupByName(virDomainPtr domain,
                                                           const char *name,
13640
                                                           unsigned int flags)
C
Chris Lalancette 已提交
13641 13642 13643 13644 13645
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

13646 13647
    virCheckFlags(0, NULL);

13648
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
13649 13650
        goto cleanup;

13651 13652 13653
    if (virDomainSnapshotLookupByNameEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

13654
    if (!(snap = qemuSnapObjFromName(vm, name)))
C
Chris Lalancette 已提交
13655 13656 13657 13658 13659 13660
        goto cleanup;

    snapshot = virGetDomainSnapshot(domain, snap->def->name);

cleanup:
    if (vm)
13661
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
13662 13663 13664 13665
    return snapshot;
}

static int qemuDomainHasCurrentSnapshot(virDomainPtr domain,
13666
                                        unsigned int flags)
C
Chris Lalancette 已提交
13667 13668 13669 13670
{
    virDomainObjPtr vm;
    int ret = -1;

13671 13672
    virCheckFlags(0, -1);

13673
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
13674 13675
        goto cleanup;

13676 13677 13678
    if (virDomainHasCurrentSnapshotEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

C
Chris Lalancette 已提交
13679 13680 13681 13682
    ret = (vm->current_snapshot != NULL);

cleanup:
    if (vm)
13683
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
13684 13685 13686
    return ret;
}

13687 13688 13689 13690 13691 13692 13693 13694 13695 13696
static virDomainSnapshotPtr
qemuDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr parent = NULL;

    virCheckFlags(0, NULL);

13697
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
13698 13699
        goto cleanup;

13700 13701 13702
    if (virDomainSnapshotGetParentEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13703
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
13704 13705 13706
        goto cleanup;

    if (!snap->def->parent) {
13707 13708 13709
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snap->def->name);
13710 13711 13712 13713 13714 13715 13716
        goto cleanup;
    }

    parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);

cleanup:
    if (vm)
13717
        virObjectUnlock(vm);
13718 13719 13720
    return parent;
}

C
Chris Lalancette 已提交
13721
static virDomainSnapshotPtr qemuDomainSnapshotCurrent(virDomainPtr domain,
13722
                                                      unsigned int flags)
C
Chris Lalancette 已提交
13723 13724 13725 13726
{
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

13727 13728
    virCheckFlags(0, NULL);

13729
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
13730 13731
        goto cleanup;

13732 13733 13734
    if (virDomainSnapshotCurrentEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

C
Chris Lalancette 已提交
13735
    if (!vm->current_snapshot) {
13736 13737
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
                       _("the domain does not have a current snapshot"));
C
Chris Lalancette 已提交
13738 13739 13740 13741 13742 13743 13744
        goto cleanup;
    }

    snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);

cleanup:
    if (vm)
13745
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
13746 13747 13748
    return snapshot;
}

13749 13750
static char *qemuDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                                          unsigned int flags)
C
Chris Lalancette 已提交
13751 13752 13753 13754 13755 13756
{
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

13757
    virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
13758

13759
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
C
Chris Lalancette 已提交
13760 13761
        goto cleanup;

13762 13763 13764
    if (virDomainSnapshotGetXMLDescEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13765
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
13766
        goto cleanup;
13767 13768

    virUUIDFormat(snapshot->domain->uuid, uuidstr);
C
Chris Lalancette 已提交
13769

13770
    xml = virDomainSnapshotDefFormat(uuidstr, snap->def, flags, 0);
C
Chris Lalancette 已提交
13771 13772 13773

cleanup:
    if (vm)
13774
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
13775 13776 13777
    return xml;
}

13778 13779 13780 13781 13782 13783 13784 13785 13786 13787
static int
qemuDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

13788
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
13789 13790
        goto cleanup;

13791 13792 13793
    if (virDomainSnapshotIsCurrentEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13794
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
13795 13796 13797 13798 13799 13800 13801
        goto cleanup;

    ret = (vm->current_snapshot &&
           STREQ(snapshot->name, vm->current_snapshot->def->name));

cleanup:
    if (vm)
13802
        virObjectUnlock(vm);
13803 13804 13805 13806 13807 13808 13809 13810 13811 13812 13813 13814 13815 13816
    return ret;
}


static int
qemuDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
                              unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

13817
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
13818 13819
        goto cleanup;

13820 13821 13822
    if (virDomainSnapshotHasMetadataEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13823
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
13824 13825 13826 13827 13828 13829 13830 13831 13832
        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)
13833
        virObjectUnlock(vm);
13834 13835 13836
    return ret;
}

13837 13838
/* The domain is expected to be locked and inactive. */
static int
13839
qemuDomainSnapshotRevertInactive(virQEMUDriverPtr driver,
E
Eric Blake 已提交
13840
                                 virDomainObjPtr vm,
13841 13842 13843
                                 virDomainSnapshotObjPtr snap)
{
    /* Try all disks, but report failure if we skipped any.  */
E
Eric Blake 已提交
13844
    int ret = qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-a", true);
13845 13846 13847
    return ret > 0 ? -1 : ret;
}

C
Chris Lalancette 已提交
13848
static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
13849
                                      unsigned int flags)
C
Chris Lalancette 已提交
13850
{
13851
    virQEMUDriverPtr driver = snapshot->domain->conn->privateData;
C
Chris Lalancette 已提交
13852 13853 13854
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
13855 13856
    virObjectEventPtr event = NULL;
    virObjectEventPtr event2 = NULL;
13857
    int detail;
C
Chris Lalancette 已提交
13858 13859
    qemuDomainObjPrivatePtr priv;
    int rc;
13860
    virDomainDefPtr config = NULL;
13861
    virQEMUDriverConfigPtr cfg = NULL;
13862
    virCapsPtr caps = NULL;
C
Chris Lalancette 已提交
13863

13864
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
13865 13866
                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
                  VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
13867

13868 13869 13870 13871 13872 13873 13874 13875 13876 13877
    /* 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
13878 13879
     * Also, several transitions occur even if we fail partway through,
     * and use of FORCE can cause multiple transitions.
13880 13881
     */

13882 13883
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
        return -1;
13884 13885 13886

    cfg = virQEMUDriverGetConfig(driver);

13887 13888 13889
    if (virDomainRevertToSnapshotEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13890 13891 13892
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

E
Eric Blake 已提交
13893 13894 13895 13896 13897
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
        goto cleanup;
    }
C
Chris Lalancette 已提交
13898

13899
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
13900 13901
        goto cleanup;

13902 13903 13904 13905 13906
    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) {
13907 13908 13909
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("transient domain needs to request run or pause "
                         "to revert to inactive snapshot"));
13910 13911
        goto cleanup;
    }
13912
    if (snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT) {
13913 13914 13915
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("revert to external disk snapshot not supported "
                         "yet"));
13916 13917
        goto cleanup;
    }
13918 13919
    if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
        if (!snap->def->dom) {
13920 13921 13922
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
                           _("snapshot '%s' lacks domain '%s' rollback info"),
                           snap->def->name, vm->def->name);
13923 13924 13925 13926 13927 13928 13929
            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))) {
13930 13931
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                           _("must respawn qemu to start inactive snapshot"));
13932 13933 13934 13935
            goto cleanup;
        }
    }

13936

13937 13938 13939
    if (vm->current_snapshot) {
        vm->current_snapshot->def->current = false;
        if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
13940
                                            cfg->snapshotDir) < 0)
13941 13942 13943 13944 13945 13946
            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?  */
    }

13947
    /* Prepare to copy the snapshot inactive xml as the config of this
13948
     * domain.
13949 13950 13951
     *
     * XXX Should domain snapshots track live xml rather
     * than inactive xml?  */
13952
    snap->def->current = true;
13953
    if (snap->def->dom) {
13954
        config = virDomainDefCopy(snap->def->dom, caps, driver->xmlopt, true);
13955 13956 13957
        if (!config)
            goto cleanup;
    }
C
Chris Lalancette 已提交
13958

13959
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
C
Chris Lalancette 已提交
13960 13961 13962 13963
        goto cleanup;

    if (snap->def->state == VIR_DOMAIN_RUNNING
        || snap->def->state == VIR_DOMAIN_PAUSED) {
13964 13965 13966 13967 13968 13969 13970 13971 13972
        /* 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 已提交
13973
        if (virDomainObjIsActive(vm)) {
13974
            /* Transitions 5, 6, 8, 9 */
13975 13976
            /* Check for ABI compatibility. We need to do this check against
             * the migratable XML or it will always fail otherwise */
13977
            if (config && !qemuDomainDefCheckABIStability(driver, vm->def, config)) {
13978 13979 13980 13981 13982
                virErrorPtr err = virGetLastError();

                if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
                    /* Re-spawn error using correct category. */
                    if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
13983 13984
                        virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                                       err->str2);
13985 13986 13987
                    goto endjob;
                }
                virResetError(err);
13988 13989
                qemuProcessStop(driver, vm,
                                VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
13990 13991
                virDomainAuditStop(vm, "from-snapshot");
                detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
13992
                event = virDomainEventLifecycleNewFromObj(vm,
13993 13994 13995 13996 13997
                                                 VIR_DOMAIN_EVENT_STOPPED,
                                                 detail);
                if (event)
                    qemuDomainEventQueue(driver, event);
                goto load;
13998 13999
            }

C
Chris Lalancette 已提交
14000
            priv = vm->privateData;
14001 14002 14003 14004 14005 14006 14007 14008 14009 14010 14011
            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;
14012
                event = virDomainEventLifecycleNewFromObj(vm,
14013 14014 14015
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 detail);
                if (!virDomainObjIsActive(vm)) {
14016 14017
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("guest unexpectedly quit"));
14018 14019 14020
                    goto endjob;
                }
            }
14021
            qemuDomainObjEnterMonitor(driver, vm);
C
Chris Lalancette 已提交
14022
            rc = qemuMonitorLoadSnapshot(priv->mon, snap->def->name);
14023
            qemuDomainObjExitMonitor(driver, vm);
14024 14025 14026
            if (rc < 0) {
                /* XXX resume domain if it was running before the
                 * failed loadvm attempt? */
14027
                goto endjob;
14028
            }
14029
            if (config)
14030
                virDomainObjAssignDef(vm, config, false, NULL);
E
Eric Blake 已提交
14031
        } else {
14032
            /* Transitions 2, 3 */
14033
        load:
14034
            was_stopped = true;
14035
            if (config)
14036
                virDomainObjAssignDef(vm, config, false, NULL);
14037

14038 14039 14040 14041
            rc = qemuProcessStart(snapshot->domain->conn,
                                  driver, vm, NULL, -1, NULL, snap,
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  VIR_QEMU_PROCESS_START_PAUSED);
14042
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
14043
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
14044
            event = virDomainEventLifecycleNewFromObj(vm,
14045 14046
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
C
Chris Lalancette 已提交
14047
            if (rc < 0)
14048
                goto endjob;
C
Chris Lalancette 已提交
14049 14050
        }

14051
        /* Touch up domain state.  */
14052 14053 14054
        if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
            (snap->def->state == VIR_DOMAIN_PAUSED ||
             (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
14055 14056 14057 14058 14059 14060
            /* 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;
14061
                event2 = virDomainEventLifecycleNewFromObj(vm,
14062 14063 14064 14065 14066 14067
                                                  VIR_DOMAIN_EVENT_SUSPENDED,
                                                  detail);
            } /* else transition 6 and 9 use event as-is */
        } else {
            /* Transitions 2, 5, 8 */
            if (!virDomainObjIsActive(vm)) {
14068 14069
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("guest unexpectedly quit"));
14070 14071 14072 14073 14074
                goto endjob;
            }
            rc = qemuProcessStartCPUs(driver, vm, snapshot->domain->conn,
                                      VIR_DOMAIN_RUNNING_FROM_SNAPSHOT,
                                      QEMU_ASYNC_JOB_NONE);
H
Hu Tao 已提交
14075
            if (rc < 0)
14076
                goto endjob;
C
Cédric Bosdonnat 已提交
14077
            virObjectUnref(event);
14078 14079 14080 14081
            event = NULL;
            if (was_stopped) {
                /* Transition 2 */
                detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
14082
                event = virDomainEventLifecycleNewFromObj(vm,
14083 14084 14085 14086 14087
                                                 VIR_DOMAIN_EVENT_STARTED,
                                                 detail);
            } else if (was_running) {
                /* Transition 8 */
                detail = VIR_DOMAIN_EVENT_RESUMED;
14088
                event = virDomainEventLifecycleNewFromObj(vm,
14089 14090 14091
                                                 VIR_DOMAIN_EVENT_RESUMED,
                                                 detail);
            }
C
Chris Lalancette 已提交
14092
        }
E
Eric Blake 已提交
14093
    } else {
14094
        /* Transitions 1, 4, 7 */
14095 14096 14097
        /* 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 已提交
14098 14099 14100
         */

        if (virDomainObjIsActive(vm)) {
14101
            /* Transitions 4, 7 */
14102
            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
14103
            virDomainAuditStop(vm, "from-snapshot");
14104
            detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
14105
            event = virDomainEventLifecycleNewFromObj(vm,
C
Chris Lalancette 已提交
14106
                                             VIR_DOMAIN_EVENT_STOPPED,
14107
                                             detail);
14108 14109
        }

E
Eric Blake 已提交
14110
        if (qemuDomainSnapshotRevertInactive(driver, vm, snap) < 0) {
14111
            if (!vm->persistent) {
E
Eric Blake 已提交
14112
                if (qemuDomainObjEndJob(driver, vm))
14113
                    qemuDomainRemoveInactive(driver, vm);
14114
                vm = NULL;
14115
                goto cleanup;
14116
            }
14117
            goto endjob;
C
Chris Lalancette 已提交
14118
        }
14119
        if (config)
14120
            virDomainObjAssignDef(vm, config, false, NULL);
14121

14122 14123 14124 14125
        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;
14126 14127 14128
            unsigned int start_flags = 0;

            start_flags |= paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
14129 14130 14131

            if (event)
                qemuDomainEventQueue(driver, event);
14132 14133 14134 14135
            rc = qemuProcessStart(snapshot->domain->conn,
                                  driver, vm, NULL, -1, NULL, NULL,
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  start_flags);
14136 14137 14138
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
            if (rc < 0) {
                if (!vm->persistent) {
E
Eric Blake 已提交
14139
                    if (qemuDomainObjEndJob(driver, vm))
14140
                        qemuDomainRemoveInactive(driver, vm);
14141 14142 14143 14144 14145 14146
                    vm = NULL;
                    goto cleanup;
                }
                goto endjob;
            }
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
14147
            event = virDomainEventLifecycleNewFromObj(vm,
14148 14149 14150 14151
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
            if (paused) {
                detail = VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT;
14152
                event2 = virDomainEventLifecycleNewFromObj(vm,
14153 14154 14155 14156
                                                  VIR_DOMAIN_EVENT_SUSPENDED,
                                                  detail);
            }
        }
C
Chris Lalancette 已提交
14157 14158 14159 14160
    }

    ret = 0;

14161
endjob:
E
Eric Blake 已提交
14162
    if (vm && !qemuDomainObjEndJob(driver, vm))
C
Chris Lalancette 已提交
14163 14164
        vm = NULL;

14165
cleanup:
14166 14167
    if (vm && ret == 0) {
        if (qemuDomainSnapshotWriteMetadata(vm, snap,
14168
                                            cfg->snapshotDir) < 0)
14169 14170 14171 14172 14173 14174
            ret = -1;
        else
            vm->current_snapshot = snap;
    } else if (snap) {
        snap->def->current = false;
    }
14175
    if (event) {
C
Chris Lalancette 已提交
14176
        qemuDomainEventQueue(driver, event);
14177 14178 14179
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
C
Chris Lalancette 已提交
14180
    if (vm)
14181
        virObjectUnlock(vm);
14182
    virObjectUnref(caps);
14183
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
14184 14185 14186 14187

    return ret;
}

14188 14189 14190 14191

typedef struct _virQEMUSnapReparent virQEMUSnapReparent;
typedef virQEMUSnapReparent *virQEMUSnapReparentPtr;
struct _virQEMUSnapReparent {
14192
    virQEMUDriverConfigPtr cfg;
14193
    virDomainSnapshotObjPtr parent;
14194 14195
    virDomainObjPtr vm;
    int err;
14196
    virDomainSnapshotObjPtr last;
14197 14198 14199 14200
};

static void
qemuDomainSnapshotReparentChildren(void *payload,
14201
                                   const void *name ATTRIBUTE_UNUSED,
14202 14203 14204
                                   void *data)
{
    virDomainSnapshotObjPtr snap = payload;
14205
    virQEMUSnapReparentPtr rep = data;
14206 14207 14208 14209 14210

    if (rep->err < 0) {
        return;
    }

14211
    VIR_FREE(snap->def->parent);
14212
    snap->parent = rep->parent;
14213

14214 14215 14216 14217
    if (rep->parent->def &&
        VIR_STRDUP(snap->def->parent, rep->parent->def->name) < 0) {
        rep->err = -1;
        return;
14218
    }
14219

14220 14221 14222
    if (!snap->sibling)
        rep->last = snap;

14223
    rep->err = qemuDomainSnapshotWriteMetadata(rep->vm, snap,
14224
                                               rep->cfg->snapshotDir);
14225 14226
}

14227

C
Chris Lalancette 已提交
14228 14229 14230
static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                                    unsigned int flags)
{
14231
    virQEMUDriverPtr driver = snapshot->domain->conn->privateData;
C
Chris Lalancette 已提交
14232 14233 14234
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
14235 14236
    virQEMUSnapRemove rem;
    virQEMUSnapReparent rep;
14237
    bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);
14238
    int external = 0;
14239
    virQEMUDriverConfigPtr cfg = NULL;
C
Chris Lalancette 已提交
14240

14241
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
14242 14243
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY |
                  VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
14244

14245 14246
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
        return -1;
C
Chris Lalancette 已提交
14247

14248
    cfg = virQEMUDriverGetConfig(driver);
14249 14250 14251 14252

    if (virDomainSnapshotDeleteEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

14253
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
14254 14255
        goto cleanup;

14256
    if (!metadata_only) {
14257
        if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) &&
14258
            virDomainSnapshotIsExternal(snap))
14259 14260
            external++;
        if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
E
Eric Blake 已提交
14261
            virDomainSnapshotForEachDescendant(snap,
14262 14263 14264
                                               qemuDomainSnapshotCountExternal,
                                               &external);
        if (external) {
14265 14266 14267
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("deletion of %d external disk snapshots not "
                             "supported yet"), external);
14268 14269 14270 14271
            goto cleanup;
        }
    }

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

14275 14276
    if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                 VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
C
Chris Lalancette 已提交
14277 14278
        rem.driver = driver;
        rem.vm = vm;
14279
        rem.metadata_only = metadata_only;
C
Chris Lalancette 已提交
14280
        rem.err = 0;
14281
        rem.current = false;
E
Eric Blake 已提交
14282
        virDomainSnapshotForEachDescendant(snap,
E
Eric Blake 已提交
14283
                                           qemuDomainSnapshotDiscardAll,
14284
                                           &rem);
C
Chris Lalancette 已提交
14285
        if (rem.err < 0)
14286
            goto endjob;
14287 14288 14289 14290
        if (rem.current) {
            if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
                snap->def->current = true;
                if (qemuDomainSnapshotWriteMetadata(vm, snap,
14291
                                                    cfg->snapshotDir) < 0) {
14292 14293 14294
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("failed to set snapshot '%s' as current"),
                                   snap->def->name);
14295 14296 14297 14298
                    snap->def->current = false;
                    goto endjob;
                }
            }
14299
            vm->current_snapshot = snap;
14300
        }
14301
    } else if (snap->nchildren) {
14302
        rep.cfg = cfg;
14303
        rep.parent = snap->parent;
14304 14305
        rep.vm = vm;
        rep.err = 0;
14306
        rep.last = NULL;
E
Eric Blake 已提交
14307
        virDomainSnapshotForEachChild(snap,
14308 14309
                                      qemuDomainSnapshotReparentChildren,
                                      &rep);
14310 14311
        if (rep.err < 0)
            goto endjob;
14312
        /* Can't modify siblings during ForEachChild, so do it now.  */
14313 14314 14315
        snap->parent->nchildren += snap->nchildren;
        rep.last->sibling = snap->parent->first_child;
        snap->parent->first_child = snap->first_child;
C
Chris Lalancette 已提交
14316 14317
    }

14318 14319 14320
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
        snap->nchildren = 0;
        snap->first_child = NULL;
14321
        ret = 0;
14322
    } else {
14323
        virDomainSnapshotDropParent(snap);
14324
        ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only);
14325
    }
C
Chris Lalancette 已提交
14326

14327
endjob:
E
Eric Blake 已提交
14328
    if (!qemuDomainObjEndJob(driver, vm))
14329 14330
        vm = NULL;

C
Chris Lalancette 已提交
14331 14332
cleanup:
    if (vm)
14333
        virObjectUnlock(vm);
14334
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
14335 14336
    return ret;
}
14337

14338 14339
static int qemuDomainQemuMonitorCommand(virDomainPtr domain, const char *cmd,
                                        char **result, unsigned int flags)
14340
{
14341
    virQEMUDriverPtr driver = domain->conn->privateData;
14342 14343 14344
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
14345
    bool hmp;
14346

14347
    virCheckFlags(VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP, -1);
14348

14349
    if (!(vm = qemuDomObjFromDomain(domain)))
14350 14351
        goto cleanup;

14352 14353 14354
    if (virDomainQemuMonitorCommandEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

14355
    if (!virDomainObjIsActive(vm)) {
14356 14357
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
14358
        goto cleanup;
14359
    }
14360

14361
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
14362 14363 14364
        goto cleanup;

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

14370 14371
    priv = vm->privateData;

14372
    qemuDomainObjTaint(driver, vm, VIR_DOMAIN_TAINT_CUSTOM_MONITOR, -1);
14373

14374 14375
    hmp = !!(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP);

14376
    qemuDomainObjEnterMonitor(driver, vm);
14377
    ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result, hmp);
14378
    qemuDomainObjExitMonitor(driver, vm);
14379 14380

endjob:
E
Eric Blake 已提交
14381
    if (!qemuDomainObjEndJob(driver, vm)) {
14382 14383 14384 14385 14386
        vm = NULL;
    }

cleanup:
    if (vm)
14387
        virObjectUnlock(vm);
14388 14389 14390
    return ret;
}

14391

14392 14393 14394
static virDomainPtr qemuDomainQemuAttach(virConnectPtr conn,
                                         unsigned int pid_value,
                                         unsigned int flags)
14395
{
14396
    virQEMUDriverPtr driver = conn->privateData;
14397 14398 14399 14400 14401
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainPtr dom = NULL;
    virDomainChrSourceDefPtr monConfig = NULL;
    bool monJSON = false;
14402
    pid_t pid = pid_value;
14403
    char *pidfile = NULL;
14404
    virQEMUCapsPtr qemuCaps = NULL;
14405
    virCapsPtr caps = NULL;
14406 14407 14408

    virCheckFlags(0, NULL);

14409 14410 14411
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

14412
    if (!(def = qemuParseCommandLinePid(caps, driver->xmlopt, pid,
14413 14414 14415
                                        &pidfile, &monConfig, &monJSON)))
        goto cleanup;

14416 14417 14418
    if (virDomainQemuAttachEnsureACL(conn, def) < 0)
        goto cleanup;

14419
    if (!monConfig) {
14420 14421
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("No monitor connection for pid %u"), pid_value);
14422 14423 14424
        goto cleanup;
    }
    if (monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
14425 14426 14427 14428 14429
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Cannot connect to monitor connection of type '%s' "
                         "for pid %u"),
                       virDomainChrTypeToString(monConfig->type),
                       pid_value);
14430 14431 14432 14433
        goto cleanup;
    }

    if (!(def->name) &&
14434
        virAsprintf(&def->name, "attach-pid-%u", pid_value) < 0)
14435 14436
        goto cleanup;

14437
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
14438 14439
        goto cleanup;

14440
    if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
14441 14442
        goto cleanup;

14443
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
14444 14445
        goto cleanup;

14446
    if (!(vm = virDomainObjListAdd(driver->domains, def,
14447
                                   driver->xmlopt,
14448 14449 14450
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
14451 14452 14453 14454
        goto cleanup;

    def = NULL;

E
Eric Blake 已提交
14455 14456 14457
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) {
        qemuDomainRemoveInactive(driver, vm);
        vm = NULL;
14458
        goto cleanup;
E
Eric Blake 已提交
14459
    }
14460 14461 14462

    if (qemuProcessAttach(conn, driver, vm, pid,
                          pidfile, monConfig, monJSON) < 0) {
E
Eric Blake 已提交
14463
        if (qemuDomainObjEndJob(driver, vm))
E
Eric Blake 已提交
14464 14465
            qemuDomainRemoveInactive(driver, vm);
        vm = NULL;
14466
        monConfig = NULL;
E
Eric Blake 已提交
14467
        goto cleanup;
14468 14469 14470 14471 14472
    }

    monConfig = NULL;

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
E
Eric Blake 已提交
14473 14474
    if (dom)
        dom->id = vm->def->id;
14475

E
Eric Blake 已提交
14476
    if (!qemuDomainObjEndJob(driver, vm))
14477 14478 14479 14480 14481 14482
        vm = NULL;

cleanup:
    virDomainDefFree(def);
    virDomainChrSourceDefFree(monConfig);
    if (vm)
14483
        virObjectUnlock(vm);
14484
    VIR_FREE(pidfile);
14485
    virObjectUnref(caps);
E
Eric Blake 已提交
14486
    virObjectUnref(qemuCaps);
14487 14488 14489 14490
    return dom;
}


14491 14492
static int
qemuDomainOpenConsole(virDomainPtr dom,
14493
                      const char *dev_name,
14494 14495 14496 14497 14498
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
14499
    size_t i;
14500
    virDomainChrDefPtr chr = NULL;
14501
    qemuDomainObjPrivatePtr priv;
14502

14503 14504
    virCheckFlags(VIR_DOMAIN_CONSOLE_SAFE |
                  VIR_DOMAIN_CONSOLE_FORCE, -1);
14505

14506
    if (!(vm = qemuDomObjFromDomain(dom)))
14507 14508
        goto cleanup;

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

14512
    if (!virDomainObjIsActive(vm)) {
14513 14514
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
14515 14516 14517
        goto cleanup;
    }

14518 14519
    priv = vm->privateData;

14520
    if (dev_name) {
14521
        for (i = 0; !chr && i < vm->def->nconsoles; i++) {
14522 14523 14524 14525
            if (vm->def->consoles[i]->info.alias &&
                STREQ(dev_name, vm->def->consoles[i]->info.alias))
                chr = vm->def->consoles[i];
        }
14526
        for (i = 0; !chr && i < vm->def->nserials; i++) {
14527
            if (STREQ(dev_name, vm->def->serials[i]->info.alias))
14528 14529
                chr = vm->def->serials[i];
        }
14530
        for (i = 0; !chr && i < vm->def->nparallels; i++) {
14531
            if (STREQ(dev_name, vm->def->parallels[i]->info.alias))
14532 14533 14534
                chr = vm->def->parallels[i];
        }
    } else {
14535 14536
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
14537 14538 14539 14540 14541
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
14542 14543 14544
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find character device %s"),
                       NULLSTR(dev_name));
14545 14546 14547
        goto cleanup;
    }

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

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

    if (ret == 1) {
14562 14563
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Active console session exists for this domain"));
14564 14565
        ret = -1;
    }
14566 14567 14568

cleanup:
    if (vm)
14569
        virObjectUnlock(vm);
14570 14571 14572
    return ret;
}

14573 14574 14575 14576 14577 14578 14579 14580
static int
qemuDomainOpenChannel(virDomainPtr dom,
                      const char *name,
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
14581
    size_t i;
14582 14583 14584 14585 14586 14587 14588 14589
    virDomainChrDefPtr chr = NULL;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(VIR_DOMAIN_CHANNEL_FORCE, -1);

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

14590 14591 14592
    if (virDomainOpenChannelEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

14593 14594 14595 14596 14597 14598 14599 14600 14601
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto cleanup;
    }

    priv = vm->privateData;

    if (name) {
14602
        for (i = 0; !chr && i < vm->def->nchannels; i++) {
14603 14604 14605 14606 14607 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 14642 14643
            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)
14644
        virObjectUnlock(vm);
14645 14646 14647
    return ret;
}

E
Eric Blake 已提交
14648
static char *
14649
qemuDiskPathToAlias(virDomainObjPtr vm, const char *path, int *idxret)
E
Eric Blake 已提交
14650
{
14651
    int idx;
14652
    char *ret = NULL;
14653
    virDomainDiskDefPtr disk;
14654

14655 14656
    idx = virDomainDiskIndexByName(vm->def, path, true);
    if (idx < 0)
14657
        goto cleanup;
14658

14659 14660 14661
    disk = vm->def->disks[idx];
    if (idxret)
        *idxret = idx;
14662

14663
    if (disk->src) {
14664
        if (virAsprintf(&ret, "drive-%s", disk->info.alias) < 0)
14665
            return NULL;
14666 14667
    }

14668
cleanup:
14669
    if (!ret) {
14670 14671
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("No device found for specified path"));
14672 14673 14674 14675
    }
    return ret;
}

14676 14677 14678 14679
/* 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 已提交
14680
qemuDomainBlockPivot(virConnectPtr conn,
14681
                     virQEMUDriverPtr driver, virDomainObjPtr vm,
14682 14683
                     const char *device, virDomainDiskDefPtr disk)
{
14684
    int ret = -1, rc;
14685 14686 14687
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainBlockJobInfo info;
    const char *format = virStorageFileFormatTypeToString(disk->mirrorFormat);
E
Eric Blake 已提交
14688
    bool resume = false;
14689 14690 14691
    char *oldsrc = NULL;
    int oldformat;
    virStorageFileMetadataPtr oldchain = NULL;
14692
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
14693 14694 14695

    /* Probe the status, if needed.  */
    if (!disk->mirroring) {
14696
        qemuDomainObjEnterMonitor(driver, vm);
14697
        rc = qemuMonitorBlockJob(priv->mon, device, NULL, 0, &info,
14698
                                  BLOCK_JOB_INFO, true);
14699
        qemuDomainObjExitMonitor(driver, vm);
14700
        if (rc < 0)
14701 14702 14703 14704 14705 14706
            goto cleanup;
        if (!virDomainObjIsActive(vm)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("domain is not running"));
            goto cleanup;
        }
14707
        if (rc == 1 && info.cur == info.end &&
14708 14709 14710 14711 14712 14713 14714 14715 14716 14717 14718
            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 已提交
14719 14720 14721 14722 14723 14724 14725 14726 14727 14728 14729 14730 14731 14732 14733 14734 14735 14736 14737 14738 14739 14740 14741
    /* 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;
        }
    }

14742 14743 14744 14745 14746 14747 14748 14749 14750 14751 14752 14753
    /* 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.  */
    oldsrc = disk->src;
    oldformat = disk->format;
    oldchain = disk->backingChain;
    disk->src = disk->mirror;
    disk->format = disk->mirrorFormat;
    disk->backingChain = NULL;
14754
    if (qemuDomainDetermineDiskChain(driver, vm, disk, false) < 0) {
14755 14756 14757 14758 14759 14760
        disk->src = oldsrc;
        disk->format = oldformat;
        disk->backingChain = oldchain;
        goto cleanup;
    }
    if (disk->mirrorFormat && disk->mirrorFormat != VIR_STORAGE_FILE_RAW &&
14761
        (virDomainLockDiskAttach(driver->lockManager, cfg->uri,
14762
                                 vm, disk) < 0 ||
14763
         qemuSetupDiskCgroup(vm, disk) < 0 ||
14764 14765 14766 14767 14768 14769 14770 14771
         virSecurityManagerSetImageLabel(driver->securityManager, vm->def,
                                         disk) < 0)) {
        disk->src = oldsrc;
        disk->format = oldformat;
        disk->backingChain = oldchain;
        goto cleanup;
    }

14772
    /* Attempt the pivot.  */
14773
    qemuDomainObjEnterMonitor(driver, vm);
14774
    ret = qemuMonitorDrivePivot(priv->mon, device, disk->mirror, format);
14775
    qemuDomainObjExitMonitor(driver, vm);
14776 14777 14778 14779 14780 14781 14782 14783 14784

    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.  */
14785 14786
        VIR_FREE(oldsrc);
        virStorageFileFreeMetadata(oldchain);
14787 14788 14789 14790 14791 14792 14793 14794 14795 14796
        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.  */
14797 14798 14799 14800
        disk->src = oldsrc;
        disk->format = oldformat;
        virStorageFileFreeMetadata(disk->backingChain);
        disk->backingChain = oldchain;
14801 14802
        VIR_FREE(disk->mirror);
    }
14803 14804
    disk->mirrorFormat = VIR_STORAGE_FILE_NONE;
    disk->mirroring = false;
14805 14806

cleanup:
E
Eric Blake 已提交
14807 14808 14809
    if (resume && virDomainObjIsActive(vm) &&
        qemuProcessStartCPUs(driver, vm, conn,
                             VIR_DOMAIN_RUNNING_UNPAUSED,
14810
                             QEMU_ASYNC_JOB_NONE) < 0) {
14811
        virObjectEventPtr event = NULL;
14812
        event = virDomainEventLifecycleNewFromObj(vm,
14813 14814 14815 14816 14817 14818 14819 14820
                                         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 已提交
14821
    }
14822
    virObjectUnref(cfg);
14823 14824 14825
    return ret;
}

14826
static int
14827 14828 14829
qemuDomainBlockJobImpl(virDomainObjPtr vm,
                       virConnectPtr conn,
                       const char *path, const char *base,
14830
                       unsigned long bandwidth, virDomainBlockJobInfoPtr info,
14831
                       int mode, unsigned int flags)
14832
{
14833
    virQEMUDriverPtr driver = conn->privateData;
14834
    qemuDomainObjPrivatePtr priv;
E
Eric Blake 已提交
14835
    char *device = NULL;
14836
    int ret = -1;
14837
    bool async = false;
14838
    virObjectEventPtr event = NULL;
14839 14840
    int idx;
    virDomainDiskDefPtr disk;
14841

14842
    if (!virDomainObjIsActive(vm)) {
14843 14844
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
14845 14846 14847
        goto cleanup;
    }

14848
    priv = vm->privateData;
14849
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC)) {
14850
        async = true;
14851
    } else if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_SYNC)) {
14852 14853
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block jobs not supported with this QEMU binary"));
14854 14855
        goto cleanup;
    } else if (base) {
14856 14857 14858
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("partial block pull not supported with this "
                         "QEMU binary"));
14859
        goto cleanup;
14860
    } else if (mode == BLOCK_JOB_PULL && bandwidth) {
14861 14862 14863
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("setting bandwidth at start of block pull not "
                         "supported with this QEMU binary"));
14864
        goto cleanup;
14865
    }
14866

14867 14868 14869 14870 14871 14872 14873 14874 14875
    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;
    }

14876 14877
    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device)
14878
        goto endjob;
14879
    disk = vm->def->disks[idx];
14880

E
Eric Blake 已提交
14881 14882 14883 14884
    if (mode == BLOCK_JOB_PULL && disk->mirror) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
                       _("disk '%s' already in active block copy job"),
                       disk->dst);
14885
        goto endjob;
E
Eric Blake 已提交
14886
    }
14887 14888 14889 14890 14891 14892
    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);
14893 14894 14895
        goto endjob;
    }

14896 14897
    if (disk->mirror && mode == BLOCK_JOB_ABORT &&
        (flags & VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT)) {
14898
        ret = qemuDomainBlockPivot(conn, driver, vm, device, disk);
14899 14900 14901
        goto endjob;
    }

14902
    qemuDomainObjEnterMonitor(driver, vm);
14903
    /* XXX - libvirt should really be tracking the backing file chain
14904 14905
     * itself, and validating that base is on the chain, rather than
     * relying on qemu to do this.  */
14906 14907
    ret = qemuMonitorBlockJob(priv->mon, device, base, bandwidth, info, mode,
                              async);
14908
    qemuDomainObjExitMonitor(driver, vm);
14909 14910 14911
    if (ret < 0)
        goto endjob;

14912 14913 14914 14915 14916 14917
    /* 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;

14918 14919 14920 14921 14922 14923 14924 14925 14926
    /* 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;
    }

14927 14928 14929 14930 14931 14932 14933 14934 14935 14936 14937 14938 14939 14940 14941 14942 14943 14944 14945
    /* 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;

14946
                qemuDomainObjEnterMonitor(driver, vm);
14947 14948
                ret = qemuMonitorBlockJob(priv->mon, device, NULL, 0, &dummy,
                                          BLOCK_JOB_INFO, async);
14949
                qemuDomainObjExitMonitor(driver, vm);
14950 14951 14952 14953

                if (ret <= 0)
                    break;

14954
                virObjectUnlock(vm);
14955 14956 14957

                nanosleep(&ts, NULL);

14958
                virObjectLock(vm);
14959 14960

                if (!virDomainObjIsActive(vm)) {
14961 14962
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("domain is not running"));
14963 14964 14965 14966 14967 14968
                    ret = -1;
                    break;
                }
            }
        }
    }
14969 14970

endjob:
E
Eric Blake 已提交
14971
    if (!qemuDomainObjEndJob(driver, vm)) {
14972 14973 14974 14975 14976 14977 14978
        vm = NULL;
        goto cleanup;
    }

cleanup:
    VIR_FREE(device);
    if (vm)
14979
        virObjectUnlock(vm);
14980 14981
    if (event)
        qemuDomainEventQueue(driver, event);
14982 14983 14984 14985 14986 14987
    return ret;
}

static int
qemuDomainBlockJobAbort(virDomainPtr dom, const char *path, unsigned int flags)
{
14988 14989
    virDomainObjPtr vm;

14990 14991
    virCheckFlags(VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC |
                  VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT, -1);
14992 14993 14994 14995 14996 14997 14998 14999 15000 15001

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

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

    return qemuDomainBlockJobImpl(vm, dom->conn, path, NULL, 0, NULL, BLOCK_JOB_ABORT,
15002
                                  flags);
15003 15004 15005 15006 15007 15008
}

static int
qemuDomainGetBlockJobInfo(virDomainPtr dom, const char *path,
                           virDomainBlockJobInfoPtr info, unsigned int flags)
{
15009
    virDomainObjPtr vm;
15010
    virCheckFlags(0, -1);
15011 15012 15013 15014 15015 15016 15017 15018 15019 15020

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

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

    return qemuDomainBlockJobImpl(vm, dom->conn, path, NULL, 0, info, BLOCK_JOB_INFO,
15021
                                  flags);
15022 15023 15024 15025 15026 15027
}

static int
qemuDomainBlockJobSetSpeed(virDomainPtr dom, const char *path,
                           unsigned long bandwidth, unsigned int flags)
{
15028
    virDomainObjPtr vm;
15029
    virCheckFlags(0, -1);
15030 15031 15032 15033 15034 15035 15036 15037 15038 15039

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

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

    return qemuDomainBlockJobImpl(vm, dom->conn, path, NULL, bandwidth, NULL,
15040
                                  BLOCK_JOB_SPEED, flags);
15041 15042
}

15043
static int
15044 15045 15046
qemuDomainBlockCopy(virDomainObjPtr vm,
                    virConnectPtr conn,
                    const char *path,
15047 15048 15049
                    const char *dest, const char *format,
                    unsigned long bandwidth, unsigned int flags)
{
15050
    virQEMUDriverPtr driver = conn->privateData;
15051 15052
    qemuDomainObjPrivatePtr priv;
    char *device = NULL;
15053
    virDomainDiskDefPtr disk = NULL;
15054 15055
    int ret = -1;
    int idx;
15056
    struct stat st;
15057 15058
    bool need_unlink = false;
    char *mirror = NULL;
15059
    virQEMUDriverConfigPtr cfg = NULL;
15060 15061

    /* Preliminaries: find the disk we are editing, sanity checks */
15062 15063
    virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
                  VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT, -1);
15064 15065

    priv = vm->privateData;
15066
    cfg = virQEMUDriverGetConfig(driver);
15067

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

15071 15072 15073
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
15074
        goto endjob;
15075 15076 15077 15078
    }

    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device) {
15079
        goto endjob;
15080 15081 15082 15083 15084 15085
    }
    disk = vm->def->disks[idx];
    if (disk->mirror) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
                       _("disk '%s' already in active block copy job"),
                       disk->dst);
15086
        goto endjob;
15087 15088
    }

15089 15090
    if (!(virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE_MIRROR) &&
          virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC))) {
15091 15092
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block copy is not supported with this QEMU binary"));
15093
        goto endjob;
15094 15095 15096 15097 15098 15099 15100 15101 15102 15103
    }
    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 endjob;
    }
15104

15105
    if (qemuDomainDetermineDiskChain(driver, vm, disk, false) < 0)
15106 15107 15108 15109 15110 15111 15112 15113 15114 15115 15116 15117 15118
        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.  */
15119 15120 15121 15122 15123 15124 15125 15126 15127 15128 15129 15130 15131 15132 15133 15134 15135 15136 15137 15138
    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;
    }

15139
    if (!(flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT)) {
15140
        int fd = qemuOpenFile(driver, vm, dest, O_WRONLY | O_TRUNC | O_CREAT,
15141 15142 15143 15144 15145
                              &need_unlink, NULL);
        if (fd < 0)
            goto endjob;
        VIR_FORCE_CLOSE(fd);
        if (!format)
15146
            disk->mirrorFormat = disk->format;
15147
    } else if (format) {
15148 15149 15150 15151 15152 15153
        disk->mirrorFormat = virStorageFileFormatTypeFromString(format);
        if (disk->mirrorFormat <= 0) {
            virReportError(VIR_ERR_INVALID_ARG, _("unrecognized format '%s'"),
                           format);
            goto endjob;
        }
15154 15155 15156 15157 15158
    } 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.  */
15159 15160
        disk->mirrorFormat = virStorageFileProbeFormat(dest, cfg->user,
                                                       cfg->group);
15161 15162 15163
    }
    if (!format && disk->mirrorFormat > 0)
        format = virStorageFileFormatTypeToString(disk->mirrorFormat);
15164
    if (VIR_STRDUP(mirror, dest) < 0)
15165 15166
        goto endjob;

15167
    if (qemuDomainPrepareDiskChainElement(driver, vm, disk, dest,
15168
                                          VIR_DISK_CHAIN_READ_WRITE) < 0) {
15169
        qemuDomainPrepareDiskChainElement(driver, vm, disk, dest,
15170 15171 15172 15173
                                          VIR_DISK_CHAIN_NO_ACCESS);
        goto endjob;
    }

15174 15175 15176 15177
    /* Actually start the mirroring */
    qemuDomainObjEnterMonitor(driver, vm);
    ret = qemuMonitorDriveMirror(priv->mon, device, dest, format, bandwidth,
                                 flags);
15178
    virDomainAuditDisk(vm, NULL, dest, "mirror", ret >= 0);
15179
    qemuDomainObjExitMonitor(driver, vm);
15180
    if (ret < 0) {
15181
        qemuDomainPrepareDiskChainElement(driver, vm, disk, dest,
15182 15183 15184 15185 15186 15187 15188 15189
                                          VIR_DISK_CHAIN_NO_ACCESS);
        goto endjob;
    }

    /* Update vm in place to match changes.  */
    need_unlink = false;
    disk->mirror = mirror;
    mirror = NULL;
15190 15191

endjob:
15192 15193
    if (need_unlink && unlink(dest))
        VIR_WARN("unable to unlink just-created %s", dest);
15194
    if (ret < 0 && disk)
15195
        disk->mirrorFormat = VIR_STORAGE_FILE_NONE;
15196
    VIR_FREE(mirror);
E
Eric Blake 已提交
15197
    if (!qemuDomainObjEndJob(driver, vm))
15198 15199 15200 15201 15202
        vm = NULL;

cleanup:
    VIR_FREE(device);
    if (vm)
15203
        virObjectUnlock(vm);
15204
    virObjectUnref(cfg);
15205 15206 15207
    return ret;
}

15208
static int
15209 15210
qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base,
                      unsigned long bandwidth, unsigned int flags)
15211
{
15212 15213
    virDomainObjPtr vm;

15214
    virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
15215
                  VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT |
15216 15217 15218
                  VIR_DOMAIN_BLOCK_REBASE_COPY |
                  VIR_DOMAIN_BLOCK_REBASE_COPY_RAW, -1);

15219 15220 15221 15222 15223 15224 15225 15226
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;

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

15227 15228 15229 15230 15231 15232
    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);
15233
        return qemuDomainBlockCopy(vm, dom->conn, path, base, format, bandwidth, flags);
15234 15235
    }

15236
    return qemuDomainBlockJobImpl(vm, dom->conn, path, base, bandwidth, NULL,
15237
                                  BLOCK_JOB_PULL, flags);
15238
}
15239

15240 15241 15242 15243
static int
qemuDomainBlockPull(virDomainPtr dom, const char *path, unsigned long bandwidth,
                    unsigned int flags)
{
15244
    virDomainObjPtr vm;
15245
    virCheckFlags(0, -1);
15246 15247 15248 15249 15250 15251 15252 15253 15254 15255

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

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

    return qemuDomainBlockJobImpl(vm, dom->conn, path, NULL, bandwidth, NULL,
15256
                                  BLOCK_JOB_PULL, flags);
15257 15258
}

15259 15260 15261 15262 15263 15264

static int
qemuDomainBlockCommit(virDomainPtr dom, const char *path, const char *base,
                      const char *top, unsigned long bandwidth,
                      unsigned int flags)
{
15265
    virQEMUDriverPtr driver = dom->conn->privateData;
15266 15267 15268 15269 15270
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm = NULL;
    char *device = NULL;
    int ret = -1;
    int idx;
E
Eric Blake 已提交
15271
    virDomainDiskDefPtr disk = NULL;
15272 15273 15274 15275
    const char *top_canon = NULL;
    virStorageFileMetadataPtr top_meta = NULL;
    const char *top_parent = NULL;
    const char *base_canon = NULL;
E
Eric Blake 已提交
15276
    bool clean_access = false;
15277

15278
    virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW, -1);
15279 15280 15281 15282 15283

    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
    priv = vm->privateData;

15284 15285 15286
    if (virDomainBlockCommitEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

15287 15288 15289 15290 15291 15292 15293 15294
    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;
    }
15295
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCK_COMMIT)) {
15296 15297 15298 15299 15300 15301 15302 15303 15304 15305 15306 15307 15308 15309 15310 15311
        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;
    }
15312
    if (qemuDomainDetermineDiskChain(driver, vm, disk, false) < 0)
15313
        goto endjob;
15314

15315 15316 15317 15318 15319 15320 15321 15322 15323 15324 15325 15326 15327 15328 15329
    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"),
15330
                       top_canon, path);
15331 15332 15333 15334 15335 15336 15337 15338 15339 15340 15341 15342 15343 15344 15345 15346 15347 15348 15349 15350 15351 15352 15353
        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;
    }
15354

15355 15356 15357 15358 15359 15360 15361
    /* 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.  */
E
Eric Blake 已提交
15362
    clean_access = true;
15363
    if (qemuDomainPrepareDiskChainElement(driver, vm, disk, base_canon,
15364 15365
                                          VIR_DISK_CHAIN_READ_WRITE) < 0 ||
        (top_parent && top_parent != disk->src &&
15366
         qemuDomainPrepareDiskChainElement(driver, vm, disk,
15367 15368 15369 15370 15371
                                           top_parent,
                                           VIR_DISK_CHAIN_READ_WRITE) < 0))
        goto endjob;

    /* Start the commit operation.  */
15372
    qemuDomainObjEnterMonitor(driver, vm);
15373 15374
    ret = qemuMonitorBlockCommit(priv->mon, device, top_canon, base_canon,
                                 bandwidth);
15375 15376 15377
    qemuDomainObjExitMonitor(driver, vm);

endjob:
E
Eric Blake 已提交
15378
    if (ret < 0 && clean_access) {
15379
        /* Revert access to read-only, if possible.  */
15380
        qemuDomainPrepareDiskChainElement(driver, vm, disk, base_canon,
15381 15382
                                          VIR_DISK_CHAIN_READ_ONLY);
        if (top_parent && top_parent != disk->src)
15383
            qemuDomainPrepareDiskChainElement(driver, vm, disk,
15384 15385 15386
                                              top_parent,
                                              VIR_DISK_CHAIN_READ_ONLY);
    }
E
Eric Blake 已提交
15387
    if (!qemuDomainObjEndJob(driver, vm))
15388 15389 15390 15391 15392
        vm = NULL;

cleanup:
    VIR_FREE(device);
    if (vm)
15393
        virObjectUnlock(vm);
15394 15395 15396
    return ret;
}

15397 15398 15399 15400 15401 15402
static int
qemuDomainOpenGraphics(virDomainPtr dom,
                       unsigned int idx,
                       int fd,
                       unsigned int flags)
{
15403
    virQEMUDriverPtr driver = dom->conn->privateData;
15404 15405 15406 15407 15408 15409 15410
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
    const char *protocol;

    virCheckFlags(VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH, -1);

15411 15412
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
15413

15414 15415 15416
    if (virDomainOpenGraphicsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

15417
    if (!virDomainObjIsActive(vm)) {
15418 15419
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
15420 15421 15422 15423 15424 15425
        goto cleanup;
    }

    priv = vm->privateData;

    if (idx >= vm->def->ngraphics) {
15426 15427
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No graphics backend with index %d"), idx);
15428 15429 15430 15431 15432 15433 15434 15435 15436 15437
        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:
15438 15439 15440
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Can only open VNC or SPICE graphics backends, not %s"),
                       virDomainGraphicsTypeToString(vm->def->graphics[idx]->type));
15441 15442 15443
        goto cleanup;
    }

15444 15445 15446 15447
    if (virSecurityManagerSetImageFDLabel(driver->securityManager, vm->def,
                                          fd) < 0)
        goto cleanup;

15448
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
15449
        goto cleanup;
15450
    qemuDomainObjEnterMonitor(driver, vm);
15451 15452
    ret = qemuMonitorOpenGraphics(priv->mon, protocol, fd, "graphicsfd",
                                  (flags & VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH) != 0);
15453
    qemuDomainObjExitMonitor(driver, vm);
E
Eric Blake 已提交
15454
    if (!qemuDomainObjEndJob(driver, vm))
15455 15456 15457 15458
        vm = NULL;

cleanup:
    if (vm)
15459
        virObjectUnlock(vm);
15460 15461 15462
    return ret;
}

15463 15464 15465 15466 15467 15468 15469
static int
qemuDomainSetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int nparams,
                         unsigned int flags)
{
15470
    virQEMUDriverPtr driver = dom->conn->privateData;
15471 15472 15473 15474
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virDomainDefPtr persistentDef = NULL;
    virDomainBlockIoTuneInfo info;
E
Eric Blake 已提交
15475
    virDomainBlockIoTuneInfo *oldinfo;
15476
    char *device = NULL;
15477
    int ret = -1;
15478
    size_t i;
15479
    int idx = -1;
E
Eric Blake 已提交
15480 15481
    bool set_bytes = false;
    bool set_iops = false;
15482
    virQEMUDriverConfigPtr cfg = NULL;
15483
    virCapsPtr caps = NULL;
15484 15485 15486

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
15487 15488 15489 15490 15491 15492 15493 15494 15495 15496 15497 15498 15499 15500
    if (virTypedParamsValidate(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)
15501
        return -1;
15502 15503 15504

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

15505 15506 15507
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;

15508 15509 15510
    if (virDomainSetBlockIoTuneEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

15514
    priv = vm->privateData;
15515 15516
    cfg = virQEMUDriverGetConfig(driver);

15517
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
15518
        goto endjob;
15519

15520 15521
    if (!(device = qemuDiskPathToAlias(vm, disk, &idx)))
        goto endjob;
15522

15523
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
15524
                                        &persistentDef) < 0)
15525 15526 15527 15528 15529
        goto endjob;

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

15530 15531 15532 15533 15534 15535 15536
        if (param->value.ul > LLONG_MAX) {
            virReportError(VIR_ERR_OVERFLOW,
                           _("block I/O throttle limit value must"
                             " be less than %llu"), LLONG_MAX);
            goto endjob;
        }

15537 15538
        if (STREQ(param->field, VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC)) {
            info.total_bytes_sec = param->value.ul;
E
Eric Blake 已提交
15539
            set_bytes = true;
15540 15541 15542
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC)) {
            info.read_bytes_sec = param->value.ul;
E
Eric Blake 已提交
15543
            set_bytes = true;
15544 15545 15546
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC)) {
            info.write_bytes_sec = param->value.ul;
E
Eric Blake 已提交
15547
            set_bytes = true;
15548 15549 15550
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC)) {
            info.total_iops_sec = param->value.ul;
E
Eric Blake 已提交
15551
            set_iops = true;
15552 15553 15554
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC)) {
            info.read_iops_sec = param->value.ul;
E
Eric Blake 已提交
15555
            set_iops = true;
15556 15557 15558
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC)) {
            info.write_iops_sec = param->value.ul;
E
Eric Blake 已提交
15559
            set_iops = true;
15560 15561 15562 15563 15564
        }
    }

    if ((info.total_bytes_sec && info.read_bytes_sec) ||
        (info.total_bytes_sec && info.write_bytes_sec)) {
15565 15566
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("total and read/write of bytes_sec cannot be set at the same time"));
15567 15568 15569 15570 15571
        goto endjob;
    }

    if ((info.total_iops_sec && info.read_iops_sec) ||
        (info.total_iops_sec && info.write_iops_sec)) {
15572 15573
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("total and read/write of iops_sec cannot be set at the same time"));
15574 15575 15576 15577
        goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
15578 15579 15580 15581 15582 15583 15584
        if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE_IOTUNE)) {
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block I/O throttling not supported with this "
                         "QEMU binary"));
            goto endjob;
        }

E
Eric Blake 已提交
15585 15586 15587 15588 15589 15590 15591 15592 15593 15594 15595 15596 15597 15598
        /* 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;
        }
15599
        qemuDomainObjEnterMonitor(driver, vm);
15600
        ret = qemuMonitorSetBlockIoThrottle(priv->mon, device, &info);
15601
        qemuDomainObjExitMonitor(driver, vm);
L
Lei Li 已提交
15602 15603
        if (ret < 0)
            goto endjob;
15604
        vm->def->disks[idx]->blkdeviotune = info;
15605 15606 15607
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
15608
        sa_assert(persistentDef);
E
Eric Blake 已提交
15609 15610 15611 15612 15613 15614 15615 15616 15617 15618 15619
        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;
        }
15620
        persistentDef->disks[idx]->blkdeviotune = info;
15621
        ret = virDomainSaveConfig(cfg->configDir, persistentDef);
15622
        if (ret < 0) {
15623
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
15624 15625 15626 15627 15628 15629
                           _("Write to config file failed"));
            goto endjob;
        }
    }

endjob:
15630
    if (!qemuDomainObjEndJob(driver, vm))
15631 15632 15633 15634 15635
        vm = NULL;

cleanup:
    VIR_FREE(device);
    if (vm)
15636
        virObjectUnlock(vm);
15637
    virObjectUnref(caps);
15638
    virObjectUnref(cfg);
15639 15640 15641 15642 15643 15644 15645 15646 15647 15648
    return ret;
}

static int
qemuDomainGetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int *nparams,
                         unsigned int flags)
{
15649
    virQEMUDriverPtr driver = dom->conn->privateData;
15650 15651 15652 15653
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virDomainDefPtr persistentDef = NULL;
    virDomainBlockIoTuneInfo reply;
15654
    char *device = NULL;
15655
    int ret = -1;
15656
    size_t i;
15657
    virCapsPtr caps = NULL;
15658 15659 15660 15661 15662 15663 15664 15665

    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;

15666 15667
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
15668

15669 15670 15671
    if (virDomainGetBlockIoTuneEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

15672 15673 15674
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

15675 15676 15677 15678 15679 15680 15681
    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;
    }

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

15685
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
15686
                                        &persistentDef) < 0)
15687 15688
        goto endjob;

15689 15690 15691 15692 15693
    device = qemuDiskPathToAlias(vm, disk, NULL);
    if (!device) {
        goto endjob;
    }

15694 15695
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        priv = vm->privateData;
15696
        qemuDomainObjEnterMonitor(driver, vm);
15697
        ret = qemuMonitorGetBlockIoThrottle(priv->mon, device, &reply);
15698
        qemuDomainObjExitMonitor(driver, vm);
15699 15700 15701 15702 15703 15704 15705 15706 15707 15708 15709 15710 15711 15712
        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];

15713
        switch (i) {
15714
        case 0:
15715 15716 15717 15718
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_bytes_sec) < 0)
15719 15720 15721
                goto endjob;
            break;
        case 1:
15722 15723 15724 15725
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_bytes_sec) < 0)
15726 15727 15728
                goto endjob;
            break;
        case 2:
15729 15730 15731 15732
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_bytes_sec) < 0)
15733 15734 15735
                goto endjob;
            break;
        case 3:
15736 15737 15738 15739
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_iops_sec) < 0)
15740 15741 15742
                goto endjob;
            break;
        case 4:
15743 15744 15745 15746
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_iops_sec) < 0)
15747 15748 15749
                goto endjob;
            break;
        case 5:
15750 15751 15752 15753
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_iops_sec) < 0)
15754 15755 15756 15757 15758 15759 15760 15761 15762 15763 15764 15765
                goto endjob;
            break;
        default:
            break;
        }
    }

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

endjob:
E
Eric Blake 已提交
15766
    if (!qemuDomainObjEndJob(driver, vm))
15767 15768 15769 15770 15771
        vm = NULL;

cleanup:
    VIR_FREE(device);
    if (vm)
15772
        virObjectUnlock(vm);
15773
    virObjectUnref(caps);
15774 15775
    return ret;
}
15776

15777 15778 15779 15780 15781 15782
static int
qemuDomainGetDiskErrors(virDomainPtr dom,
                        virDomainDiskErrorPtr errors,
                        unsigned int nerrors,
                        unsigned int flags)
{
15783
    virQEMUDriverPtr driver = dom->conn->privateData;
15784 15785 15786 15787
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virHashTablePtr table = NULL;
    int ret = -1;
15788
    size_t i;
15789 15790 15791 15792
    int n = 0;

    virCheckFlags(0, -1);

15793
    if (!(vm = qemuDomObjFromDomain(dom)))
15794 15795 15796 15797
        goto cleanup;

    priv = vm->privateData;

15798 15799 15800
    if (virDomainGetDiskErrorsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

15801 15802 15803 15804
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
15805 15806
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
15807 15808 15809 15810 15811 15812 15813 15814 15815 15816 15817 15818 15819 15820 15821 15822 15823 15824 15825 15826 15827 15828 15829
        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;

15830
            if (VIR_STRDUP(errors[n].disk, disk->dst) < 0)
15831 15832 15833 15834 15835 15836 15837 15838 15839
                goto endjob;
            errors[n].error = info->io_status;
            n++;
        }
    }

    ret = n;

endjob:
E
Eric Blake 已提交
15840
    if (!qemuDomainObjEndJob(driver, vm))
15841 15842 15843 15844
        vm = NULL;

cleanup:
    if (vm)
15845
        virObjectUnlock(vm);
15846 15847 15848 15849 15850 15851 15852 15853
    virHashFree(table);
    if (ret < 0) {
        for (i = 0; i < n; i++)
            VIR_FREE(errors[i].disk);
    }
    return ret;
}

15854 15855 15856 15857
static int
qemuDomainSetMetadata(virDomainPtr dom,
                      int type,
                      const char *metadata,
15858 15859
                      const char *key,
                      const char *uri,
15860 15861
                      unsigned int flags)
{
15862
    virQEMUDriverPtr driver = dom->conn->privateData;
15863
    virDomainObjPtr vm;
15864
    virQEMUDriverConfigPtr cfg = NULL;
15865
    virCapsPtr caps = NULL;
15866
    int ret = -1;
15867 15868 15869 15870

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

15871
    if (!(vm = qemuDomObjFromDomain(dom)))
15872
        return -1;
15873

15874 15875
    cfg = virQEMUDriverGetConfig(driver);

15876 15877 15878
    if (virDomainSetMetadataEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

15879 15880 15881
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

15882 15883
    ret = virDomainObjSetMetadata(vm, type, metadata, key, uri, caps,
                                  driver->xmlopt, cfg->configDir, flags);
15884 15885

cleanup:
15886
    virObjectUnlock(vm);
15887
    virObjectUnref(caps);
15888
    virObjectUnref(cfg);
15889 15890 15891 15892 15893 15894
    return ret;
}

static char *
qemuDomainGetMetadata(virDomainPtr dom,
                      int type,
15895
                      const char *uri,
15896 15897
                      unsigned int flags)
{
15898
    virQEMUDriverPtr driver = dom->conn->privateData;
15899
    virCapsPtr caps = NULL;
15900 15901 15902
    virDomainObjPtr vm;
    char *ret = NULL;

15903
    if (!(vm = qemuDomObjFromDomain(dom)))
15904
        return NULL;
15905

15906 15907 15908
    if (virDomainGetMetadataEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

15909 15910 15911
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

15912
    ret = virDomainObjGetMetadata(vm, type, uri, caps, driver->xmlopt, flags);
15913 15914

cleanup:
15915
    virObjectUnlock(vm);
15916
    virObjectUnref(caps);
15917 15918 15919
    return ret;
}

15920 15921 15922 15923 15924 15925 15926 15927 15928 15929 15930 15931 15932 15933 15934
/* 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
15935
getSumVcpuPercpuStats(virDomainObjPtr vm,
15936 15937 15938 15939
                      unsigned long long *sum_cpu_time,
                      unsigned int num)
{
    int ret = -1;
15940
    size_t i;
15941
    char *buf = NULL;
15942
    qemuDomainObjPrivatePtr priv = vm->privateData;
15943 15944
    virCgroupPtr group_vcpu = NULL;

15945
    for (i = 0; i < priv->nvcpupids; i++) {
15946 15947
        char *pos;
        unsigned long long tmp;
15948
        size_t j;
15949

15950
        if (virCgroupNewVcpu(priv->cgroup, i, false, &group_vcpu) < 0)
15951 15952
            goto cleanup;

15953
        if (virCgroupGetCpuacctPercpuUsage(group_vcpu, &buf) < 0)
15954 15955 15956 15957 15958
            goto cleanup;

        pos = buf;
        for (j = 0; j < num; j++) {
            if (virStrToLong_ull(pos, &pos, 10, &tmp) < 0) {
15959 15960
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("cpuacct parse error"));
15961 15962 15963 15964 15965 15966 15967 15968 15969 15970 15971 15972 15973 15974 15975 15976
                goto cleanup;
            }
            sum_cpu_time[j] += tmp;
        }

        virCgroupFree(&group_vcpu);
        VIR_FREE(buf);
    }

    ret = 0;
cleanup:
    virCgroupFree(&group_vcpu);
    VIR_FREE(buf);
    return ret;
}

15977
static int
15978
qemuDomainGetPercpuStats(virDomainObjPtr vm,
15979 15980 15981 15982 15983 15984
                         virTypedParameterPtr params,
                         unsigned int nparams,
                         int start_cpu,
                         unsigned int ncpus)
{
    int rv = -1;
15985 15986
    size_t i;
    int id, max_id;
15987 15988
    char *pos;
    char *buf = NULL;
15989 15990 15991 15992
    unsigned long long *sum_cpu_time = NULL;
    unsigned long long *sum_cpu_pos;
    unsigned int n = 0;
    qemuDomainObjPrivatePtr priv = vm->privateData;
15993 15994
    virTypedParameterPtr ent;
    int param_idx;
15995
    unsigned long long cpu_time;
15996 15997 15998

    /* return the number of supported params */
    if (nparams == 0 && ncpus != 0)
15999
        return QEMU_NB_PER_CPU_STAT_PARAM;
16000

16001 16002 16003
    /* To parse account file, we need to know how many cpus are present.  */
    max_id = nodeGetCPUCount();
    if (max_id < 0)
16004 16005 16006
        return rv;

    if (ncpus == 0) { /* returns max cpu ID */
16007
        rv = max_id;
16008 16009 16010 16011
        goto cleanup;
    }

    if (start_cpu > max_id) {
16012 16013 16014
        virReportError(VIR_ERR_INVALID_ARG,
                       _("start_cpu %d larger than maximum of %d"),
                       start_cpu, max_id);
16015 16016 16017 16018
        goto cleanup;
    }

    /* we get percpu cputime accounting info. */
16019
    if (virCgroupGetCpuacctPercpuUsage(priv->cgroup, &buf))
16020 16021 16022
        goto cleanup;
    pos = buf;

16023 16024 16025
    /* return percpu cputime in index 0 */
    param_idx = 0;

16026
    /* number of cpus to compute */
16027 16028 16029
    if (start_cpu >= max_id - ncpus)
        id = max_id - 1;
    else
16030
        id = start_cpu + ncpus - 1;
16031

16032
    for (i = 0; i <= id; i++) {
16033
        if (virStrToLong_ull(pos, &pos, 10, &cpu_time) < 0) {
16034
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
16035
                           _("cpuacct parse error"));
16036
            goto cleanup;
16037 16038
        } else {
            n++;
16039 16040 16041
        }
        if (i < start_cpu)
            continue;
16042
        ent = &params[(i - start_cpu) * nparams + param_idx];
E
Eric Blake 已提交
16043 16044 16045
        if (virTypedParameterAssign(ent, VIR_DOMAIN_CPU_STATS_CPUTIME,
                                    VIR_TYPED_PARAM_ULLONG, cpu_time) < 0)
            goto cleanup;
16046
    }
16047 16048 16049 16050 16051 16052 16053

    /* return percpu vcputime in index 1 */
    if (++param_idx >= nparams) {
        rv = nparams;
        goto cleanup;
    }

16054
    if (VIR_ALLOC_N(sum_cpu_time, n) < 0)
16055
        goto cleanup;
16056
    if (getSumVcpuPercpuStats(vm, sum_cpu_time, n) < 0)
16057 16058 16059
        goto cleanup;

    sum_cpu_pos = sum_cpu_time;
16060
    for (i = 0; i <= id; i++) {
16061
        cpu_time = *(sum_cpu_pos++);
16062 16063 16064 16065 16066 16067 16068 16069 16070 16071
        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;
    }

16072 16073
    rv = param_idx + 1;
cleanup:
16074
    VIR_FREE(sum_cpu_time);
16075 16076 16077 16078 16079 16080 16081
    VIR_FREE(buf);
    return rv;
}


static int
qemuDomainGetCPUStats(virDomainPtr domain,
16082 16083 16084 16085 16086
                      virTypedParameterPtr params,
                      unsigned int nparams,
                      int start_cpu,
                      unsigned int ncpus,
                      unsigned int flags)
16087 16088 16089 16090
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    bool isActive;
16091
    qemuDomainObjPrivatePtr priv;
16092 16093 16094

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

16095 16096
    if (!(vm = qemuDomObjFromDomain(domain)))
        return -1;
16097

16098 16099
    priv = vm->privateData;

16100 16101 16102
    if (virDomainGetCPUStatsEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

16103 16104
    isActive = virDomainObjIsActive(vm);
    if (!isActive) {
16105 16106
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
16107 16108 16109
        goto cleanup;
    }

16110
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUACCT)) {
16111 16112
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPUACCT controller is not mounted"));
16113 16114 16115 16116
        goto cleanup;
    }

    if (start_cpu == -1)
16117 16118
        ret = virCgroupGetDomainTotalCpuStats(priv->cgroup,
                                              params, nparams);
16119
    else
16120
        ret = qemuDomainGetPercpuStats(vm, params, nparams,
16121 16122 16123
                                       start_cpu, ncpus);
cleanup:
    if (vm)
16124
        virObjectUnlock(vm);
16125 16126 16127
    return ret;
}

16128 16129 16130 16131 16132 16133
static int
qemuDomainPMSuspendForDuration(virDomainPtr dom,
                               unsigned int target,
                               unsigned long long duration,
                               unsigned int flags)
{
16134
    virQEMUDriverPtr driver = dom->conn->privateData;
16135 16136 16137 16138 16139 16140 16141
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

    if (duration) {
16142 16143
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Duration not supported. Use 0 for now"));
16144 16145 16146 16147 16148 16149
        return -1;
    }

    if (!(target == VIR_NODE_SUSPEND_TARGET_MEM ||
          target == VIR_NODE_SUSPEND_TARGET_DISK ||
          target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
16150 16151 16152
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unknown suspend target: %u"),
                       target);
16153 16154 16155
        return -1;
    }

16156
    if (!(vm = qemuDomObjFromDomain(dom)))
16157 16158 16159 16160
        goto cleanup;

    priv = vm->privateData;

16161 16162 16163
    if (virDomainPMSuspendForDurationEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

16164
    if (!virDomainObjIsActive(vm)) {
16165 16166
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
16167 16168 16169
        goto cleanup;
    }

16170
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_WAKEUP) &&
16171 16172
        (target == VIR_NODE_SUSPEND_TARGET_MEM ||
         target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
16173 16174 16175
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Unable to suspend domain due to "
                         "missing system_wakeup monitor command"));
O
Osier Yang 已提交
16176
        goto cleanup;
16177 16178
    }

16179 16180 16181 16182 16183 16184 16185 16186 16187 16188 16189 16190 16191 16192 16193 16194 16195
    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;
        }
    }

16196
    if (priv->agentError) {
16197 16198 16199
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                       _("QEMU guest agent is not "
                         "available due to an error"));
16200 16201 16202 16203
        goto cleanup;
    }

    if (!priv->agent) {
16204 16205
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("QEMU guest agent is not configured"));
16206 16207 16208 16209 16210 16211 16212
        goto cleanup;
    }

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

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

16218
    qemuDomainObjEnterAgent(vm);
16219
    ret = qemuAgentSuspend(priv->agent, target);
16220
    qemuDomainObjExitAgent(vm);
16221 16222

endjob:
E
Eric Blake 已提交
16223
    if (!qemuDomainObjEndJob(driver, vm))
16224 16225 16226 16227
        vm = NULL;

cleanup:
    if (vm)
16228
        virObjectUnlock(vm);
16229 16230 16231
    return ret;
}

16232 16233 16234 16235
static int
qemuDomainPMWakeup(virDomainPtr dom,
                   unsigned int flags)
{
16236
    virQEMUDriverPtr driver = dom->conn->privateData;
16237 16238 16239 16240 16241 16242
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

16243
    if (!(vm = qemuDomObjFromDomain(dom)))
16244 16245
        goto cleanup;

16246 16247 16248
    if (virDomainPMWakeupEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

16249 16250 16251 16252
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
16253 16254
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
16255 16256 16257 16258 16259
        goto endjob;
    }

    priv = vm->privateData;

16260
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_WAKEUP)) {
16261 16262 16263
       virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                      _("Unable to wake up domain due to "
                        "missing system_wakeup monitor command"));
16264 16265 16266 16267 16268 16269 16270 16271
       goto endjob;
    }

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

endjob:
E
Eric Blake 已提交
16272
    if (!qemuDomainObjEndJob(driver, vm))
16273 16274 16275 16276
        vm = NULL;

cleanup:
    if (vm)
16277
        virObjectUnlock(vm);
16278 16279 16280
    return ret;
}

16281
static int
16282 16283 16284
qemuConnectListAllDomains(virConnectPtr conn,
                          virDomainPtr **domains,
                          unsigned int flags)
16285
{
16286
    virQEMUDriverPtr driver = conn->privateData;
16287 16288
    int ret = -1;

O
Osier Yang 已提交
16289
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
16290

16291 16292 16293
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        goto cleanup;

16294 16295
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
16296

16297
cleanup:
16298 16299 16300
    return ret;
}

M
MATSUDA Daiki 已提交
16301
static char *
16302 16303 16304 16305
qemuDomainQemuAgentCommand(virDomainPtr domain,
                           const char *cmd,
                           int timeout,
                           unsigned int flags)
M
MATSUDA Daiki 已提交
16306
{
16307
    virQEMUDriverPtr driver = domain->conn->privateData;
M
MATSUDA Daiki 已提交
16308 16309 16310 16311 16312 16313 16314
    virDomainObjPtr vm;
    int ret = -1;
    char *result = NULL;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, NULL);

16315
    if (!(vm = qemuDomObjFromDomain(domain)))
M
MATSUDA Daiki 已提交
16316 16317 16318 16319
        goto cleanup;

    priv = vm->privateData;

16320 16321 16322
    if (virDomainQemuAgentCommandEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

M
MATSUDA Daiki 已提交
16323 16324 16325 16326 16327 16328 16329
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto cleanup;
    }

    if (priv->agentError) {
16330 16331 16332
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                       _("QEMU guest agent is not "
                         "available due to an error"));
M
MATSUDA Daiki 已提交
16333 16334 16335 16336 16337 16338 16339 16340 16341 16342 16343 16344 16345 16346 16347 16348 16349 16350
        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;
    }

16351
    qemuDomainObjEnterAgent(vm);
M
MATSUDA Daiki 已提交
16352
    ret = qemuAgentArbitraryCommand(priv->agent, cmd, &result, timeout);
16353
    qemuDomainObjExitAgent(vm);
16354 16355
    if (ret < 0)
        VIR_FREE(result);
M
MATSUDA Daiki 已提交
16356 16357

endjob:
E
Eric Blake 已提交
16358
    if (!qemuDomainObjEndJob(driver, vm))
M
MATSUDA Daiki 已提交
16359 16360 16361 16362
        vm = NULL;

cleanup:
    if (vm)
16363
        virObjectUnlock(vm);
M
MATSUDA Daiki 已提交
16364 16365 16366
    return result;
}

M
Michal Privoznik 已提交
16367 16368 16369 16370 16371 16372
static int
qemuDomainFSTrim(virDomainPtr dom,
                 const char *mountPoint,
                 unsigned long long minimum,
                 unsigned int flags)
{
16373
    virQEMUDriverPtr driver = dom->conn->privateData;
M
Michal Privoznik 已提交
16374 16375 16376 16377 16378 16379 16380 16381 16382 16383 16384 16385 16386 16387 16388 16389 16390 16391
    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;

16392 16393 16394
    if (virDomainFSTrimEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

M
Michal Privoznik 已提交
16395 16396 16397 16398 16399 16400 16401 16402 16403 16404 16405 16406 16407 16408 16409 16410 16411 16412 16413 16414 16415 16416 16417 16418 16419 16420 16421 16422
    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;
    }

16423
    qemuDomainObjEnterAgent(vm);
M
Michal Privoznik 已提交
16424
    ret = qemuAgentFSTrim(priv->agent, minimum);
16425
    qemuDomainObjExitAgent(vm);
M
Michal Privoznik 已提交
16426 16427

endjob:
E
Eric Blake 已提交
16428
    if (!qemuDomainObjEndJob(driver, vm))
M
Michal Privoznik 已提交
16429 16430 16431 16432
        vm = NULL;

cleanup:
    if (vm)
16433
        virObjectUnlock(vm);
M
Michal Privoznik 已提交
16434 16435 16436
    return ret;
}

16437 16438

static int
16439
qemuNodeGetInfo(virConnectPtr conn,
16440 16441
                virNodeInfoPtr nodeinfo)
{
16442 16443 16444
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

16445 16446 16447 16448 16449
    return nodeGetInfo(nodeinfo);
}


static int
16450
qemuNodeGetCPUStats(virConnectPtr conn,
16451 16452 16453 16454 16455
                    int cpuNum,
                    virNodeCPUStatsPtr params,
                    int *nparams,
                    unsigned int flags)
{
16456 16457 16458
    if (virNodeGetCPUStatsEnsureACL(conn) < 0)
        return -1;

16459 16460 16461 16462 16463
    return nodeGetCPUStats(cpuNum, params, nparams, flags);
}


static int
16464
qemuNodeGetMemoryStats(virConnectPtr conn,
16465 16466 16467 16468 16469
                       int cellNum,
                       virNodeMemoryStatsPtr params,
                       int *nparams,
                       unsigned int flags)
{
16470 16471 16472
    if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
        return -1;

16473 16474 16475 16476 16477
    return nodeGetMemoryStats(cellNum, params, nparams, flags);
}


static int
16478
qemuNodeGetCellsFreeMemory(virConnectPtr conn,
16479 16480 16481 16482
                           unsigned long long *freeMems,
                           int startCell,
                           int maxCells)
{
16483 16484 16485
    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
        return -1;

16486 16487 16488 16489 16490
    return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}


static unsigned long long
16491
qemuNodeGetFreeMemory(virConnectPtr conn)
16492
{
16493 16494 16495
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
        return 0;

16496 16497 16498 16499 16500
    return nodeGetFreeMemory();
}


static int
16501
qemuNodeGetMemoryParameters(virConnectPtr conn,
16502 16503 16504 16505
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
{
16506 16507 16508
    if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
        return -1;

16509 16510 16511 16512 16513
    return nodeGetMemoryParameters(params, nparams, flags);
}


static int
16514
qemuNodeSetMemoryParameters(virConnectPtr conn,
16515 16516 16517 16518
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
{
16519 16520 16521
    if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
        return -1;

16522 16523 16524 16525 16526
    return nodeSetMemoryParameters(params, nparams, flags);
}


static int
16527
qemuNodeGetCPUMap(virConnectPtr conn,
16528 16529 16530 16531
                  unsigned char **cpumap,
                  unsigned int *online,
                  unsigned int flags)
{
16532 16533 16534
    if (virNodeGetCPUMapEnsureACL(conn) < 0)
        return -1;

16535 16536 16537
    return nodeGetCPUMap(cpumap, online, flags);
}

16538 16539

static int
16540
qemuNodeSuspendForDuration(virConnectPtr conn,
16541 16542 16543 16544
                           unsigned int target,
                           unsigned long long duration,
                           unsigned int flags)
{
16545 16546 16547
    if (virNodeSuspendForDurationEnsureACL(conn) < 0)
        return -1;

16548 16549 16550
    return nodeSuspendForDuration(target, duration, flags);
}

16551 16552 16553 16554 16555 16556 16557 16558 16559 16560 16561 16562 16563
static int
qemuConnectGetCPUModelNames(virConnectPtr conn,
                            const char *arch,
                            char ***models,
                            unsigned int flags)
{
    virCheckFlags(0, -1);
    if (virConnectGetCPUModelNamesEnsureACL(conn) < 0)
        return -1;

    return cpuGetModels(arch, models);
}

16564

16565
static virDriver qemuDriver = {
16566
    .no = VIR_DRV_QEMU,
16567
    .name = QEMU_DRIVER_NAME,
16568 16569 16570 16571 16572
    .connectOpen = qemuConnectOpen, /* 0.2.0 */
    .connectClose = qemuConnectClose, /* 0.2.0 */
    .connectSupportsFeature = qemuConnectSupportsFeature, /* 0.5.0 */
    .connectGetType = qemuConnectGetType, /* 0.2.0 */
    .connectGetVersion = qemuConnectGetVersion, /* 0.2.0 */
16573
    .connectGetHostname = qemuConnectGetHostname, /* 0.3.3 */
16574 16575
    .connectGetSysinfo = qemuConnectGetSysinfo, /* 0.8.8 */
    .connectGetMaxVcpus = qemuConnectGetMaxVcpus, /* 0.2.1 */
16576
    .nodeGetInfo = qemuNodeGetInfo, /* 0.2.0 */
16577 16578 16579 16580 16581
    .connectGetCapabilities = qemuConnectGetCapabilities, /* 0.2.1 */
    .connectListDomains = qemuConnectListDomains, /* 0.2.0 */
    .connectNumOfDomains = qemuConnectNumOfDomains, /* 0.2.0 */
    .connectListAllDomains = qemuConnectListAllDomains, /* 0.9.13 */
    .domainCreateXML = qemuDomainCreateXML, /* 0.2.0 */
16582 16583 16584 16585 16586
    .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 */
16587
    .domainShutdown = qemuDomainShutdown, /* 0.2.0 */
16588
    .domainShutdownFlags = qemuDomainShutdownFlags, /* 0.9.10 */
16589
    .domainReboot = qemuDomainReboot, /* 0.9.3 */
16590
    .domainReset = qemuDomainReset, /* 0.9.7 */
16591 16592
    .domainDestroy = qemuDomainDestroy, /* 0.2.0 */
    .domainDestroyFlags = qemuDomainDestroyFlags, /* 0.9.4 */
16593
    .domainGetOSType = qemuDomainGetOSType, /* 0.2.2 */
16594
    .domainGetMaxMemory = qemuDomainGetMaxMemory, /* 0.4.2 */
16595 16596 16597
    .domainSetMaxMemory = qemuDomainSetMaxMemory, /* 0.4.2 */
    .domainSetMemory = qemuDomainSetMemory, /* 0.4.2 */
    .domainSetMemoryFlags = qemuDomainSetMemoryFlags, /* 0.9.0 */
16598 16599
    .domainSetMemoryParameters = qemuDomainSetMemoryParameters, /* 0.8.5 */
    .domainGetMemoryParameters = qemuDomainGetMemoryParameters, /* 0.8.5 */
16600
    .domainSetMemoryStatsPeriod = qemuDomainSetMemoryStatsPeriod, /* 1.1.1 */
16601 16602
    .domainSetBlkioParameters = qemuDomainSetBlkioParameters, /* 0.9.0 */
    .domainGetBlkioParameters = qemuDomainGetBlkioParameters, /* 0.9.0 */
16603
    .domainGetInfo = qemuDomainGetInfo, /* 0.2.0 */
16604
    .domainGetState = qemuDomainGetState, /* 0.9.2 */
16605
    .domainGetControlInfo = qemuDomainGetControlInfo, /* 0.9.3 */
16606 16607
    .domainSave = qemuDomainSave, /* 0.2.0 */
    .domainSaveFlags = qemuDomainSaveFlags, /* 0.9.4 */
16608
    .domainRestore = qemuDomainRestore, /* 0.2.0 */
16609
    .domainRestoreFlags = qemuDomainRestoreFlags, /* 0.9.4 */
16610 16611
    .domainSaveImageGetXMLDesc = qemuDomainSaveImageGetXMLDesc, /* 0.9.4 */
    .domainSaveImageDefineXML = qemuDomainSaveImageDefineXML, /* 0.9.4 */
16612
    .domainCoreDump = qemuDomainCoreDump, /* 0.7.0 */
16613
    .domainScreenshot = qemuDomainScreenshot, /* 0.9.2 */
16614 16615
    .domainSetVcpus = qemuDomainSetVcpus, /* 0.4.4 */
    .domainSetVcpusFlags = qemuDomainSetVcpusFlags, /* 0.8.5 */
16616 16617 16618 16619 16620 16621 16622 16623 16624
    .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 已提交
16625
    .domainGetSecurityLabelList = qemuDomainGetSecurityLabelList, /* 0.10.0 */
16626
    .nodeGetSecurityModel = qemuNodeGetSecurityModel, /* 0.6.1 */
16627
    .domainGetXMLDesc = qemuDomainGetXMLDesc, /* 0.2.0 */
16628 16629 16630 16631 16632 16633 16634
    .connectDomainXMLFromNative = qemuConnectDomainXMLFromNative, /* 0.6.4 */
    .connectDomainXMLToNative = qemuConnectDomainXMLToNative, /* 0.6.4 */
    .connectListDefinedDomains = qemuConnectListDefinedDomains, /* 0.2.0 */
    .connectNumOfDefinedDomains = qemuConnectNumOfDefinedDomains, /* 0.2.0 */
    .domainCreate = qemuDomainCreate, /* 0.2.0 */
    .domainCreateWithFlags = qemuDomainCreateWithFlags, /* 0.8.2 */
    .domainDefineXML = qemuDomainDefineXML, /* 0.2.0 */
16635
    .domainUndefine = qemuDomainUndefine, /* 0.2.0 */
16636
    .domainUndefineFlags = qemuDomainUndefineFlags, /* 0.9.4 */
16637 16638 16639 16640 16641
    .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 */
16642 16643
    .domainGetAutostart = qemuDomainGetAutostart, /* 0.2.1 */
    .domainSetAutostart = qemuDomainSetAutostart, /* 0.2.1 */
16644 16645 16646 16647 16648
    .domainGetSchedulerType = qemuDomainGetSchedulerType, /* 0.7.0 */
    .domainGetSchedulerParameters = qemuDomainGetSchedulerParameters, /* 0.7.0 */
    .domainGetSchedulerParametersFlags = qemuDomainGetSchedulerParametersFlags, /* 0.9.2 */
    .domainSetSchedulerParameters = qemuDomainSetSchedulerParameters, /* 0.7.0 */
    .domainSetSchedulerParametersFlags = qemuDomainSetSchedulerParametersFlags, /* 0.9.2 */
16649
    .domainMigratePerform = qemuDomainMigratePerform, /* 0.5.0 */
16650
    .domainBlockResize = qemuDomainBlockResize, /* 0.9.8 */
16651 16652
    .domainBlockStats = qemuDomainBlockStats, /* 0.4.1 */
    .domainBlockStatsFlags = qemuDomainBlockStatsFlags, /* 0.9.5 */
16653 16654 16655 16656
    .domainInterfaceStats = qemuDomainInterfaceStats, /* 0.4.1 */
    .domainMemoryStats = qemuDomainMemoryStats, /* 0.7.5 */
    .domainBlockPeek = qemuDomainBlockPeek, /* 0.4.4 */
    .domainMemoryPeek = qemuDomainMemoryPeek, /* 0.4.4 */
16657
    .domainGetBlockInfo = qemuDomainGetBlockInfo, /* 0.8.1 */
16658 16659 16660 16661
    .nodeGetCPUStats = qemuNodeGetCPUStats, /* 0.9.3 */
    .nodeGetMemoryStats = qemuNodeGetMemoryStats, /* 0.9.3 */
    .nodeGetCellsFreeMemory = qemuNodeGetCellsFreeMemory, /* 0.4.4 */
    .nodeGetFreeMemory = qemuNodeGetFreeMemory, /* 0.4.4 */
16662 16663
    .connectDomainEventRegister = qemuConnectDomainEventRegister, /* 0.5.0 */
    .connectDomainEventDeregister = qemuConnectDomainEventDeregister, /* 0.5.0 */
16664 16665 16666
    .domainMigratePrepare2 = qemuDomainMigratePrepare2, /* 0.5.0 */
    .domainMigrateFinish2 = qemuDomainMigrateFinish2, /* 0.5.0 */
    .nodeDeviceDettach = qemuNodeDeviceDettach, /* 0.6.1 */
16667
    .nodeDeviceDetachFlags = qemuNodeDeviceDetachFlags, /* 1.0.5 */
16668 16669 16670
    .nodeDeviceReAttach = qemuNodeDeviceReAttach, /* 0.6.1 */
    .nodeDeviceReset = qemuNodeDeviceReset, /* 0.6.1 */
    .domainMigratePrepareTunnel = qemuDomainMigratePrepareTunnel, /* 0.7.2 */
16671 16672
    .connectIsEncrypted = qemuConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = qemuConnectIsSecure, /* 0.7.3 */
16673 16674 16675
    .domainIsActive = qemuDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = qemuDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = qemuDomainIsUpdated, /* 0.8.6 */
16676 16677
    .connectCompareCPU = qemuConnectCompareCPU, /* 0.7.5 */
    .connectBaselineCPU = qemuConnectBaselineCPU, /* 0.7.7 */
16678
    .domainGetJobInfo = qemuDomainGetJobInfo, /* 0.7.7 */
16679
    .domainGetJobStats = qemuDomainGetJobStats, /* 1.0.3 */
16680 16681
    .domainAbortJob = qemuDomainAbortJob, /* 0.7.7 */
    .domainMigrateSetMaxDowntime = qemuDomainMigrateSetMaxDowntime, /* 0.8.0 */
16682 16683
    .domainMigrateGetCompressionCache = qemuDomainMigrateGetCompressionCache, /* 1.0.3 */
    .domainMigrateSetCompressionCache = qemuDomainMigrateSetCompressionCache, /* 1.0.3 */
16684
    .domainMigrateSetMaxSpeed = qemuDomainMigrateSetMaxSpeed, /* 0.9.0 */
16685
    .domainMigrateGetMaxSpeed = qemuDomainMigrateGetMaxSpeed, /* 0.9.5 */
16686 16687
    .connectDomainEventRegisterAny = qemuConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = qemuConnectDomainEventDeregisterAny, /* 0.8.0 */
16688 16689 16690 16691 16692 16693 16694
    .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 */
16695
    .domainListAllSnapshots = qemuDomainListAllSnapshots, /* 0.9.13 */
16696 16697
    .domainSnapshotNumChildren = qemuDomainSnapshotNumChildren, /* 0.9.7 */
    .domainSnapshotListChildrenNames = qemuDomainSnapshotListChildrenNames, /* 0.9.7 */
16698
    .domainSnapshotListAllChildren = qemuDomainSnapshotListAllChildren, /* 0.9.13 */
16699 16700
    .domainSnapshotLookupByName = qemuDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = qemuDomainHasCurrentSnapshot, /* 0.8.0 */
16701
    .domainSnapshotGetParent = qemuDomainSnapshotGetParent, /* 0.9.7 */
16702
    .domainSnapshotCurrent = qemuDomainSnapshotCurrent, /* 0.8.0 */
16703 16704
    .domainSnapshotIsCurrent = qemuDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = qemuDomainSnapshotHasMetadata, /* 0.9.13 */
16705 16706
    .domainRevertToSnapshot = qemuDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = qemuDomainSnapshotDelete, /* 0.8.0 */
16707 16708 16709
    .domainQemuMonitorCommand = qemuDomainQemuMonitorCommand, /* 0.8.3 */
    .domainQemuAttach = qemuDomainQemuAttach, /* 0.9.4 */
    .domainQemuAgentCommand = qemuDomainQemuAgentCommand, /* 0.10.0 */
16710
    .domainOpenConsole = qemuDomainOpenConsole, /* 0.8.6 */
16711
    .domainOpenGraphics = qemuDomainOpenGraphics, /* 0.9.7 */
16712
    .domainInjectNMI = qemuDomainInjectNMI, /* 0.9.2 */
16713 16714 16715 16716 16717 16718
    .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 */
16719
    .domainSendKey = qemuDomainSendKey, /* 0.9.4 */
16720 16721 16722 16723
    .domainBlockJobAbort = qemuDomainBlockJobAbort, /* 0.9.4 */
    .domainGetBlockJobInfo = qemuDomainGetBlockJobInfo, /* 0.9.4 */
    .domainBlockJobSetSpeed = qemuDomainBlockJobSetSpeed, /* 0.9.4 */
    .domainBlockPull = qemuDomainBlockPull, /* 0.9.4 */
16724
    .domainBlockRebase = qemuDomainBlockRebase, /* 0.9.10 */
16725
    .domainBlockCommit = qemuDomainBlockCommit, /* 1.0.0 */
16726
    .connectIsAlive = qemuConnectIsAlive, /* 0.9.8 */
16727
    .nodeSuspendForDuration = qemuNodeSuspendForDuration, /* 0.9.8 */
16728 16729
    .domainSetBlockIoTune = qemuDomainSetBlockIoTune, /* 0.9.8 */
    .domainGetBlockIoTune = qemuDomainGetBlockIoTune, /* 0.9.8 */
16730 16731
    .domainSetNumaParameters = qemuDomainSetNumaParameters, /* 0.9.9 */
    .domainGetNumaParameters = qemuDomainGetNumaParameters, /* 0.9.9 */
16732 16733
    .domainGetInterfaceParameters = qemuDomainGetInterfaceParameters, /* 0.9.9 */
    .domainSetInterfaceParameters = qemuDomainSetInterfaceParameters, /* 0.9.9 */
16734
    .domainGetDiskErrors = qemuDomainGetDiskErrors, /* 0.9.10 */
16735 16736
    .domainSetMetadata = qemuDomainSetMetadata, /* 0.9.10 */
    .domainGetMetadata = qemuDomainGetMetadata, /* 0.9.10 */
16737
    .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */
16738
    .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */
16739
    .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */
16740 16741 16742
    .nodeGetMemoryParameters = qemuNodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = qemuNodeSetMemoryParameters, /* 0.10.2 */
    .nodeGetCPUMap = qemuNodeGetCPUMap, /* 1.0.0 */
M
Michal Privoznik 已提交
16743
    .domainFSTrim = qemuDomainFSTrim, /* 1.0.1 */
16744
    .domainOpenChannel = qemuDomainOpenChannel, /* 1.0.2 */
16745 16746 16747 16748 16749 16750
    .domainMigrateBegin3Params = qemuDomainMigrateBegin3Params, /* 1.1.0 */
    .domainMigratePrepare3Params = qemuDomainMigratePrepare3Params, /* 1.1.0 */
    .domainMigratePrepareTunnel3Params = qemuDomainMigratePrepareTunnel3Params, /* 1.1.0 */
    .domainMigratePerform3Params = qemuDomainMigratePerform3Params, /* 1.1.0 */
    .domainMigrateFinish3Params = qemuDomainMigrateFinish3Params, /* 1.1.0 */
    .domainMigrateConfirm3Params = qemuDomainMigrateConfirm3Params, /* 1.1.0 */
16751
    .connectGetCPUModelNames = qemuConnectGetCPUModelNames, /* 1.1.3 */
16752 16753 16754
};


16755
static virStateDriver qemuStateDriver = {
16756
    .name = "QEMU",
16757
    .stateInitialize = qemuStateInitialize,
16758
    .stateAutoStart = qemuStateAutoStart,
16759 16760 16761
    .stateCleanup = qemuStateCleanup,
    .stateReload = qemuStateReload,
    .stateStop = qemuStateStop,
16762
};
16763

16764
int qemuRegister(void) {
16765 16766 16767 16768
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
    return 0;
}