qemu_driver.c 531.8 KB
Newer Older
D
Daniel P. Berrange 已提交
1
/*
2
 * qemu_driver.c: core driver methods for managing qemu guests
D
Daniel P. Berrange 已提交
3
 *
4
 * Copyright (C) 2006-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

98 99
#define VIR_FROM_THIS VIR_FROM_QEMU

100 101
#define QEMU_DRIVER_NAME "QEMU"

102 103
#define QEMU_NB_MEM_PARAM  3

104 105
#define QEMU_NB_BLOCK_IO_TUNE_PARAM  6

106 107
#define QEMU_NB_NUMA_PARAM 2

E
Eric Blake 已提交
108
#define QEMU_NB_TOTAL_CPU_STAT_PARAM 3
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 2248 2249
    } else {
        /* resize the current memory */

        if (newmem > vm->def->mem.max_balloon) {
2250 2251
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("cannot set memory higher than max memory"));
2252 2253 2254
            goto endjob;
        }

2255
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
2256
            priv = vm->privateData;
2257
            qemuDomainObjEnterMonitor(driver, vm);
2258
            r = qemuMonitorSetBalloon(priv->mon, newmem);
2259
            qemuDomainObjExitMonitor(driver, vm);
2260 2261
            virDomainAuditMemory(vm, vm->def->mem.cur_balloon, newmem, "update",
                                 r == 1);
2262 2263 2264 2265 2266
            if (r < 0)
                goto endjob;

            /* Lack of balloon support is a fatal error */
            if (r == 0) {
2267 2268 2269
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("Unable to change memory of active domain without "
                                 "the balloon device and guest OS balloon driver"));
2270 2271 2272 2273
                goto endjob;
            }
        }

2274
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
2275
            sa_assert(persistentDef);
2276
            persistentDef->mem.cur_balloon = newmem;
2277
            ret = virDomainSaveConfig(cfg->configDir, persistentDef);
2278 2279
            goto endjob;
        }
2280
    }
2281

2282
    ret = 0;
2283
endjob:
E
Eric Blake 已提交
2284
    if (!qemuDomainObjEndJob(driver, vm))
2285
        vm = NULL;
2286

2287
cleanup:
2288
    if (vm)
2289
        virObjectUnlock(vm);
2290
    virObjectUnref(caps);
2291
    virObjectUnref(cfg);
2292
    return ret;
2293 2294
}

2295
static int qemuDomainSetMemory(virDomainPtr dom, unsigned long newmem)
2296
{
2297
    return qemuDomainSetMemoryFlags(dom, newmem, VIR_DOMAIN_AFFECT_LIVE);
2298 2299
}

2300
static int qemuDomainSetMaxMemory(virDomainPtr dom, unsigned long memory)
2301
{
2302
    return qemuDomainSetMemoryFlags(dom, memory, VIR_DOMAIN_MEM_MAXIMUM);
2303 2304
}

2305 2306 2307 2308 2309 2310 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
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 已提交
2358
    if (!qemuDomainObjEndJob(driver, vm))
2359 2360 2361 2362 2363 2364 2365 2366 2367 2368
        vm = NULL;

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

2369 2370
static int qemuDomainInjectNMI(virDomainPtr domain, unsigned int flags)
{
2371
    virQEMUDriverPtr driver = domain->conn->privateData;
2372 2373 2374 2375 2376 2377
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2378 2379
    if (!(vm = qemuDomObjFromDomain(domain)))
        return -1;
2380

2381 2382 2383
    if (virDomainInjectNMIEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

2384
    if (!virDomainObjIsActive(vm)) {
2385 2386
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2387 2388 2389 2390 2391
        goto cleanup;
    }

    priv = vm->privateData;

2392
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
2393
        goto cleanup;
2394 2395

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

2401
    qemuDomainObjEnterMonitor(driver, vm);
2402
    ret = qemuMonitorInjectNMI(priv->mon);
2403
    qemuDomainObjExitMonitor(driver, vm);
2404 2405

endjob:
E
Eric Blake 已提交
2406
    if (!qemuDomainObjEndJob(driver, vm))
2407 2408 2409 2410
        vm = NULL;

cleanup:
    if (vm)
2411
        virObjectUnlock(vm);
2412 2413 2414
    return ret;
}

2415 2416 2417 2418 2419 2420 2421
static int qemuDomainSendKey(virDomainPtr domain,
                             unsigned int codeset,
                             unsigned int holdtime,
                             unsigned int *keycodes,
                             int nkeycodes,
                             unsigned int flags)
{
2422
    virQEMUDriverPtr driver = domain->conn->privateData;
2423 2424 2425 2426 2427 2428
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

2429 2430
    /* translate the keycode to RFB for qemu driver */
    if (codeset != VIR_KEYCODE_SET_RFB) {
2431
        size_t i;
2432 2433 2434
        int keycode;

        for (i = 0; i < nkeycodes; i++) {
2435
            keycode = virKeycodeValueTranslate(codeset, VIR_KEYCODE_SET_RFB,
2436 2437
                                               keycodes[i]);
            if (keycode < 0) {
2438 2439 2440 2441
                virReportError(VIR_ERR_INTERNAL_ERROR,
                               _("cannot translate keycode %u of %s codeset to rfb keycode"),
                               keycodes[i],
                               virKeycodeSetTypeToString(codeset));
2442 2443 2444 2445 2446 2447
                return -1;
            }
            keycodes[i] = keycode;
        }
    }

2448
    if (!(vm = qemuDomObjFromDomain(domain)))
2449 2450 2451 2452
        goto cleanup;

    priv = vm->privateData;

2453 2454 2455
    if (virDomainSendKeyEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

2456
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
2457 2458 2459
        goto cleanup;

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

2465
    qemuDomainObjEnterMonitor(driver, vm);
2466
    ret = qemuMonitorSendKey(priv->mon, holdtime, keycodes, nkeycodes);
2467
    qemuDomainObjExitMonitor(driver, vm);
2468 2469

endjob:
E
Eric Blake 已提交
2470
    if (!qemuDomainObjEndJob(driver, vm))
2471 2472 2473 2474
        vm = NULL;

cleanup:
    if (vm)
2475
        virObjectUnlock(vm);
2476 2477 2478
    return ret;
}

2479 2480
static int qemuDomainGetInfo(virDomainPtr dom,
                             virDomainInfoPtr info)
2481
{
2482
    virQEMUDriverPtr driver = dom->conn->privateData;
2483 2484
    virDomainObjPtr vm;
    int ret = -1;
2485
    int err;
2486
    unsigned long long balloon;
2487

2488
    if (!(vm = qemuDomObjFromDomain(dom)))
2489
        goto cleanup;
D
Daniel P. Berrange 已提交
2490

2491 2492 2493
    if (virDomainGetInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

D
Daniel P. Berrange 已提交
2496
    if (!virDomainObjIsActive(vm)) {
2497
        info->cpuTime = 0;
D
Daniel P. Berrange 已提交
2498
    } else {
2499
        if (qemuGetProcessInfo(&(info->cpuTime), NULL, NULL, vm->pid, 0) < 0) {
2500 2501
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("cannot read cputime for domain"));
2502
            goto cleanup;
D
Daniel P. Berrange 已提交
2503 2504 2505
        }
    }

2506
    info->maxMem = vm->def->mem.max_balloon;
2507

D
Daniel P. Berrange 已提交
2508
    if (virDomainObjIsActive(vm)) {
2509
        qemuDomainObjPrivatePtr priv = vm->privateData;
2510 2511 2512

        if ((vm->def->memballoon != NULL) &&
            (vm->def->memballoon->model == VIR_DOMAIN_MEMBALLOON_MODEL_NONE)) {
2513
            info->memory = vm->def->mem.max_balloon;
2514
        } else if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT)) {
2515
            info->memory = vm->def->mem.cur_balloon;
2516
        } else if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
2517
            if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
2518
                goto cleanup;
2519 2520 2521
            if (!virDomainObjIsActive(vm))
                err = 0;
            else {
2522
                qemuDomainObjEnterMonitor(driver, vm);
2523
                err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
2524
                qemuDomainObjExitMonitor(driver, vm);
2525
            }
E
Eric Blake 已提交
2526
            if (!qemuDomainObjEndJob(driver, vm)) {
2527
                vm = NULL;
2528 2529 2530
                goto cleanup;
            }

2531 2532 2533 2534 2535 2536 2537
            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) {
2538
                /* Balloon not supported, so maxmem is always the allocation */
2539
                info->memory = vm->def->mem.max_balloon;
2540
            } else {
2541
                info->memory = balloon;
2542
            }
2543
        } else {
2544
            info->memory = vm->def->mem.cur_balloon;
2545
        }
2546
    } else {
2547
        info->memory = vm->def->mem.cur_balloon;
2548 2549
    }

2550
    info->nrVirtCpu = vm->def->vcpus;
2551 2552 2553
    ret = 0;

cleanup:
2554
    if (vm)
2555
        virObjectUnlock(vm);
2556
    return ret;
D
Daniel P. Berrange 已提交
2557 2558
}

2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569
static int
qemuDomainGetState(virDomainPtr dom,
                   int *state,
                   int *reason,
                   unsigned int flags)
{
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

2570
    if (!(vm = qemuDomObjFromDomain(dom)))
2571 2572
        goto cleanup;

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

J
Jiri Denemark 已提交
2576
    *state = virDomainObjGetState(vm, reason);
2577 2578 2579 2580
    ret = 0;

cleanup:
    if (vm)
2581
        virObjectUnlock(vm);
2582 2583 2584
    return ret;
}

2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595
static int
qemuDomainGetControlInfo(virDomainPtr dom,
                          virDomainControlInfoPtr info,
                          unsigned int flags)
{
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

2596
    if (!(vm = qemuDomObjFromDomain(dom)))
2597 2598
        goto cleanup;

2599 2600 2601
    if (virDomainGetControlInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

2602
    if (!virDomainObjIsActive(vm)) {
2603 2604
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
2605 2606 2607 2608 2609 2610 2611 2612 2613
        goto cleanup;
    }

    priv = vm->privateData;

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

    if (priv->monError) {
        info->state = VIR_DOMAIN_CONTROL_ERROR;
2614
    } else if (priv->job.active) {
2615 2616
        if (!priv->monStart) {
            info->state = VIR_DOMAIN_CONTROL_JOB;
2617
            if (virTimeMillisNow(&info->stateTime) < 0)
2618
                goto cleanup;
2619
            info->stateTime -= priv->job.start;
2620 2621
        } else {
            info->state = VIR_DOMAIN_CONTROL_OCCUPIED;
2622
            if (virTimeMillisNow(&info->stateTime) < 0)
2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633
                goto cleanup;
            info->stateTime -= priv->monStart;
        }
    } else {
        info->state = VIR_DOMAIN_CONTROL_OK;
    }

    ret = 0;

cleanup:
    if (vm)
2634
        virObjectUnlock(vm);
2635 2636 2637
    return ret;
}

D
Daniel P. Berrange 已提交
2638

2639 2640 2641 2642 2643 2644
/* 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
2645

2646
verify(sizeof(QEMU_SAVE_MAGIC) == sizeof(QEMU_SAVE_PARTIAL));
E
Eric Blake 已提交
2647

2648
typedef enum {
2649 2650 2651
    QEMU_SAVE_FORMAT_RAW = 0,
    QEMU_SAVE_FORMAT_GZIP = 1,
    QEMU_SAVE_FORMAT_BZIP2 = 2,
2652 2653
    /*
     * Deprecated by xz and never used as part of a release
2654
     * QEMU_SAVE_FORMAT_LZMA
2655
     */
2656 2657
    QEMU_SAVE_FORMAT_XZ = 3,
    QEMU_SAVE_FORMAT_LZOP = 4,
2658 2659 2660
    /* Note: add new members only at the end.
       These values are used in the on-disk format.
       Do not change or re-use numbers. */
2661

2662
    QEMU_SAVE_FORMAT_LAST
2663
} virQEMUSaveFormat;
2664

2665 2666
VIR_ENUM_DECL(qemuSaveCompression)
VIR_ENUM_IMPL(qemuSaveCompression, QEMU_SAVE_FORMAT_LAST,
2667 2668 2669
              "raw",
              "gzip",
              "bzip2",
2670 2671
              "xz",
              "lzop")
2672

2673 2674 2675
typedef struct _virQEMUSaveHeader virQEMUSaveHeader;
typedef virQEMUSaveHeader *virQEMUSaveHeaderPtr;
struct _virQEMUSaveHeader {
2676
    char magic[sizeof(QEMU_SAVE_MAGIC)-1];
2677 2678 2679 2680 2681
    uint32_t version;
    uint32_t xml_len;
    uint32_t was_running;
    uint32_t compressed;
    uint32_t unused[15];
2682 2683
};

2684
static inline void
2685
bswap_header(virQEMUSaveHeaderPtr hdr) {
2686 2687 2688 2689 2690 2691 2692
    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);
}


2693
/* return -errno on failure, or 0 on success */
E
Eric Blake 已提交
2694
static int
2695
qemuDomainSaveHeader(int fd, const char *path, const char *xml,
2696
                     virQEMUSaveHeaderPtr header)
E
Eric Blake 已提交
2697
{
2698 2699
    int ret = 0;

E
Eric Blake 已提交
2700
    if (safewrite(fd, header, sizeof(*header)) != sizeof(*header)) {
2701
        ret = -errno;
2702 2703 2704
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to write header to domain save file '%s'"),
                       path);
2705 2706 2707
        goto endjob;
    }

E
Eric Blake 已提交
2708
    if (safewrite(fd, xml, header->xml_len) != header->xml_len) {
2709
        ret = -errno;
2710 2711
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("failed to write xml to '%s'"), path);
2712 2713 2714 2715 2716 2717
        goto endjob;
    }
endjob:
    return ret;
}

2718
/* Given a virQEMUSaveFormat compression level, return the name
2719 2720 2721 2722
 * of the program to run, or NULL if no program is needed.  */
static const char *
qemuCompressProgramName(int compress)
{
2723 2724
    return (compress == QEMU_SAVE_FORMAT_RAW ? NULL :
            qemuSaveCompressionTypeToString(compress));
2725 2726
}

2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753
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 已提交
2754
/* Internal function to properly create or open existing files, with
2755
 * ownership affected by qemu driver setup and domain DAC label.  */
E
Eric Blake 已提交
2756
static int
2757 2758 2759
qemuOpenFile(virQEMUDriverPtr driver,
             virDomainObjPtr vm,
             const char *path, int oflags,
E
Eric Blake 已提交
2760
             bool *needUnlink, bool *bypassSecurityDriver)
2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788
{
    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 已提交
2789 2790 2791 2792 2793
{
    struct stat sb;
    bool is_reg = true;
    bool need_unlink = false;
    bool bypass_security = false;
L
Laine Stump 已提交
2794
    unsigned int vfoflags = 0;
E
Eric Blake 已提交
2795
    int fd = -1;
2796
    int path_shared = virStorageFileIsSharedFS(path);
2797 2798
    uid_t uid = geteuid();
    gid_t gid = getegid();
E
Eric Blake 已提交
2799 2800 2801 2802 2803 2804

    /* 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;
2805 2806 2807

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

E
Eric Blake 已提交
2811 2812 2813 2814 2815
        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 */
2816
            if (is_reg && !dynamicOwnership) {
E
Eric Blake 已提交
2817 2818 2819 2820 2821 2822 2823 2824
                uid = sb.st_uid;
                gid = sb.st_gid;
            }
        }
    }

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

            /* On Linux we can also verify the FS-type of the directory. */
2842
            switch (path_shared) {
E
Eric Blake 已提交
2843
                case 1:
2844 2845 2846 2847
                    /* it was on a network share, so we'll continue
                     * as outlined above
                     */
                    break;
E
Eric Blake 已提交
2848 2849

                case -1:
2850 2851 2852 2853 2854 2855 2856
                    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 已提交
2857 2858 2859

                case 0:
                default:
2860 2861
                    /* local file - log the error returned by virFileOpenAs */
                    goto error;
E
Eric Blake 已提交
2862 2863
            }

2864
            /* Retry creating the file as qemu user */
E
Eric Blake 已提交
2865 2866 2867

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

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

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

2925
    memset(&header, 0, sizeof(header));
2926 2927
    memcpy(header.magic, QEMU_SAVE_PARTIAL, sizeof(header.magic));
    header.version = QEMU_SAVE_VERSION;
2928
    header.was_running = was_running ? 1 : 0;
2929

2930
    header.compressed = compressed;
2931

2932
    len = strlen(domXML) + 1;
2933 2934 2935 2936 2937 2938 2939 2940 2941 2942 2943 2944 2945
    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));
2946
    if (VIR_ALLOC_N(xml, len + pad) < 0)
2947
        goto cleanup;
2948 2949
    strcpy(xml, domXML);

2950 2951
    offset += pad;
    header.xml_len = len;
2952

2953
    /* Obtain the file handle.  */
2954 2955
    if ((flags & VIR_DOMAIN_SAVE_BYPASS_CACHE)) {
        wrapperFlags |= VIR_FILE_WRAPPER_BYPASS_CACHE;
2956 2957
        directFlag = virFileDirectFdFlag();
        if (directFlag < 0) {
2958 2959
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
E
Eric Blake 已提交
2960
            goto cleanup;
2961
        }
2962
    }
2963 2964
    fd = qemuOpenFile(driver, vm, path,
                      O_WRONLY | O_TRUNC | O_CREAT | directFlag,
E
Eric Blake 已提交
2965 2966
                      &needUnlink, &bypassSecurityDriver);
    if (fd < 0)
2967 2968
        goto cleanup;

2969
    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, wrapperFlags)))
2970
        goto cleanup;
2971

2972
    /* Write header to file, followed by XML */
2973 2974
    if (qemuDomainSaveHeader(fd, path, xml, &header) < 0)
        goto cleanup;
2975

2976
    /* Perform the migration */
2977
    if (qemuMigrationToFile(driver, vm, fd, offset, path,
2978
                            qemuCompressProgramName(compressed),
E
Eric Blake 已提交
2979
                            bypassSecurityDriver,
2980 2981
                            asyncJob) < 0)
        goto cleanup;
E
Eric Blake 已提交
2982

2983 2984 2985 2986 2987 2988 2989 2990
    /* 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);
2991
        goto cleanup;
E
Eric Blake 已提交
2992
    }
2993

2994
    if (virFileWrapperFdClose(wrapperFd) < 0)
2995 2996
        goto cleanup;

2997
    if ((fd = qemuOpenFile(driver, vm, path, O_WRONLY, NULL, NULL)) < 0)
2998
        goto cleanup;
2999

3000
    memcpy(header.magic, QEMU_SAVE_MAGIC, sizeof(header.magic));
3001

E
Eric Blake 已提交
3002 3003
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header)) {
        virReportSystemError(errno, _("unable to write %s"), path);
3004
        goto cleanup;
E
Eric Blake 已提交
3005
    }
3006

3007 3008
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno, _("unable to close %s"), path);
3009
        goto cleanup;
3010 3011
    }

3012 3013
    ret = 0;

3014 3015 3016
cleanup:
    VIR_FORCE_CLOSE(fd);
    virFileWrapperFdFree(wrapperFd);
3017
    VIR_FREE(xml);
3018 3019 3020 3021 3022 3023 3024

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

    return ret;
}

3025
/* The vm must be active + locked. Vm will be unlocked and
3026 3027 3028 3029 3030
 * 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
3031
qemuDomainSaveInternal(virQEMUDriverPtr driver, virDomainPtr dom,
3032 3033 3034 3035 3036 3037 3038
                       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;
3039
    virObjectEventPtr event = NULL;
3040
    qemuDomainObjPrivatePtr priv = vm->privateData;
3041 3042 3043 3044
    virCapsPtr caps;

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

3046
    if (!qemuMigrationIsAllowed(driver, vm, vm->def, false, false))
3047 3048
        goto cleanup;

3049 3050
    if (qemuDomainObjBeginAsyncJob(driver, vm, QEMU_ASYNC_JOB_SAVE) < 0)
        goto cleanup;
3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081

    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;

3082
        if (!(def = virDomainDefParseString(xmlin, caps, driver->xmlopt,
3083 3084 3085 3086
                                            QEMU_EXPECTED_VIRT_TYPES,
                                            VIR_DOMAIN_XML_INACTIVE))) {
            goto endjob;
        }
3087
        if (!qemuDomainDefCheckABIStability(driver, vm->def, def)) {
3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105
            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;

3106
    /* Shut it down */
3107
    qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_SAVED, 0);
3108
    virDomainAuditStop(vm, "saved");
3109
    event = virDomainEventLifecycleNewFromObj(vm,
3110 3111
                                     VIR_DOMAIN_EVENT_STOPPED,
                                     VIR_DOMAIN_EVENT_STOPPED_SAVED);
3112
    if (!vm->persistent) {
3113
        if (qemuDomainObjEndAsyncJob(driver, vm) > 0)
3114
            qemuDomainRemoveInactive(driver, vm);
3115 3116
        vm = NULL;
    }
3117

3118
endjob:
3119
    if (vm) {
3120
        if (ret != 0) {
3121
            if (was_running && virDomainObjIsActive(vm)) {
J
Jiri Denemark 已提交
3122
                rc = qemuProcessStartCPUs(driver, vm, dom->conn,
3123 3124
                                          VIR_DOMAIN_RUNNING_SAVE_CANCELED,
                                          QEMU_ASYNC_JOB_SAVE);
3125
                if (rc < 0) {
3126
                    VIR_WARN("Unable to resume guest CPUs after save failure");
3127
                    event = virDomainEventLifecycleNewFromObj(vm,
3128 3129 3130
                                                     VIR_DOMAIN_EVENT_SUSPENDED,
                                                     VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
                }
3131
            }
3132
        }
3133
        if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
3134
            vm = NULL;
3135
    }
3136

3137 3138
cleanup:
    VIR_FREE(xml);
3139 3140
    if (event)
        qemuDomainEventQueue(driver, event);
3141
    if (vm)
3142
        virObjectUnlock(vm);
3143
    virObjectUnref(caps);
3144
    return ret;
D
Daniel P. Berrange 已提交
3145 3146
}

3147
/* Returns true if a compression program is available in PATH */
3148 3149
static bool
qemuCompressProgramAvailable(virQEMUSaveFormat compress)
3150
{
3151
    char *path;
3152

3153
    if (compress == QEMU_SAVE_FORMAT_RAW)
3154
        return true;
3155 3156

    if (!(path = virFindFileInPath(qemuSaveCompressionTypeToString(compress))))
3157
        return false;
3158 3159

    VIR_FREE(path);
3160 3161 3162
    return true;
}

3163 3164 3165
static int
qemuDomainSaveFlags(virDomainPtr dom, const char *path, const char *dxml,
                    unsigned int flags)
3166
{
3167
    virQEMUDriverPtr driver = dom->conn->privateData;
3168
    int compressed = QEMU_SAVE_FORMAT_RAW;
3169 3170
    int ret = -1;
    virDomainObjPtr vm = NULL;
3171
    virQEMUDriverConfigPtr cfg = NULL;
3172

3173 3174 3175
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
3176

3177
    cfg = virQEMUDriverGetConfig(driver);
3178
    if (cfg->saveImageFormat) {
3179
        compressed = qemuSaveCompressionTypeFromString(cfg->saveImageFormat);
3180
        if (compressed < 0) {
3181 3182 3183
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Invalid save image format specified "
                             "in configuration file"));
3184
            goto cleanup;
3185
        }
3186
        if (!qemuCompressProgramAvailable(compressed)) {
3187 3188 3189
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("Compression program for image format "
                             "in configuration file isn't available"));
3190
            goto cleanup;
3191
        }
3192 3193
    }

3194
    if (!(vm = qemuDomObjFromDomain(dom)))
3195 3196
        goto cleanup;

3197 3198 3199
    if (virDomainSaveFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3200
    if (!virDomainObjIsActive(vm)) {
3201 3202
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3203 3204 3205
        goto cleanup;
    }

3206
    ret = qemuDomainSaveInternal(driver, dom, vm, path, compressed,
3207
                                 dxml, flags);
3208
    vm = NULL;
3209 3210 3211

cleanup:
    if (vm)
3212
        virObjectUnlock(vm);
3213
    virObjectUnref(cfg);
3214
    return ret;
3215 3216
}

3217 3218 3219 3220 3221 3222
static int
qemuDomainSave(virDomainPtr dom, const char *path)
{
    return qemuDomainSaveFlags(dom, path, NULL, 0);
}

3223
static char *
3224 3225
qemuDomainManagedSavePath(virQEMUDriverPtr driver, virDomainObjPtr vm)
{
3226
    char *ret;
3227
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
3228

3229 3230
    if (virAsprintf(&ret, "%s/%s.save", cfg->saveDir, vm->def->name) < 0) {
        virObjectUnref(cfg);
3231
        return NULL;
3232 3233
    }

3234
    virObjectUnref(cfg);
3235
    return ret;
3236 3237 3238 3239 3240
}

static int
qemuDomainManagedSave(virDomainPtr dom, unsigned int flags)
{
3241
    virQEMUDriverPtr driver = dom->conn->privateData;
3242 3243
    virQEMUDriverConfigPtr cfg = NULL;
    int compressed = QEMU_SAVE_FORMAT_RAW;
3244
    virDomainObjPtr vm;
3245 3246 3247
    char *name = NULL;
    int ret = -1;

3248 3249 3250
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
3251

3252
    if (!(vm = qemuDomObjFromDomain(dom)))
3253
        return -1;
3254

3255 3256 3257
    if (virDomainManagedSaveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3258
    if (!virDomainObjIsActive(vm)) {
3259 3260
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3261 3262
        goto cleanup;
    }
3263
    if (!vm->persistent) {
3264 3265
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot do managed save for transient domain"));
3266 3267
        goto cleanup;
    }
3268

3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 3281 3282 3283 3284 3285
    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;
        }
    }

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

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

3291
    if ((ret = qemuDomainSaveInternal(driver, dom, vm, name, compressed,
3292 3293 3294
                                      NULL, flags)) == 0)
        vm->hasManagedSave = true;

3295
    vm = NULL;
3296 3297 3298

cleanup:
    if (vm)
3299
        virObjectUnlock(vm);
3300
    VIR_FREE(name);
3301
    virObjectUnref(cfg);
3302 3303

    return ret;
3304 3305
}

3306 3307
static int
qemuDomainManagedSaveLoad(virDomainObjPtr vm,
3308 3309
                          void *opaque)
{
3310
    virQEMUDriverPtr driver = opaque;
3311
    char *name;
3312
    int ret = -1;
3313

3314
    virObjectLock(vm);
3315 3316 3317 3318 3319 3320

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

    vm->hasManagedSave = virFileExists(name);

3321
    ret = 0;
3322
cleanup:
3323
    virObjectUnlock(vm);
3324
    VIR_FREE(name);
3325
    return ret;
3326 3327
}

3328

3329 3330 3331 3332
static int
qemuDomainHasManagedSaveImage(virDomainPtr dom, unsigned int flags)
{
    virDomainObjPtr vm = NULL;
3333
    int ret = -1;
3334

3335
    virCheckFlags(0, -1);
3336

3337 3338
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
3339

3340 3341 3342
    if (virDomainHasManagedSaveImageEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3343
    ret = vm->hasManagedSave;
3344 3345

cleanup:
3346
    virObjectUnlock(vm);
3347 3348 3349 3350 3351 3352
    return ret;
}

static int
qemuDomainManagedSaveRemove(virDomainPtr dom, unsigned int flags)
{
3353
    virQEMUDriverPtr driver = dom->conn->privateData;
3354
    virDomainObjPtr vm;
3355 3356 3357
    int ret = -1;
    char *name = NULL;

3358
    virCheckFlags(0, -1);
3359

3360
    if (!(vm = qemuDomObjFromDomain(dom)))
3361
        return -1;
3362

3363 3364 3365
    if (virDomainManagedSaveRemoveEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

3369 3370 3371 3372 3373 3374 3375
    if (unlink(name) < 0) {
        virReportSystemError(errno,
                             _("Failed to remove managed save file '%s'"),
                             name);
        goto cleanup;
    }

3376
    vm->hasManagedSave = false;
3377
    ret = 0;
3378 3379 3380

cleanup:
    VIR_FREE(name);
3381
    virObjectUnlock(vm);
3382 3383
    return ret;
}
D
Daniel P. Berrange 已提交
3384

3385
static int qemuDumpToFd(virQEMUDriverPtr driver, virDomainObjPtr vm,
3386 3387 3388 3389 3390
                        int fd, enum qemuDomainAsyncJob asyncJob)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int ret = -1;

3391
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DUMP_GUEST_MEMORY)) {
3392
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
3393
                       _("dump-guest-memory is not supported"));
3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405
        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;

3406
    ret = qemuMonitorDumpToFd(priv->mon, fd);
3407
    qemuDomainObjExitMonitor(driver, vm);
3408 3409 3410 3411

    return ret;
}

3412
static int
3413
doCoreDump(virQEMUDriverPtr driver,
3414 3415
           virDomainObjPtr vm,
           const char *path,
3416
           virQEMUSaveFormat compress,
3417
           unsigned int dump_flags)
H
Hu Tao 已提交
3418 3419 3420
{
    int fd = -1;
    int ret = -1;
J
Jiri Denemark 已提交
3421
    virFileWrapperFdPtr wrapperFd = NULL;
3422
    int directFlag = 0;
3423
    unsigned int flags = VIR_FILE_WRAPPER_NON_BLOCKING;
H
Hu Tao 已提交
3424 3425

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

3443
    if (!(wrapperFd = virFileWrapperFdNew(&fd, path, flags)))
3444 3445
        goto cleanup;

3446 3447 3448 3449 3450 3451 3452 3453 3454
    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)
3455 3456
        goto cleanup;

H
Hu Tao 已提交
3457 3458
    if (VIR_CLOSE(fd) < 0) {
        virReportSystemError(errno,
3459
                             _("unable to close file %s"),
H
Hu Tao 已提交
3460 3461 3462
                             path);
        goto cleanup;
    }
J
Jiri Denemark 已提交
3463
    if (virFileWrapperFdClose(wrapperFd) < 0)
3464
        goto cleanup;
H
Hu Tao 已提交
3465

3466
    ret = 0;
H
Hu Tao 已提交
3467 3468

cleanup:
3469
    VIR_FORCE_CLOSE(fd);
3470
    if (ret != 0)
H
Hu Tao 已提交
3471
        unlink(path);
3472
    virFileWrapperFdFree(wrapperFd);
H
Hu Tao 已提交
3473 3474 3475
    return ret;
}

3476
static virQEMUSaveFormat
3477
getCompressionType(virQEMUDriverPtr driver)
3478
{
3479 3480
    int ret = QEMU_SAVE_FORMAT_RAW;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
3481

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

3510 3511 3512
static int qemuDomainCoreDump(virDomainPtr dom,
                              const char *path,
                              unsigned int flags)
3513
{
3514
    virQEMUDriverPtr driver = dom->conn->privateData;
3515
    virDomainObjPtr vm;
M
Michal Privoznik 已提交
3516
    qemuDomainObjPrivatePtr priv;
3517
    bool resume = false, paused = false;
H
Hu Tao 已提交
3518
    int ret = -1;
3519
    virObjectEventPtr event = NULL;
3520

M
Michal Privoznik 已提交
3521
    virCheckFlags(VIR_DUMP_LIVE | VIR_DUMP_CRASH |
3522 3523
                  VIR_DUMP_BYPASS_CACHE | VIR_DUMP_RESET |
                  VIR_DUMP_MEMORY_ONLY, -1);
3524

3525 3526
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
P
Paolo Bonzini 已提交
3527

3528 3529 3530
    if (virDomainCoreDumpEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3531 3532
    if (qemuDomainObjBeginAsyncJob(driver, vm,
                                   QEMU_ASYNC_JOB_DUMP) < 0)
3533 3534
        goto cleanup;

D
Daniel P. Berrange 已提交
3535
    if (!virDomainObjIsActive(vm)) {
3536 3537
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3538
        goto endjob;
P
Paolo Bonzini 已提交
3539 3540
    }

P
Paolo Bonzini 已提交
3541 3542
    /* Migrate will always stop the VM, so the resume condition is
       independent of whether the stop command is issued.  */
J
Jiri Denemark 已提交
3543
    resume = virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING;
P
Paolo Bonzini 已提交
3544 3545

    /* Pause domain for non-live dump */
J
Jiri Denemark 已提交
3546 3547
    if (!(flags & VIR_DUMP_LIVE) &&
        virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
3548 3549
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_DUMP,
                                QEMU_ASYNC_JOB_DUMP) < 0)
3550
            goto endjob;
3551
        paused = true;
3552 3553

        if (!virDomainObjIsActive(vm)) {
3554 3555
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
3556 3557
            goto endjob;
        }
P
Paolo Bonzini 已提交
3558 3559
    }

3560
    ret = doCoreDump(driver, vm, path, getCompressionType(driver), flags);
3561 3562 3563
    if (ret < 0)
        goto endjob;

3564
    paused = true;
3565 3566

endjob:
3567
    if ((ret == 0) && (flags & VIR_DUMP_CRASH)) {
3568
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_CRASHED, 0);
3569
        virDomainAuditStop(vm, "crashed");
3570
        event = virDomainEventLifecycleNewFromObj(vm,
3571 3572 3573 3574
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);
    }

P
Paolo Bonzini 已提交
3575 3576 3577
    /* 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 已提交
3578 3579 3580 3581
    else if (((resume && paused) || (flags & VIR_DUMP_RESET)) &&
             virDomainObjIsActive(vm)) {
        if ((ret == 0) && (flags & VIR_DUMP_RESET)) {
            priv =  vm->privateData;
3582
            qemuDomainObjEnterMonitor(driver, vm);
M
Michal Privoznik 已提交
3583
            ret = qemuMonitorSystemReset(priv->mon);
3584
            qemuDomainObjExitMonitor(driver, vm);
M
Michal Privoznik 已提交
3585 3586 3587 3588 3589
        }

        if (resume && qemuProcessStartCPUs(driver, vm, dom->conn,
                                           VIR_DOMAIN_RUNNING_UNPAUSED,
                                           QEMU_ASYNC_JOB_DUMP) < 0) {
3590
            event = virDomainEventLifecycleNewFromObj(vm,
3591 3592
                                             VIR_DOMAIN_EVENT_SUSPENDED,
                                             VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
3593
            if (virGetLastError() == NULL)
3594 3595
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("resuming after dump failed"));
P
Paolo Bonzini 已提交
3596 3597
        }
    }
3598

3599
    if (qemuDomainObjEndAsyncJob(driver, vm) == 0)
3600
        vm = NULL;
3601
    else if ((ret == 0) && (flags & VIR_DUMP_CRASH) && !vm->persistent) {
3602
        qemuDomainRemoveInactive(driver, vm);
3603 3604
        vm = NULL;
    }
3605 3606

cleanup:
P
Paolo Bonzini 已提交
3607
    if (vm)
3608
        virObjectUnlock(vm);
3609 3610
    if (event)
        qemuDomainEventQueue(driver, event);
P
Paolo Bonzini 已提交
3611 3612 3613
    return ret;
}

3614 3615 3616 3617
static char *
qemuDomainScreenshot(virDomainPtr dom,
                     virStreamPtr st,
                     unsigned int screen,
E
Eric Blake 已提交
3618
                     unsigned int flags)
3619
{
3620
    virQEMUDriverPtr driver = dom->conn->privateData;
3621 3622 3623 3624 3625
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    char *tmp = NULL;
    int tmp_fd = -1;
    char *ret = NULL;
E
Eric Blake 已提交
3626
    bool unlink_tmp = false;
3627
    virQEMUDriverConfigPtr cfg = NULL;
3628

E
Eric Blake 已提交
3629 3630
    virCheckFlags(0, NULL);

3631
    if (!(vm = qemuDomObjFromDomain(dom)))
3632 3633 3634
        goto cleanup;

    priv = vm->privateData;
3635
    cfg = virQEMUDriverGetConfig(driver);
3636

3637 3638 3639
    if (virDomainScreenshotEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

3640
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
3641 3642 3643
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
3644 3645
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
3646 3647 3648 3649 3650 3651
        goto endjob;
    }

    /* Well, even if qemu allows multiple graphic cards, heads, whatever,
     * screenshot command does not */
    if (screen) {
3652 3653 3654
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("currently is supported only taking "
                               "screenshots of screen ID 0"));
3655 3656 3657
        goto endjob;
    }

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

3661 3662
    if ((tmp_fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
        virReportSystemError(errno, _("mkostemp(\"%s\") failed"), tmp);
3663 3664
        goto endjob;
    }
E
Eric Blake 已提交
3665
    unlink_tmp = true;
3666

3667
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
3668

3669
    qemuDomainObjEnterMonitor(driver, vm);
3670
    if (qemuMonitorScreendump(priv->mon, tmp) < 0) {
3671
        qemuDomainObjExitMonitor(driver, vm);
3672 3673
        goto endjob;
    }
3674
    qemuDomainObjExitMonitor(driver, vm);
3675 3676 3677 3678 3679 3680

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

E
Eric Blake 已提交
3681
    if (virFDStreamOpenFile(st, tmp, 0, 0, O_RDONLY) < 0) {
3682 3683
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("unable to open stream"));
3684 3685 3686
        goto endjob;
    }

3687
    ignore_value(VIR_STRDUP(ret, "image/x-portable-pixmap"));
3688 3689 3690

endjob:
    VIR_FORCE_CLOSE(tmp_fd);
E
Eric Blake 已提交
3691 3692
    if (unlink_tmp)
        unlink(tmp);
E
Eric Blake 已提交
3693
    VIR_FREE(tmp);
3694

E
Eric Blake 已提交
3695
    if (!qemuDomainObjEndJob(driver, vm))
3696 3697 3698 3699
        vm = NULL;

cleanup:
    if (vm)
3700
        virObjectUnlock(vm);
3701
    virObjectUnref(cfg);
3702 3703 3704
    return ret;
}

C
Chen Fan 已提交
3705
static void processWatchdogEvent(virQEMUDriverPtr driver, virDomainObjPtr vm, int action)
H
Hu Tao 已提交
3706 3707
{
    int ret;
C
Chen Fan 已提交
3708
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
W
Wen Congyang 已提交
3709

C
Chen Fan 已提交
3710
    switch (action) {
H
Hu Tao 已提交
3711 3712 3713
    case VIR_DOMAIN_WATCHDOG_ACTION_DUMP:
        {
            char *dumpfile;
3714
            unsigned int flags = 0;
H
Hu Tao 已提交
3715

E
Eric Blake 已提交
3716
            if (virAsprintf(&dumpfile, "%s/%s-%u",
3717
                            cfg->autoDumpPath,
C
Chen Fan 已提交
3718
                            vm->def->name,
3719
                            (unsigned int)time(NULL)) < 0)
C
Chen Fan 已提交
3720
                goto cleanup;
H
Hu Tao 已提交
3721

C
Chen Fan 已提交
3722 3723
            if (qemuDomainObjBeginAsyncJob(driver, vm,
                                           QEMU_ASYNC_JOB_DUMP) < 0) {
W
Wen Congyang 已提交
3724
                VIR_FREE(dumpfile);
C
Chen Fan 已提交
3725
                goto cleanup;
W
Wen Congyang 已提交
3726
            }
H
Hu Tao 已提交
3727

C
Chen Fan 已提交
3728
            if (!virDomainObjIsActive(vm)) {
3729 3730
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("domain is not running"));
W
Wen Congyang 已提交
3731 3732
                VIR_FREE(dumpfile);
                goto endjob;
H
Hu Tao 已提交
3733 3734
            }

3735
            flags |= cfg->autoDumpBypassCache ? VIR_DUMP_BYPASS_CACHE: 0;
C
Chen Fan 已提交
3736
            ret = doCoreDump(driver, vm, dumpfile,
3737
                             getCompressionType(driver), flags);
H
Hu Tao 已提交
3738
            if (ret < 0)
3739 3740
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Dump failed"));
H
Hu Tao 已提交
3741

C
Chen Fan 已提交
3742
            ret = qemuProcessStartCPUs(driver, vm, NULL,
3743 3744
                                       VIR_DOMAIN_RUNNING_UNPAUSED,
                                       QEMU_ASYNC_JOB_DUMP);
H
Hu Tao 已提交
3745 3746

            if (ret < 0)
3747 3748
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("Resuming after dump failed"));
H
Hu Tao 已提交
3749 3750 3751 3752

            VIR_FREE(dumpfile);
        }
        break;
W
Wen Congyang 已提交
3753
    default:
C
Chen Fan 已提交
3754
        goto cleanup;
H
Hu Tao 已提交
3755 3756
    }

W
Wen Congyang 已提交
3757 3758 3759 3760
endjob:
    /* Safe to ignore value since ref count was incremented in
     * qemuProcessHandleWatchdog().
     */
C
Chen Fan 已提交
3761
    ignore_value(qemuDomainObjEndAsyncJob(driver, vm));
W
Wen Congyang 已提交
3762

C
Chen Fan 已提交
3763
cleanup:
3764
    virObjectUnref(cfg);
H
Hu Tao 已提交
3765
}
P
Paolo Bonzini 已提交
3766

3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 3780 3781 3782 3783 3784
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,
3785
                    timestr) < 0)
3786 3787 3788 3789 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 3813 3814 3815 3816 3817
        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;
}

3818 3819 3820 3821 3822 3823
static void
processGuestPanicEvent(virQEMUDriverPtr driver,
                       virDomainObjPtr vm,
                       int action)
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
3824
    virObjectEventPtr event = NULL;
3825 3826 3827 3828 3829 3830 3831 3832 3833 3834 3835 3836
    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);

3837
    event = virDomainEventLifecycleNewFromObj(vm,
3838 3839 3840 3841 3842 3843 3844 3845 3846 3847 3848 3849 3850 3851 3852 3853
                                     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) {
3854 3855 3856 3857 3858 3859
    case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_DESTROY:
        if (doCoreDumpToAutoDumpPath(driver, vm, VIR_DUMP_MEMORY_ONLY) < 0) {
            goto cleanup;
        }
        /* fall through */

3860 3861 3862 3863 3864 3865 3866 3867 3868 3869 3870 3871 3872 3873 3874 3875 3876
    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);
3877
        event = virDomainEventLifecycleNewFromObj(vm,
3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890
                                         VIR_DOMAIN_EVENT_STOPPED,
                                         VIR_DOMAIN_EVENT_STOPPED_CRASHED);

        if (event)
            qemuDomainEventQueue(driver, event);

        virDomainAuditStop(vm, "destroyed");

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

3891 3892 3893 3894 3895 3896
    case VIR_DOMAIN_LIFECYCLE_CRASH_COREDUMP_RESTART:
        if (doCoreDumpToAutoDumpPath(driver, vm, VIR_DUMP_MEMORY_ONLY) < 0) {
            goto cleanup;
        }
        /* fall through */

3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912
    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 已提交
3913 3914 3915 3916 3917 3918
static void qemuProcessEventHandler(void *data, void *opaque)
{
    struct qemuProcessEvent *processEvent = data;
    virDomainObjPtr vm = processEvent->vm;
    virQEMUDriverPtr driver = opaque;

3919 3920
    VIR_DEBUG("vm=%p", vm);

C
Chen Fan 已提交
3921 3922 3923 3924 3925 3926
    virObjectLock(vm);

    switch (processEvent->eventType) {
    case QEMU_PROCESS_EVENT_WATCHDOG:
        processWatchdogEvent(driver, vm, processEvent->action);
        break;
3927 3928 3929
    case QEMU_PROCESS_EVENT_GUESTPANIC:
        processGuestPanicEvent(driver, vm, processEvent->action);
        break;
C
Chen Fan 已提交
3930 3931 3932 3933 3934 3935 3936 3937 3938
    default:
       break;
    }

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

3939
static int qemuDomainHotplugVcpus(virQEMUDriverPtr driver,
3940 3941
                                  virDomainObjPtr vm,
                                  unsigned int nvcpus)
3942 3943
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
3944 3945
    size_t i;
    int rc = 1;
3946
    int ret = -1;
3947
    int oldvcpus = vm->def->vcpus;
E
Eric Blake 已提交
3948
    int vcpus = oldvcpus;
3949 3950
    pid_t *cpupids = NULL;
    int ncpupids;
3951
    virCgroupPtr cgroup_vcpu = NULL;
3952

3953
    qemuDomainObjEnterMonitor(driver, vm);
3954

3955 3956 3957
    /* 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 已提交
3958
    if (nvcpus > vcpus) {
3959
        for (i = vcpus; i < nvcpus; i++) {
3960
            /* Online new CPU */
3961
            rc = qemuMonitorSetCPU(priv->mon, i, true);
3962 3963 3964 3965 3966
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3967
            vcpus++;
3968 3969
        }
    } else {
3970
        for (i = vcpus - 1; i >= nvcpus; i--) {
3971
            /* Offline old CPU */
3972
            rc = qemuMonitorSetCPU(priv->mon, i, false);
3973 3974 3975 3976 3977
            if (rc == 0)
                goto unsupported;
            if (rc < 0)
                goto cleanup;

E
Eric Blake 已提交
3978
            vcpus--;
3979 3980 3981
        }
    }

3982 3983
    /* hotplug succeeded */

3984 3985
    ret = 0;

3986 3987 3988 3989 3990 3991 3992 3993 3994 3995
    /* 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;
    }

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

4005
    if (ncpupids != vcpus) {
4006 4007 4008 4009
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("got wrong number of vCPU pids from QEMU monitor. "
                         "got %d, wanted %d"),
                       ncpupids, vcpus);
4010
        vcpus = oldvcpus;
4011 4012 4013 4014
        ret = -1;
        goto cleanup;
    }

4015 4016
    if (nvcpus > oldvcpus) {
        for (i = oldvcpus; i < nvcpus; i++) {
4017
            if (priv->cgroup) {
4018
                int rv = -1;
4019
                /* Create cgroup for the onlined vcpu */
4020
                if (virCgroupNewVcpu(priv->cgroup, i, true, &cgroup_vcpu) < 0)
4021 4022 4023 4024 4025 4026
                    goto cleanup;

                /* Add vcpu thread to the cgroup */
                rv = virCgroupAddTask(cgroup_vcpu, cpupids[i]);
                if (rv < 0) {
                    virReportSystemError(-rv,
4027
                                         _("unable to add vcpu %zu task %d to cgroup"),
4028 4029 4030 4031
                                         i, cpupids[i]);
                    virCgroupRemove(cgroup_vcpu);
                    goto cleanup;
                }
4032
            }
4033

4034 4035 4036 4037 4038 4039 4040 4041
            /* 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,
4042
                                  vm->def->cputune.nvcpupin + 1) < 0)
4043 4044
                    goto cleanup;

4045
                if (VIR_ALLOC(vcpupin) < 0)
4046 4047 4048 4049 4050 4051 4052
                    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;

4053
                if (cgroup_vcpu) {
4054 4055 4056 4057 4058
                    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"
4059
                                         " for vcpu %zu"), i);
4060 4061 4062 4063
                        ret = -1;
                        goto cleanup;
                    }
                } else {
4064 4065
                    if (virProcessSetAffinity(cpupids[i],
                                              vcpupin->cpumask) < 0) {
4066
                        virReportError(VIR_ERR_SYSTEM_ERROR,
4067
                                       _("failed to set cpu affinity for vcpu %zu"),
4068 4069 4070 4071 4072
                                       i);
                        ret = -1;
                        goto cleanup;
                    }
                }
4073
            }
4074 4075

            virCgroupFree(&cgroup_vcpu);
G
Guido Günther 已提交
4076
        }
4077 4078 4079 4080
    } else {
        for (i = oldvcpus - 1; i >= nvcpus; i--) {
            virDomainVcpuPinDefPtr vcpupin = NULL;

4081
            if (priv->cgroup) {
4082
                if (virCgroupNewVcpu(priv->cgroup, i, false, &cgroup_vcpu) < 0)
4083 4084 4085 4086 4087 4088 4089
                    goto cleanup;

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

4090 4091 4092 4093 4094
            /* Free vcpupin setting */
            if ((vcpupin = virDomainLookupVcpuPin(vm->def, i))) {
                VIR_FREE(vcpupin);
            }
        }
4095 4096
    }

4097 4098 4099 4100 4101
    priv->nvcpupids = ncpupids;
    VIR_FREE(priv->vcpupids);
    priv->vcpupids = cpupids;
    cpupids = NULL;

4102
cleanup:
4103
    qemuDomainObjExitMonitor(driver, vm);
E
Eric Blake 已提交
4104
    vm->def->vcpus = vcpus;
4105
    VIR_FREE(cpupids);
4106
    virDomainAuditVcpu(vm, oldvcpus, nvcpus, "update", rc == 1);
4107 4108
    if (cgroup_vcpu)
        virCgroupFree(&cgroup_vcpu);
4109 4110 4111
    return ret;

unsupported:
4112 4113
    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                   _("cannot change vcpu count of this domain"));
4114 4115 4116 4117
    goto cleanup;
}


4118
static int
4119 4120
qemuDomainSetVcpusFlags(virDomainPtr dom, unsigned int nvcpus,
                        unsigned int flags)
4121
{
4122
    virQEMUDriverPtr driver = dom->conn->privateData;
4123
    virDomainObjPtr vm = NULL;
4124
    virDomainDefPtr persistentDef;
4125
    int ret = -1;
4126
    bool maximum;
4127
    virQEMUDriverConfigPtr cfg = NULL;
4128
    virCapsPtr caps = NULL;
4129 4130 4131
    qemuAgentCPUInfoPtr cpuinfo = NULL;
    int ncpuinfo;
    qemuDomainObjPrivatePtr priv;
4132

4133 4134
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
4135
                  VIR_DOMAIN_VCPU_MAXIMUM |
4136
                  VIR_DOMAIN_VCPU_GUEST, -1);
4137 4138

    if (!nvcpus || (unsigned short) nvcpus != nvcpus) {
4139 4140
        virReportError(VIR_ERR_INVALID_ARG,
                       _("argument out of range: %d"), nvcpus);
4141 4142 4143
        return -1;
    }

4144 4145 4146
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;

4147
    cfg = virQEMUDriverGetConfig(driver);
4148 4149

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

4152
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
4153
        goto cleanup;
4154

4155 4156
    priv = vm->privateData;

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

4160 4161 4162
    maximum = (flags & VIR_DOMAIN_VCPU_MAXIMUM) != 0;
    flags &= ~VIR_DOMAIN_VCPU_MAXIMUM;

4163
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
4164 4165
                                        &persistentDef) < 0)
        goto endjob;
4166 4167 4168

    /* MAXIMUM cannot be mixed with LIVE.  */
    if (maximum && (flags & VIR_DOMAIN_AFFECT_LIVE)) {
4169 4170
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("cannot adjust maximum on running domain"));
4171 4172 4173
        goto endjob;
    }

4174
    if (!maximum && nvcpus > vm->def->maxvcpus) {
4175 4176
        virReportError(VIR_ERR_INVALID_ARG,
                       _("requested vcpus is greater than max allowable"
4177 4178
                         " vcpus for the domain: %d > %d"),
                       nvcpus, vm->def->maxvcpus);
4179 4180 4181
        goto endjob;
    }

4182
    if (flags & VIR_DOMAIN_VCPU_GUEST) {
4183 4184
        if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
4185
                           _("changing of maximum vCPU count isn't supported "
4186
                             "via guest agent"));
4187
            goto endjob;
4188
        }
4189

4190 4191 4192 4193 4194 4195 4196 4197 4198 4199 4200 4201 4202
        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;
        }

4203 4204 4205 4206 4207 4208 4209 4210
        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;
        }

4211 4212 4213 4214 4215 4216 4217
        qemuDomainObjEnterAgent(vm);
        ncpuinfo = qemuAgentGetVCPUs(priv->agent, &cpuinfo);
        qemuDomainObjExitAgent(vm);

        if (ncpuinfo < 0)
            goto endjob;

4218
        if (qemuAgentUpdateCPUInfo(nvcpus, cpuinfo, ncpuinfo) < 0)
4219 4220 4221 4222 4223 4224 4225
            goto endjob;

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

        if (ret < 0)
4226
            goto endjob;
4227 4228 4229 4230 4231 4232 4233 4234 4235 4236 4237 4238 4239 4240 4241 4242 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252

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

4255
    ret = 0;
4256

4257
endjob:
E
Eric Blake 已提交
4258
    if (!qemuDomainObjEndJob(driver, vm))
4259
        vm = NULL;
4260

4261
cleanup:
4262
    if (vm)
4263
        virObjectUnlock(vm);
4264
    virObjectUnref(caps);
4265
    VIR_FREE(cpuinfo);
4266
    virObjectUnref(cfg);
4267
    return ret;
4268 4269
}

4270
static int
4271
qemuDomainSetVcpus(virDomainPtr dom, unsigned int nvcpus)
4272
{
4273
    return qemuDomainSetVcpusFlags(dom, nvcpus, VIR_DOMAIN_AFFECT_LIVE);
4274 4275
}

4276 4277

static int
4278 4279 4280 4281 4282
qemuDomainPinVcpuFlags(virDomainPtr dom,
                       unsigned int vcpu,
                       unsigned char *cpumap,
                       int maplen,
                       unsigned int flags) {
4283

4284
    virQEMUDriverPtr driver = dom->conn->privateData;
4285
    virDomainObjPtr vm;
4286
    virDomainDefPtr persistentDef = NULL;
4287
    virCgroupPtr cgroup_vcpu = NULL;
4288
    int ret = -1;
4289
    qemuDomainObjPrivatePtr priv;
4290
    bool doReset = false;
4291 4292
    int newVcpuPinNum = 0;
    virDomainVcpuPinDefPtr *newVcpuPin = NULL;
4293
    virBitmapPtr pcpumap = NULL;
4294
    virQEMUDriverConfigPtr cfg = NULL;
4295
    virCapsPtr caps = NULL;
4296

4297 4298 4299
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4300 4301
    cfg = virQEMUDriverGetConfig(driver);

4302
    if (!(vm = qemuDomObjFromDomain(dom)))
4303 4304
        goto cleanup;

4305 4306 4307
    if (virDomainPinVcpuFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4308 4309 4310
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

4311
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
4312
                                        &persistentDef) < 0)
4313
        goto cleanup;
4314

4315 4316 4317
    priv = vm->privateData;

    if (vcpu > (priv->nvcpupids-1)) {
4318 4319 4320
        virReportError(VIR_ERR_INVALID_ARG,
                       _("vcpu number out of range %d > %d"),
                       vcpu, priv->nvcpupids);
4321
        goto cleanup;
4322 4323
    }

4324 4325 4326 4327
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

4328 4329 4330 4331 4332 4333
    if (virBitmapIsAllClear(pcpumap)) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Empty cpu list for pinning"));
        goto cleanup;
    }

4334 4335 4336
    /* pinning to all physical cpus means resetting,
     * so check if we can reset setting.
     */
4337 4338
    if (virBitmapIsAllSet(pcpumap))
        doReset = true;
4339

4340
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
4341

4342
        if (priv->vcpupids == NULL) {
4343 4344
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cpu affinity is not supported"));
4345 4346 4347
            goto cleanup;
        }

4348 4349 4350 4351 4352 4353 4354 4355
        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 {
4356
            if (VIR_ALLOC(newVcpuPin) < 0)
4357 4358 4359 4360
                goto cleanup;
            newVcpuPinNum = 0;
        }

4361
        if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, vcpu) < 0) {
4362 4363
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("failed to update vcpupin"));
H
Hu Tao 已提交
4364
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
4365 4366 4367 4368
            goto cleanup;
        }

        /* Configure the corresponding cpuset cgroup before set affinity. */
4369
        if (virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) {
4370 4371 4372
            if (virCgroupNewVcpu(priv->cgroup, vcpu, false, &cgroup_vcpu) < 0)
                goto cleanup;
            if (qemuSetupCgroupVcpuPin(cgroup_vcpu, newVcpuPin, newVcpuPinNum, vcpu) < 0) {
4373 4374 4375
                virReportError(VIR_ERR_OPERATION_INVALID,
                               _("failed to set cpuset.cpus in cgroup"
                                 " for vcpu %d"), vcpu);
4376 4377 4378
                goto cleanup;
            }
        } else {
4379
            if (virProcessSetAffinity(priv->vcpupids[vcpu], pcpumap) < 0) {
4380 4381 4382 4383
                virReportError(VIR_ERR_SYSTEM_ERROR,
                               _("failed to set cpu affinity for vcpu %d"),
                               vcpu);
                goto cleanup;
H
Hu Tao 已提交
4384
            }
4385 4386
        }

4387
        if (doReset) {
4388
            if (virDomainVcpuPinDel(vm->def, vcpu) < 0) {
4389
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4390
                               _("failed to delete vcpupin xml of "
4391
                                 "a running domain"));
4392 4393
                goto cleanup;
            }
4394 4395
        } else {
            if (vm->def->cputune.vcpupin)
H
Hu Tao 已提交
4396
                virDomainVcpuPinDefArrayFree(vm->def->cputune.vcpupin, vm->def->cputune.nvcpupin);
4397 4398 4399 4400

            vm->def->cputune.vcpupin = newVcpuPin;
            vm->def->cputune.nvcpupin = newVcpuPinNum;
            newVcpuPin = NULL;
4401 4402
        }

4403
        if (newVcpuPin)
H
Hu Tao 已提交
4404
            virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
4405

4406
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
4407
            goto cleanup;
4408
    }
4409

4410 4411
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

4412
        if (doReset) {
E
Eric Blake 已提交
4413
            if (virDomainVcpuPinDel(persistentDef, vcpu) < 0) {
4414 4415 4416
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to delete vcpupin xml of "
                                 "a persistent domain"));
4417 4418 4419
                goto cleanup;
            }
        } else {
H
Hu Tao 已提交
4420
            if (!persistentDef->cputune.vcpupin) {
4421
                if (VIR_ALLOC(persistentDef->cputune.vcpupin) < 0)
H
Hu Tao 已提交
4422 4423 4424
                    goto cleanup;
                persistentDef->cputune.nvcpupin = 0;
            }
4425
            if (virDomainVcpuPinAdd(&persistentDef->cputune.vcpupin,
H
Hu Tao 已提交
4426 4427 4428 4429
                                    &persistentDef->cputune.nvcpupin,
                                    cpumap,
                                    maplen,
                                    vcpu) < 0) {
4430 4431 4432
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update or add vcpupin xml of "
                                 "a persistent domain"));
4433 4434
                goto cleanup;
            }
4435
        }
4436

4437
        ret = virDomainSaveConfig(cfg->configDir, persistentDef);
4438 4439 4440
        goto cleanup;
    }

4441
    ret = 0;
4442

4443
cleanup:
4444 4445
    if (cgroup_vcpu)
        virCgroupFree(&cgroup_vcpu);
4446
    if (vm)
4447
        virObjectUnlock(vm);
4448
    virBitmapFree(pcpumap);
4449
    virObjectUnref(caps);
4450
    virObjectUnref(cfg);
4451
    return ret;
4452 4453
}

4454
static int
4455
qemuDomainPinVcpu(virDomainPtr dom,
4456 4457 4458
                   unsigned int vcpu,
                   unsigned char *cpumap,
                   int maplen) {
4459 4460
    return qemuDomainPinVcpuFlags(dom, vcpu, cpumap, maplen,
                                  VIR_DOMAIN_AFFECT_LIVE);
4461 4462
}

4463
static int
4464 4465 4466 4467 4468
qemuDomainGetVcpuPinInfo(virDomainPtr dom,
                         int ncpumaps,
                         unsigned char *cpumaps,
                         int maplen,
                         unsigned int flags) {
4469

4470
    virQEMUDriverPtr driver = dom->conn->privateData;
E
Eric Blake 已提交
4471
    virDomainObjPtr vm = NULL;
4472 4473 4474 4475
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    int maxcpu, hostcpus, vcpu, pcpu;
    int n;
E
Eric Blake 已提交
4476
    virDomainVcpuPinDefPtr *vcpupin_list;
H
Hu Tao 已提交
4477
    virBitmapPtr cpumask = NULL;
4478
    unsigned char *cpumap;
H
Hu Tao 已提交
4479
    bool pinned;
4480
    virCapsPtr caps = NULL;
4481 4482 4483 4484

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4485
    if (!(vm = qemuDomObjFromDomain(dom)))
4486 4487
        goto cleanup;

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

4491 4492 4493
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

4494
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
4495 4496
                                        &targetDef) < 0)
        goto cleanup;
4497 4498 4499 4500 4501

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

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

4505
    if ((hostcpus = nodeGetCPUCount()) < 0)
4506
        goto cleanup;
4507

4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535
    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 已提交
4536 4537 4538
            if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0)
                goto cleanup;
            if (!pinned)
4539 4540 4541 4542 4543 4544 4545
                VIR_UNUSE_CPU(cpumap, pcpu);
        }
    }
    ret = ncpumaps;

cleanup:
    if (vm)
4546
        virObjectUnlock(vm);
4547
    virObjectUnref(caps);
4548 4549 4550
    return ret;
}

H
Hu Tao 已提交
4551
static int
4552 4553 4554 4555
qemuDomainPinEmulator(virDomainPtr dom,
                      unsigned char *cpumap,
                      int maplen,
                      unsigned int flags)
H
Hu Tao 已提交
4556
{
4557
    virQEMUDriverPtr driver = dom->conn->privateData;
H
Hu Tao 已提交
4558 4559 4560 4561 4562 4563
    virDomainObjPtr vm;
    virCgroupPtr cgroup_emulator = NULL;
    pid_t pid;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
4564
    bool doReset = false;
H
Hu Tao 已提交
4565 4566
    int newVcpuPinNum = 0;
    virDomainVcpuPinDefPtr *newVcpuPin = NULL;
4567
    virBitmapPtr pcpumap = NULL;
4568
    virQEMUDriverConfigPtr cfg = NULL;
4569
    virCapsPtr caps = NULL;
H
Hu Tao 已提交
4570 4571 4572 4573

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4574 4575
    cfg = virQEMUDriverGetConfig(driver);

4576
    if (!(vm = qemuDomObjFromDomain(dom)))
H
Hu Tao 已提交
4577 4578
        goto cleanup;

4579 4580 4581
    if (virDomainPinEmulatorEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

4582 4583 4584
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

4585 4586 4587 4588 4589 4590 4591
    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;
    }

4592
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
H
Hu Tao 已提交
4593 4594 4595 4596 4597
                                        &persistentDef) < 0)
        goto cleanup;

    priv = vm->privateData;

4598 4599 4600 4601
    pcpumap = virBitmapNewData(cpumap, maplen);
    if (!pcpumap)
        goto cleanup;

4602 4603 4604 4605 4606 4607
    if (virBitmapIsAllClear(pcpumap)) {
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("Empty cpu list for pinning"));
        goto cleanup;
    }

H
Hu Tao 已提交
4608 4609 4610
    /* pinning to all physical cpus means resetting,
     * so check if we can reset setting.
     */
4611 4612
    if (virBitmapIsAllSet(pcpumap))
        doReset = true;
H
Hu Tao 已提交
4613 4614 4615 4616 4617 4618

    pid = vm->pid;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {

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

4622
            if (virDomainVcpuPinAdd(&newVcpuPin, &newVcpuPinNum, cpumap, maplen, -1) < 0) {
H
Hu Tao 已提交
4623 4624
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("failed to update vcpupin"));
H
Hu Tao 已提交
4625
                virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
H
Hu Tao 已提交
4626 4627 4628
                goto cleanup;
            }

4629 4630
            if (virCgroupHasController(priv->cgroup,
                                       VIR_CGROUP_CONTROLLER_CPUSET)) {
H
Hu Tao 已提交
4631 4632 4633
                /*
                 * Configure the corresponding cpuset cgroup.
                 */
4634 4635 4636 4637 4638 4639 4640 4641
                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 已提交
4642 4643
                }
            } else {
4644
                if (virProcessSetAffinity(pid, pcpumap) < 0) {
H
Hu Tao 已提交
4645 4646 4647 4648 4649 4650 4651
                    virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
                                   _("failed to set cpu affinity for "
                                     "emulator threads"));
                    goto cleanup;
                }
            }

4652
            if (doReset) {
H
Hu Tao 已提交
4653 4654 4655 4656 4657 4658 4659
                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 已提交
4660
                virDomainVcpuPinDefFree(vm->def->cputune.emulatorpin);
H
Hu Tao 已提交
4661 4662 4663 4664 4665
                vm->def->cputune.emulatorpin = newVcpuPin[0];
                VIR_FREE(newVcpuPin);
            }

            if (newVcpuPin)
H
Hu Tao 已提交
4666
                virDomainVcpuPinDefArrayFree(newVcpuPin, newVcpuPinNum);
H
Hu Tao 已提交
4667 4668 4669 4670 4671 4672
        } else {
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cpu affinity is not supported"));
            goto cleanup;
        }

4673
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
H
Hu Tao 已提交
4674 4675 4676 4677 4678
            goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {

4679
        if (doReset) {
H
Hu Tao 已提交
4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694
            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;
            }
        }

4695
        ret = virDomainSaveConfig(cfg->configDir, persistentDef);
H
Hu Tao 已提交
4696 4697 4698 4699 4700 4701 4702 4703
        goto cleanup;
    }

    ret = 0;

cleanup:
    if (cgroup_emulator)
        virCgroupFree(&cgroup_emulator);
4704
    virBitmapFree(pcpumap);
4705
    virObjectUnref(caps);
H
Hu Tao 已提交
4706
    if (vm)
4707
        virObjectUnlock(vm);
4708
    virObjectUnref(cfg);
H
Hu Tao 已提交
4709 4710 4711 4712
    return ret;
}

static int
4713 4714 4715 4716
qemuDomainGetEmulatorPinInfo(virDomainPtr dom,
                             unsigned char *cpumaps,
                             int maplen,
                             unsigned int flags)
H
Hu Tao 已提交
4717
{
4718
    virQEMUDriverPtr driver = dom->conn->privateData;
H
Hu Tao 已提交
4719 4720 4721 4722
    virDomainObjPtr vm = NULL;
    virDomainDefPtr targetDef = NULL;
    int ret = -1;
    int maxcpu, hostcpus, pcpu;
H
Hu Tao 已提交
4723 4724
    virBitmapPtr cpumask = NULL;
    bool pinned;
4725
    virCapsPtr caps = NULL;
H
Hu Tao 已提交
4726 4727 4728 4729

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

4730
    if (!(vm = qemuDomObjFromDomain(dom)))
H
Hu Tao 已提交
4731 4732
        goto cleanup;

4733 4734 4735
    if (virDomainGetEmulatorPinInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

4736 4737 4738
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

4739
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
4740
                                        vm, &flags, &targetDef) < 0)
H
Hu Tao 已提交
4741 4742 4743 4744 4745 4746 4747 4748
        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);

4749
    if ((hostcpus = nodeGetCPUCount()) < 0)
H
Hu Tao 已提交
4750
        goto cleanup;
4751

H
Hu Tao 已提交
4752 4753 4754 4755 4756 4757 4758 4759 4760 4761
    maxcpu = maplen * 8;
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;

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

4762 4763 4764 4765 4766
    if (targetDef->cputune.emulatorpin) {
        cpumask = targetDef->cputune.emulatorpin->cpumask;
    } else if (targetDef->cpumask) {
        cpumask = targetDef->cpumask;
    } else {
H
Hu Tao 已提交
4767 4768 4769 4770 4771
        ret = 0;
        goto cleanup;
    }

    for (pcpu = 0; pcpu < maxcpu; pcpu++) {
H
Hu Tao 已提交
4772 4773 4774
        if (virBitmapGetBit(cpumask, pcpu, &pinned) < 0)
            goto cleanup;
        if (!pinned)
H
Hu Tao 已提交
4775 4776 4777 4778 4779 4780 4781
            VIR_UNUSE_CPU(cpumaps, pcpu);
    }

    ret = 1;

cleanup:
    if (vm)
4782
        virObjectUnlock(vm);
4783
    virObjectUnref(caps);
H
Hu Tao 已提交
4784 4785 4786
    return ret;
}

4787
static int
4788 4789 4790 4791 4792
qemuDomainGetVcpus(virDomainPtr dom,
                   virVcpuInfoPtr info,
                   int maxinfo,
                   unsigned char *cpumaps,
                   int maplen) {
4793
    virDomainObjPtr vm;
4794 4795
    size_t i;
    int v, maxcpu, hostcpus;
4796
    int ret = -1;
4797
    qemuDomainObjPrivatePtr priv;
4798

4799
    if (!(vm = qemuDomObjFromDomain(dom)))
4800 4801
        goto cleanup;

4802 4803 4804
    if (virDomainGetVcpusEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

D
Daniel P. Berrange 已提交
4805
    if (!virDomainObjIsActive(vm)) {
4806 4807 4808
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s",
                       _("cannot list vcpu pinning for an inactive domain"));
4809
        goto cleanup;
4810 4811
    }

4812 4813
    priv = vm->privateData;

4814
    if ((hostcpus = nodeGetCPUCount()) < 0)
4815
        goto cleanup;
4816 4817

    maxcpu = maplen * 8;
4818 4819
    if (maxcpu > hostcpus)
        maxcpu = hostcpus;
4820 4821

    /* Clamp to actual number of vcpus */
4822 4823
    if (maxinfo > priv->nvcpupids)
        maxinfo = priv->nvcpupids;
4824

4825 4826 4827
    if (maxinfo >= 1) {
        if (info != NULL) {
            memset(info, 0, sizeof(*info) * maxinfo);
4828
            for (i = 0; i < maxinfo; i++) {
4829 4830
                info[i].number = i;
                info[i].state = VIR_VCPU_RUNNING;
4831

4832
                if (priv->vcpupids != NULL &&
4833 4834 4835 4836 4837
                    qemuGetProcessInfo(&(info[i].cpuTime),
                                       &(info[i].cpu),
                                       NULL,
                                       vm->pid,
                                       priv->vcpupids[i]) < 0) {
4838
                    virReportSystemError(errno, "%s",
4839 4840 4841
                                         _("cannot get vCPU placement & pCPU time"));
                    goto cleanup;
                }
4842
            }
4843 4844
        }

4845 4846
        if (cpumaps != NULL) {
            memset(cpumaps, 0, maplen * maxinfo);
4847
            if (priv->vcpupids != NULL) {
4848
                for (v = 0; v < maxinfo; v++) {
4849
                    unsigned char *cpumap = VIR_GET_CPUMAP(cpumaps, maplen, v);
4850 4851 4852
                    virBitmapPtr map = NULL;
                    unsigned char *tmpmap = NULL;
                    int tmpmapLen = 0;
4853

4854 4855
                    if (virProcessGetAffinity(priv->vcpupids[v],
                                              &map, maxcpu) < 0)
4856
                        goto cleanup;
4857 4858 4859 4860 4861 4862 4863
                    virBitmapToData(map, &tmpmap, &tmpmapLen);
                    if (tmpmapLen > maplen)
                        tmpmapLen = maplen;
                    memcpy(cpumap, tmpmap, tmpmapLen);

                    VIR_FREE(tmpmap);
                    virBitmapFree(map);
4864
                }
4865
            } else {
4866 4867
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("cpu affinity is not available"));
4868
                goto cleanup;
4869 4870 4871
            }
        }
    }
4872
    ret = maxinfo;
4873

4874
cleanup:
4875
    if (vm)
4876
        virObjectUnlock(vm);
4877
    return ret;
4878 4879 4880
}


4881
static int
4882
qemuDomainGetVcpusFlags(virDomainPtr dom, unsigned int flags)
4883
{
4884
    virQEMUDriverPtr driver = dom->conn->privateData;
4885
    qemuDomainObjPrivatePtr priv;
4886
    virDomainObjPtr vm;
4887
    virDomainDefPtr def;
4888
    int ret = -1;
4889
    virCapsPtr caps = NULL;
4890
    qemuAgentCPUInfoPtr cpuinfo = NULL;
4891
    int ncpuinfo = -1;
4892
    size_t i;
4893

4894 4895
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
4896
                  VIR_DOMAIN_VCPU_MAXIMUM |
4897
                  VIR_DOMAIN_VCPU_GUEST, -1);
4898

4899
    if (!(vm = qemuDomObjFromDomain(dom)))
4900 4901 4902
        return -1;

    priv = vm->privateData;
4903

4904
    if (virDomainGetVcpusFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
4905 4906
        goto cleanup;

4907 4908 4909
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

4910
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt,
4911
                                        vm, &flags, &def) < 0)
4912
        goto cleanup;
4913

4914
    if (flags & VIR_DOMAIN_AFFECT_LIVE)
4915
        def = vm->def;
4916

4917
    if (flags & VIR_DOMAIN_VCPU_GUEST) {
4918 4919 4920 4921 4922 4923 4924 4925 4926 4927
        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;

4928 4929 4930 4931 4932 4933 4934 4935 4936 4937 4938 4939 4940
        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;
        }

4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951
        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 已提交
4952
        if (!qemuDomainObjEndJob(driver, vm))
4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 4971 4972 4973
            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;
4974 4975 4976
    }


4977
cleanup:
4978
    if (vm)
4979
        virObjectUnlock(vm);
4980
    virObjectUnref(caps);
4981
    VIR_FREE(cpuinfo);
4982 4983 4984
    return ret;
}

4985
static int
4986
qemuDomainGetMaxVcpus(virDomainPtr dom)
4987
{
4988 4989
    return qemuDomainGetVcpusFlags(dom, (VIR_DOMAIN_AFFECT_LIVE |
                                         VIR_DOMAIN_VCPU_MAXIMUM));
4990 4991
}

4992
static int qemuDomainGetSecurityLabel(virDomainPtr dom, virSecurityLabelPtr seclabel)
4993
{
4994
    virQEMUDriverPtr driver = dom->conn->privateData;
4995 4996 4997
    virDomainObjPtr vm;
    int ret = -1;

4998 4999
    memset(seclabel, 0, sizeof(*seclabel));

5000 5001
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
5002

5003 5004 5005
    if (virDomainGetSecurityLabelEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

5006
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
5007 5008 5009
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
5010 5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026
        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 已提交
5027
    if (virDomainObjIsActive(vm)) {
5028
        if (virSecurityManagerGetProcessLabel(driver->securityManager,
5029
                                              vm->def, vm->pid, seclabel) < 0) {
5030 5031
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           "%s", _("Failed to get security label"));
5032
            goto cleanup;
5033 5034 5035 5036 5037 5038 5039
        }
    }

    ret = 0;

cleanup:
    if (vm)
5040
        virObjectUnlock(vm);
5041 5042 5043
    return ret;
}

M
Marcelo Cerri 已提交
5044 5045 5046
static int qemuDomainGetSecurityLabelList(virDomainPtr dom,
                                          virSecurityLabelPtr* seclabels)
{
5047
    virQEMUDriverPtr driver = dom->conn->privateData;
M
Marcelo Cerri 已提交
5048
    virDomainObjPtr vm;
5049 5050
    size_t i;
    int ret = -1;
M
Marcelo Cerri 已提交
5051

5052 5053
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
M
Marcelo Cerri 已提交
5054

5055 5056 5057
    if (virDomainGetSecurityLabelListEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

M
Marcelo Cerri 已提交
5058 5059 5060 5061 5062 5063 5064 5065
    if (!virDomainVirtTypeToString(vm->def->virtType)) {
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("unknown virt type in domain definition '%d'"),
                       vm->def->virtType);
        goto cleanup;
    }

    /*
5066
     * Check the comment in qemuDomainGetSecurityLabel function.
M
Marcelo Cerri 已提交
5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 5081 5082 5083 5084 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105
     */
    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)
5106
        virObjectUnlock(vm);
M
Marcelo Cerri 已提交
5107 5108
    return ret;
}
5109 5110


5111 5112
static int qemuNodeGetSecurityModel(virConnectPtr conn,
                                    virSecurityModelPtr secmodel)
5113
{
5114
    virQEMUDriverPtr driver = conn->privateData;
5115
    char *p;
5116
    int ret = 0;
5117
    virCapsPtr caps = NULL;
5118

5119 5120
    memset(secmodel, 0, sizeof(*secmodel));

5121 5122 5123
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

5124 5125 5126
    if (virNodeGetSecurityModelEnsureACL(conn) < 0)
        goto cleanup;

5127
    /* We treat no driver as success, but simply return no data in *secmodel */
5128 5129
    if (caps->host.nsecModels == 0 ||
        caps->host.secModels[0].model == NULL)
5130
        goto cleanup;
5131

5132
    p = caps->host.secModels[0].model;
5133
    if (strlen(p) >= VIR_SECURITY_MODEL_BUFLEN-1) {
5134 5135 5136
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security model string exceeds max %d bytes"),
                       VIR_SECURITY_MODEL_BUFLEN-1);
5137 5138
        ret = -1;
        goto cleanup;
5139 5140 5141
    }
    strcpy(secmodel->model, p);

5142
    p = caps->host.secModels[0].doi;
5143
    if (strlen(p) >= VIR_SECURITY_DOI_BUFLEN-1) {
5144 5145 5146
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("security DOI string exceeds max %d bytes"),
                       VIR_SECURITY_DOI_BUFLEN-1);
5147 5148
        ret = -1;
        goto cleanup;
5149 5150
    }
    strcpy(secmodel->doi, p);
5151 5152

cleanup:
5153
    virObjectUnref(caps);
5154
    return ret;
5155 5156
}

E
Eric Blake 已提交
5157
/* Return -1 on most failures after raising error, -2 if edit was specified
5158 5159 5160
 * 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.  */
5161
static int ATTRIBUTE_NONNULL(3) ATTRIBUTE_NONNULL(4)
5162
qemuDomainSaveImageOpen(virQEMUDriverPtr driver,
5163 5164
                        const char *path,
                        virDomainDefPtr *ret_def,
5165
                        virQEMUSaveHeaderPtr ret_header,
J
Jiri Denemark 已提交
5166 5167
                        bool bypass_cache,
                        virFileWrapperFdPtr *wrapperFd,
5168 5169
                        const char *xmlin, int state, bool edit,
                        bool unlink_corrupt)
J
Jiri Denemark 已提交
5170
{
W
Wen Congyang 已提交
5171
    int fd = -1;
5172
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
5173 5174
    char *xml = NULL;
    virDomainDefPtr def = NULL;
5175
    int oflags = edit ? O_RDWR : O_RDONLY;
5176
    virCapsPtr caps = NULL;
5177

5178
    if (bypass_cache) {
5179
        int directFlag = virFileDirectFdFlag();
5180
        if (directFlag < 0) {
5181 5182
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("bypass cache unsupported by this system"));
5183 5184
            goto error;
        }
5185
        oflags |= directFlag;
5186
    }
5187

5188 5189 5190
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto error;

5191
    if ((fd = qemuOpenFile(driver, NULL, path, oflags, NULL, NULL)) < 0)
E
Eric Blake 已提交
5192
        goto error;
J
Jiri Denemark 已提交
5193 5194 5195
    if (bypass_cache &&
        !(*wrapperFd = virFileWrapperFdNew(&fd, path,
                                           VIR_FILE_WRAPPER_BYPASS_CACHE)))
5196
        goto error;
5197 5198

    if (saferead(fd, &header, sizeof(header)) != sizeof(header)) {
5199 5200 5201 5202 5203 5204 5205 5206 5207
        if (unlink_corrupt) {
            if (VIR_CLOSE(fd) < 0 || unlink(path) < 0) {
                virReportSystemError(errno,
                                     _("cannot remove corrupt file: %s"),
                                     path);
                goto error;
            }
            return -3;
        }
5208 5209
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to read qemu header"));
J
Jiri Denemark 已提交
5210
        goto error;
5211 5212
    }

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

5216
        if (memcmp(header.magic, QEMU_SAVE_PARTIAL,
E
Eric Blake 已提交
5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228
                   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;
            }
        }
5229
        virReportError(VIR_ERR_OPERATION_FAILED, "%s", msg);
J
Jiri Denemark 已提交
5230
        goto error;
5231 5232
    }

5233
    if (header.version > QEMU_SAVE_VERSION) {
5234 5235 5236 5237
        /* convert endianess and try again */
        bswap_header(&header);
    }

5238
    if (header.version > QEMU_SAVE_VERSION) {
5239 5240
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("image version is not supported (%d > %d)"),
5241
                       header.version, QEMU_SAVE_VERSION);
J
Jiri Denemark 已提交
5242
        goto error;
5243 5244
    }

5245
    if (header.xml_len <= 0) {
5246 5247
        virReportError(VIR_ERR_OPERATION_FAILED,
                       _("invalid XML length: %d"), header.xml_len);
J
Jiri Denemark 已提交
5248
        goto error;
5249 5250
    }

5251
    if (VIR_ALLOC_N(xml, header.xml_len) < 0)
J
Jiri Denemark 已提交
5252
        goto error;
5253 5254

    if (saferead(fd, xml, header.xml_len) != header.xml_len) {
5255 5256
        virReportError(VIR_ERR_OPERATION_FAILED,
                       "%s", _("failed to read XML"));
J
Jiri Denemark 已提交
5257
        goto error;
5258 5259
    }

5260 5261
    if (edit && STREQ(xml, xmlin) &&
        (state < 0 || state == header.was_running)) {
5262 5263 5264 5265 5266 5267 5268
        VIR_FREE(xml);
        if (VIR_CLOSE(fd) < 0) {
            virReportSystemError(errno, _("cannot close file: %s"), path);
            goto error;
        }
        return -2;
    }
5269 5270
    if (state >= 0)
        header.was_running = state;
5271

5272
    /* Create a domain from this XML */
5273
    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
M
Matthias Bolte 已提交
5274
                                        QEMU_EXPECTED_VIRT_TYPES,
5275
                                        VIR_DOMAIN_XML_INACTIVE)))
J
Jiri Denemark 已提交
5276
        goto error;
5277 5278
    if (xmlin) {
        virDomainDefPtr def2 = NULL;
5279
        virDomainDefPtr newdef = NULL;
5280

5281
        if (!(def2 = virDomainDefParseString(xmlin, caps, driver->xmlopt,
5282 5283 5284
                                             QEMU_EXPECTED_VIRT_TYPES,
                                             VIR_DOMAIN_XML_INACTIVE)))
            goto error;
5285 5286

        newdef = qemuDomainDefCopy(driver, def2, VIR_DOMAIN_XML_MIGRATABLE);
5287 5288
        if (!newdef) {
            virDomainDefFree(def2);
5289
            goto error;
5290
        }
5291 5292 5293

        if (!virDomainDefCheckABIStability(def, newdef)) {
            virDomainDefFree(newdef);
5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309
            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;
5310 5311
        } else {
            virDomainDefFree(def2);
5312
        }
5313

5314
        virDomainDefFree(def);
5315
        def = newdef;
5316
    }
5317

J
Jiri Denemark 已提交
5318
    VIR_FREE(xml);
5319

J
Jiri Denemark 已提交
5320 5321
    *ret_def = def;
    *ret_header = header;
5322

5323 5324
    virObjectUnref(caps);

J
Jiri Denemark 已提交
5325
    return fd;
5326

J
Jiri Denemark 已提交
5327 5328 5329
error:
    virDomainDefFree(def);
    VIR_FREE(xml);
5330
    VIR_FORCE_CLOSE(fd);
5331
    virObjectUnref(caps);
J
Jiri Denemark 已提交
5332 5333 5334 5335

    return -1;
}

5336 5337
static int ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(5) ATTRIBUTE_NONNULL(6)
qemuDomainSaveImageStartVM(virConnectPtr conn,
5338
                           virQEMUDriverPtr driver,
5339 5340
                           virDomainObjPtr vm,
                           int *fd,
E
Eric Blake 已提交
5341
                           const virQEMUSaveHeader *header,
5342 5343
                           const char *path,
                           bool start_paused)
J
Jiri Denemark 已提交
5344 5345
{
    int ret = -1;
5346
    virObjectEventPtr event;
J
Jiri Denemark 已提交
5347
    int intermediatefd = -1;
5348
    virCommandPtr cmd = NULL;
5349
    char *errbuf = NULL;
5350
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
J
Jiri Denemark 已提交
5351

5352 5353 5354
    if ((header->version == 2) &&
        (header->compressed != QEMU_SAVE_FORMAT_RAW)) {
        if (!(cmd = qemuCompressGetCommand(header->compressed)))
5355
            goto cleanup;
5356

5357 5358
        intermediatefd = *fd;
        *fd = -1;
5359

5360 5361 5362 5363
        virCommandSetInputFD(cmd, intermediatefd);
        virCommandSetOutputFD(cmd, fd);
        virCommandSetErrorBuffer(cmd, &errbuf);
        virCommandDoAsyncIO(cmd);
5364

5365 5366 5367
        if (virCommandRunAsync(cmd, NULL) < 0) {
            *fd = intermediatefd;
            goto cleanup;
5368 5369
        }
    }
J
Jiri Denemark 已提交
5370

5371
    /* Set the migration source and start it up. */
5372 5373 5374
    ret = qemuProcessStart(conn, driver, vm, "stdio", *fd, path, NULL,
                           VIR_NETDEV_VPORT_PROFILE_OP_RESTORE,
                           VIR_QEMU_PROCESS_START_PAUSED);
J
Jiri Denemark 已提交
5375

5376
    if (intermediatefd != -1) {
5377
        if (ret < 0) {
5378 5379 5380
            /* if there was an error setting up qemu, the intermediate
             * process will wait forever to write to stdout, so we
             * must manually kill it.
5381 5382
             */
            VIR_FORCE_CLOSE(intermediatefd);
5383
            VIR_FORCE_CLOSE(*fd);
5384 5385
        }

5386 5387
        if (virCommandWait(cmd, NULL) < 0) {
            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FAILED, 0);
5388
            ret = -1;
5389
        }
5390
        VIR_DEBUG("Decompression binary stderr: %s", NULLSTR(errbuf));
5391
    }
5392
    VIR_FORCE_CLOSE(intermediatefd);
J
Jiri Denemark 已提交
5393

5394 5395 5396
    if (VIR_CLOSE(*fd) < 0) {
        virReportSystemError(errno, _("cannot close file: %s"), path);
        ret = -1;
5397
    }
J
Jiri Denemark 已提交
5398

5399
    if (ret < 0) {
5400
        virDomainAuditStart(vm, "restored", false);
5401
        goto cleanup;
5402
    }
5403

5404
    event = virDomainEventLifecycleNewFromObj(vm,
5405 5406
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_RESTORED);
5407
    virDomainAuditStart(vm, "restored", true);
J
Jiri Denemark 已提交
5408 5409 5410
    if (event)
        qemuDomainEventQueue(driver, event);

5411

5412 5413
    /* If it was running before, resume it now unless caller requested pause. */
    if (header->was_running && !start_paused) {
J
Jiri Denemark 已提交
5414
        if (qemuProcessStartCPUs(driver, vm, conn,
5415 5416
                                 VIR_DOMAIN_RUNNING_RESTORED,
                                 QEMU_ASYNC_JOB_NONE) < 0) {
5417
            if (virGetLastError() == NULL)
5418 5419
                virReportError(VIR_ERR_OPERATION_FAILED,
                               "%s", _("failed to resume domain"));
5420
            goto cleanup;
5421
        }
5422
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
5423
            VIR_WARN("Failed to save status on vm %s", vm->def->name);
5424
            goto cleanup;
5425
        }
5426 5427 5428
    } else {
        int detail = (start_paused ? VIR_DOMAIN_EVENT_SUSPENDED_PAUSED :
                      VIR_DOMAIN_EVENT_SUSPENDED_RESTORED);
5429
        event = virDomainEventLifecycleNewFromObj(vm,
5430 5431 5432 5433
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         detail);
        if (event)
            qemuDomainEventQueue(driver, event);
5434
    }
J
Jiri Denemark 已提交
5435

5436
    ret = 0;
5437

5438
cleanup:
5439
    virCommandFree(cmd);
5440
    VIR_FREE(errbuf);
5441
    if (virSecurityManagerRestoreSavedStateLabel(driver->securityManager,
5442
                                                 vm->def, path) < 0)
5443
        VIR_WARN("failed to restore save state label on %s", path);
5444
    virObjectUnref(cfg);
J
Jiri Denemark 已提交
5445 5446 5447
    return ret;
}

5448
static int
5449 5450 5451 5452
qemuDomainRestoreFlags(virConnectPtr conn,
                       const char *path,
                       const char *dxml,
                       unsigned int flags)
5453
{
5454
    virQEMUDriverPtr driver = conn->privateData;
J
Jiri Denemark 已提交
5455 5456 5457 5458
    virDomainDefPtr def = NULL;
    virDomainObjPtr vm = NULL;
    int fd = -1;
    int ret = -1;
5459
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
5460
    virFileWrapperFdPtr wrapperFd = NULL;
5461
    int state = -1;
J
Jiri Denemark 已提交
5462

5463 5464 5465
    virCheckFlags(VIR_DOMAIN_SAVE_BYPASS_CACHE |
                  VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
5466

J
Jiri Denemark 已提交
5467

5468 5469 5470 5471 5472
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

5473 5474
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
                                 (flags & VIR_DOMAIN_SAVE_BYPASS_CACHE) != 0,
J
Jiri Denemark 已提交
5475
                                 &wrapperFd, dxml, state, false, false);
J
Jiri Denemark 已提交
5476 5477 5478
    if (fd < 0)
        goto cleanup;

5479 5480 5481
    if (virDomainRestoreFlagsEnsureACL(conn, def) < 0)
        goto cleanup;

5482
    if (!(vm = virDomainObjListAdd(driver->domains, def,
5483
                                   driver->xmlopt,
5484 5485 5486
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
J
Jiri Denemark 已提交
5487 5488 5489
        goto cleanup;
    def = NULL;

5490
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
J
Jiri Denemark 已提交
5491 5492
        goto cleanup;

5493 5494
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     false);
J
Jiri Denemark 已提交
5495
    if (virFileWrapperFdClose(wrapperFd) < 0)
5496
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
5497

E
Eric Blake 已提交
5498
    if (!qemuDomainObjEndJob(driver, vm))
5499
        vm = NULL;
J
Jiri Denemark 已提交
5500
    else if (ret < 0 && !vm->persistent) {
5501
        qemuDomainRemoveInactive(driver, vm);
J
Jiri Denemark 已提交
5502 5503
        vm = NULL;
    }
5504

5505 5506
cleanup:
    virDomainDefFree(def);
5507
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
5508
    virFileWrapperFdFree(wrapperFd);
5509
    if (vm)
5510
        virObjectUnlock(vm);
5511
    return ret;
D
Daniel P. Berrange 已提交
5512 5513
}

5514 5515 5516 5517 5518 5519 5520
static int
qemuDomainRestore(virConnectPtr conn,
                  const char *path)
{
    return qemuDomainRestoreFlags(conn, path, NULL, 0);
}

5521 5522 5523 5524
static char *
qemuDomainSaveImageGetXMLDesc(virConnectPtr conn, const char *path,
                              unsigned int flags)
{
5525
    virQEMUDriverPtr driver = conn->privateData;
5526 5527 5528
    char *ret = NULL;
    virDomainDefPtr def = NULL;
    int fd = -1;
5529
    virQEMUSaveHeader header;
5530 5531 5532 5533 5534

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

    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
5535
                                 NULL, -1, false, false);
5536 5537 5538 5539

    if (fd < 0)
        goto cleanup;

5540 5541 5542
    if (virDomainSaveImageGetXMLDescEnsureACL(conn, def) < 0)
        goto cleanup;

5543
    ret = qemuDomainDefFormatXML(driver, def, flags);
5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554

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

static int
qemuDomainSaveImageDefineXML(virConnectPtr conn, const char *path,
                             const char *dxml, unsigned int flags)
{
5555
    virQEMUDriverPtr driver = conn->privateData;
5556 5557 5558
    int ret = -1;
    virDomainDefPtr def = NULL;
    int fd = -1;
5559
    virQEMUSaveHeader header;
5560 5561
    char *xml = NULL;
    size_t len;
5562
    int state = -1;
5563

5564 5565
    virCheckFlags(VIR_DOMAIN_SAVE_RUNNING |
                  VIR_DOMAIN_SAVE_PAUSED, -1);
5566

5567 5568 5569 5570 5571
    if (flags & VIR_DOMAIN_SAVE_RUNNING)
        state = 1;
    else if (flags & VIR_DOMAIN_SAVE_PAUSED)
        state = 0;

5572
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header, false, NULL,
5573
                                 dxml, state, true, false);
5574 5575 5576 5577 5578 5579 5580 5581

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

5582 5583 5584
    if (virDomainSaveImageDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

5585 5586
    xml = qemuDomainDefFormatXML(driver, def,
                                 VIR_DOMAIN_XML_INACTIVE |
5587 5588
                                 VIR_DOMAIN_XML_SECURE |
                                 VIR_DOMAIN_XML_MIGRATABLE);
5589 5590 5591 5592 5593
    if (!xml)
        goto cleanup;
    len = strlen(xml) + 1;

    if (len > header.xml_len) {
5594 5595
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("new xml too large to fit in file"));
5596 5597
        goto cleanup;
    }
5598
    if (VIR_EXPAND_N(xml, len, header.xml_len - len) < 0)
5599 5600
        goto cleanup;

5601
    if (lseek(fd, 0, SEEK_SET) != 0) {
5602 5603 5604
        virReportSystemError(errno, _("cannot seek in '%s'"), path);
        goto cleanup;
    }
5605 5606
    if (safewrite(fd, &header, sizeof(header)) != sizeof(header) ||
        safewrite(fd, xml, len) != len ||
5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620
        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 已提交
5621 5622
/* Return 0 on success, 1 if incomplete saved image was silently unlinked,
 * and -1 on failure with error raised.  */
5623 5624
static int
qemuDomainObjRestore(virConnectPtr conn,
5625
                     virQEMUDriverPtr driver,
5626
                     virDomainObjPtr vm,
5627
                     const char *path,
5628
                     bool start_paused,
5629
                     bool bypass_cache)
J
Jiri Denemark 已提交
5630 5631 5632 5633
{
    virDomainDefPtr def = NULL;
    int fd = -1;
    int ret = -1;
5634
    virQEMUSaveHeader header;
J
Jiri Denemark 已提交
5635
    virFileWrapperFdPtr wrapperFd = NULL;
J
Jiri Denemark 已提交
5636

5637
    fd = qemuDomainSaveImageOpen(driver, path, &def, &header,
J
Jiri Denemark 已提交
5638
                                 bypass_cache, &wrapperFd, NULL, -1, false,
5639
                                 true);
E
Eric Blake 已提交
5640 5641 5642
    if (fd < 0) {
        if (fd == -3)
            ret = 1;
J
Jiri Denemark 已提交
5643
        goto cleanup;
E
Eric Blake 已提交
5644
    }
J
Jiri Denemark 已提交
5645 5646 5647 5648 5649 5650 5651

    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);
5652 5653 5654 5655 5656
        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 已提交
5657 5658 5659
        goto cleanup;
    }

5660
    virDomainObjAssignDef(vm, def, true, NULL);
J
Jiri Denemark 已提交
5661 5662
    def = NULL;

5663 5664
    ret = qemuDomainSaveImageStartVM(conn, driver, vm, &fd, &header, path,
                                     start_paused);
J
Jiri Denemark 已提交
5665
    if (virFileWrapperFdClose(wrapperFd) < 0)
5666
        VIR_WARN("Failed to close %s", path);
J
Jiri Denemark 已提交
5667 5668 5669

cleanup:
    virDomainDefFree(def);
5670
    VIR_FORCE_CLOSE(fd);
J
Jiri Denemark 已提交
5671
    virFileWrapperFdFree(wrapperFd);
J
Jiri Denemark 已提交
5672 5673 5674
    return ret;
}

D
Daniel P. Berrange 已提交
5675

5676
static char *qemuDomainGetXMLDesc(virDomainPtr dom,
5677 5678
                                  unsigned int flags)
{
5679
    virQEMUDriverPtr driver = dom->conn->privateData;
5680 5681
    virDomainObjPtr vm;
    char *ret = NULL;
5682
    unsigned long long balloon;
5683
    int err = 0;
5684
    qemuDomainObjPrivatePtr priv;
5685

5686
    /* Flags checked by virDomainDefFormat */
5687

5688
    if (!(vm = qemuDomObjFromDomain(dom)))
5689
        goto cleanup;
D
Daniel P. Berrange 已提交
5690

5691 5692
    priv = vm->privateData;

5693 5694 5695
    if (virDomainGetXMLDescEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

5696 5697 5698
    /* Refresh current memory based on balloon info if supported */
    if ((vm->def->memballoon != NULL) &&
        (vm->def->memballoon->model != VIR_DOMAIN_MEMBALLOON_MODEL_NONE) &&
5699
        !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BALLOON_EVENT) &&
5700
        (virDomainObjIsActive(vm))) {
5701 5702
        /* Don't delay if someone's using the monitor, just use
         * existing most recent data instead */
5703
        if (qemuDomainJobAllowed(priv, QEMU_JOB_QUERY)) {
5704
            if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
5705 5706
                goto cleanup;

5707
            if (!virDomainObjIsActive(vm)) {
5708 5709
                virReportError(VIR_ERR_OPERATION_INVALID,
                               "%s", _("domain is not running"));
5710 5711 5712
                goto endjob;
            }

5713
            qemuDomainObjEnterMonitor(driver, vm);
5714
            err = qemuMonitorGetBalloonInfo(priv->mon, &balloon);
5715
            qemuDomainObjExitMonitor(driver, vm);
5716 5717

endjob:
E
Eric Blake 已提交
5718
            if (!qemuDomainObjEndJob(driver, vm)) {
5719 5720 5721
                vm = NULL;
                goto cleanup;
            }
5722 5723 5724
            if (err < 0)
                goto cleanup;
            if (err > 0)
5725
                vm->def->mem.cur_balloon = balloon;
5726 5727
            /* err == 0 indicates no balloon support, so ignore it */
        }
5728
    }
5729

5730 5731 5732 5733
    if ((flags & VIR_DOMAIN_XML_MIGRATABLE))
        flags |= QEMU_DOMAIN_FORMAT_LIVE_FLAGS;

    ret = qemuDomainFormatXML(driver, vm, flags);
5734 5735

cleanup:
5736
    if (vm)
5737
        virObjectUnlock(vm);
5738
    return ret;
D
Daniel P. Berrange 已提交
5739 5740 5741
}


5742 5743 5744 5745
static char *qemuConnectDomainXMLFromNative(virConnectPtr conn,
                                            const char *format,
                                            const char *config,
                                            unsigned int flags)
E
Eric Blake 已提交
5746
{
5747
    virQEMUDriverPtr driver = conn->privateData;
5748 5749
    virDomainDefPtr def = NULL;
    char *xml = NULL;
5750
    virCapsPtr caps = NULL;
5751

E
Eric Blake 已提交
5752 5753
    virCheckFlags(0, NULL);

5754 5755 5756
    if (virConnectDomainXMLFromNativeEnsureACL(conn) < 0)
        goto cleanup;

5757
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
5758 5759
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), format);
5760 5761 5762
        goto cleanup;
    }

5763 5764 5765
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

5766
    def = qemuParseCommandLineString(caps, driver->xmlopt, config,
5767
                                     NULL, NULL, NULL);
5768 5769 5770
    if (!def)
        goto cleanup;

5771
    if (!def->name && VIR_STRDUP(def->name, "unnamed") < 0)
5772 5773
        goto cleanup;

5774
    xml = qemuDomainDefFormatXML(driver, def, VIR_DOMAIN_XML_INACTIVE);
5775 5776 5777

cleanup:
    virDomainDefFree(def);
5778
    virObjectUnref(caps);
5779 5780 5781
    return xml;
}

5782 5783 5784 5785
static char *qemuConnectDomainXMLToNative(virConnectPtr conn,
                                          const char *format,
                                          const char *xmlData,
                                          unsigned int flags)
E
Eric Blake 已提交
5786
{
5787
    virQEMUDriverPtr driver = conn->privateData;
5788
    virDomainDefPtr def = NULL;
5789
    virDomainChrSourceDef monConfig;
5790
    virQEMUCapsPtr qemuCaps = NULL;
T
tangchen 已提交
5791
    bool monitor_json = false;
E
Eric Blake 已提交
5792
    virCommandPtr cmd = NULL;
5793
    char *ret = NULL;
5794
    size_t i;
5795
    virQEMUDriverConfigPtr cfg;
5796
    virCapsPtr caps = NULL;
5797

E
Eric Blake 已提交
5798 5799
    virCheckFlags(0, NULL);

5800
    cfg = virQEMUDriverGetConfig(driver);
5801

5802 5803 5804
    if (virConnectDomainXMLToNativeEnsureACL(conn) < 0)
        goto cleanup;

5805
    if (STRNEQ(format, QEMU_CONFIG_FORMAT_ARGV)) {
5806 5807
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unsupported config type %s"), format);
5808 5809 5810
        goto cleanup;
    }

5811 5812 5813
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

5814
    def = virDomainDefParseString(xmlData, caps, driver->xmlopt,
M
Matthias Bolte 已提交
5815
                                  QEMU_EXPECTED_VIRT_TYPES, 0);
5816 5817 5818
    if (!def)
        goto cleanup;

5819
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
5820 5821
        goto cleanup;

5822 5823
    /* Since we're just exporting args, we can't do bridge/network/direct
     * setups, since libvirt will normally create TAP/macvtap devices
5824 5825 5826
     * directly. We convert those configs into generic 'ethernet'
     * config and assume the user has suitable 'ifup-qemu' scripts
     */
5827
    for (i = 0; i < def->nnets; i++) {
5828
        virDomainNetDefPtr net = def->nets[i];
5829
        int bootIndex = net->info.bootIndex;
5830
        char *model = net->model;
5831
        virMacAddr mac = net->mac;
5832

5833 5834 5835 5836
        if (net->type == VIR_DOMAIN_NET_TYPE_NETWORK) {
            int actualType = virDomainNetGetActualType(net);
            const char *brname;

5837
            VIR_FREE(net->data.network.name);
5838 5839 5840 5841
            VIR_FREE(net->data.network.portgroup);
            if ((actualType == VIR_DOMAIN_NET_TYPE_BRIDGE) &&
                (brname = virDomainNetGetActualBridgeName(net))) {

5842 5843
                char *brnamecopy;
                if (VIR_STRDUP(brnamecopy, brname) < 0)
5844 5845 5846 5847
                    goto cleanup;

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

5848
                memset(net, 0, sizeof(*net));
5849 5850

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5851
                net->script = NULL;
5852 5853 5854 5855 5856 5857 5858
                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);
5859
                memset(net, 0, sizeof(*net));
5860 5861

                net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5862
                net->script = NULL;
5863 5864 5865 5866 5867
                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);
5868

5869
            memset(net, 0, sizeof(*net));
5870 5871

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5872
            net->script = NULL;
5873 5874 5875
            net->data.ethernet.dev = NULL;
            net->data.ethernet.ipaddr = NULL;
        } else if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
5876
            char *script = net->script;
5877 5878 5879
            char *brname = net->data.bridge.brname;
            char *ipaddr = net->data.bridge.ipaddr;

5880
            memset(net, 0, sizeof(*net));
5881 5882

            net->type = VIR_DOMAIN_NET_TYPE_ETHERNET;
5883
            net->script = script;
5884 5885 5886
            net->data.ethernet.dev = brname;
            net->data.ethernet.ipaddr = ipaddr;
        }
5887

5888
        VIR_FREE(net->virtPortProfile);
5889
        net->info.bootIndex = bootIndex;
5890
        net->model = model;
5891
        net->mac = mac;
5892 5893
    }

5894
    monitor_json = virQEMUCapsGet(qemuCaps, QEMU_CAPS_MONITOR_JSON);
T
tangchen 已提交
5895

5896
    if (qemuProcessPrepareMonitorChr(cfg, &monConfig, def->name) < 0)
5897
        goto cleanup;
5898

5899
    if (qemuAssignDeviceAliases(def, qemuCaps) < 0)
5900 5901
        goto cleanup;

5902 5903 5904
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
        goto cleanup;

5905
    /* do fake auto-alloc of graphics ports, if such config is used */
5906
    for (i = 0; i < def->ngraphics; ++i) {
5907 5908 5909 5910 5911
        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) {
5912
            size_t j;
5913 5914 5915 5916 5917 5918
            bool needTLSPort = false;
            bool needPort = false;
            int defaultMode = graphics->data.spice.defaultMode;

            if (graphics->data.spice.autoport) {
                /* check if tlsPort or port need allocation */
5919
                for (j = 0; j < VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST; j++) {
5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 5933 5934 5935 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956
                    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;
        }
    }

5957
    if (!(cmd = qemuBuildCommandLine(conn, driver, def,
5958
                                     &monConfig, monitor_json, qemuCaps,
5959 5960
                                     NULL, -1, NULL, VIR_NETDEV_VPORT_PROFILE_OP_NO_OP,
                                     &buildCommandLineCallbacks)))
5961 5962
        goto cleanup;

E
Eric Blake 已提交
5963
    ret = virCommandToString(cmd);
5964 5965 5966

cleanup:

5967
    virObjectUnref(qemuCaps);
E
Eric Blake 已提交
5968
    virCommandFree(cmd);
5969
    virDomainDefFree(def);
5970
    virObjectUnref(caps);
5971
    virObjectUnref(cfg);
5972 5973 5974 5975
    return ret;
}


5976 5977
static int qemuConnectListDefinedDomains(virConnectPtr conn,
                                         char **const names, int nnames) {
5978
    virQEMUDriverPtr driver = conn->privateData;
5979
    int ret = -1;
5980

5981 5982 5983
    if (virConnectListDefinedDomainsEnsureACL(conn) < 0)
        goto cleanup;

5984
    ret = virDomainObjListGetInactiveNames(driver->domains, names, nnames,
5985 5986
                                           virConnectListDefinedDomainsCheckACL,
                                           conn);
5987 5988 5989

cleanup:
    return ret;
D
Daniel P. Berrange 已提交
5990 5991
}

5992
static int qemuConnectNumOfDefinedDomains(virConnectPtr conn) {
5993
    virQEMUDriverPtr driver = conn->privateData;
5994 5995 5996 5997
    int ret = -1;

    if (virConnectNumOfDefinedDomainsEnsureACL(conn) < 0)
        goto cleanup;
5998

5999
    ret = virDomainObjListNumOfDomains(driver->domains, false,
6000 6001
                                       virConnectNumOfDefinedDomainsCheckACL,
                                       conn);
6002

6003 6004
cleanup:
    return ret;
D
Daniel P. Berrange 已提交
6005 6006 6007
}


6008 6009
static int
qemuDomainObjStart(virConnectPtr conn,
6010
                   virQEMUDriverPtr driver,
6011
                   virDomainObjPtr vm,
6012
                   unsigned int flags)
J
Jiri Denemark 已提交
6013 6014 6015
{
    int ret = -1;
    char *managed_save;
6016 6017 6018 6019
    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;
6020 6021 6022
    unsigned int start_flags = VIR_QEMU_PROCESS_START_COLD;

    start_flags |= start_paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
6023
    start_flags |= autodestroy ? VIR_QEMU_PROCESS_START_AUTODESTROY : 0;
J
Jiri Denemark 已提交
6024 6025 6026

    /*
     * If there is a managed saved state restore it instead of starting
6027
     * from scratch. The old state is removed once the restoring succeeded.
J
Jiri Denemark 已提交
6028 6029
     */
    managed_save = qemuDomainManagedSavePath(driver, vm);
6030 6031 6032 6033

    if (!managed_save)
        goto cleanup;

E
Eric Blake 已提交
6034
    if (virFileExists(managed_save)) {
6035 6036 6037 6038 6039 6040 6041
        if (force_boot) {
            if (unlink(managed_save) < 0) {
                virReportSystemError(errno,
                                     _("cannot remove managed save file %s"),
                                     managed_save);
                goto cleanup;
            }
6042
            vm->hasManagedSave = false;
6043 6044
        } else {
            ret = qemuDomainObjRestore(conn, driver, vm, managed_save,
6045
                                       start_paused, bypass_cache);
J
Jiri Denemark 已提交
6046

6047 6048 6049 6050 6051 6052 6053
            if (ret == 0) {
                if (unlink(managed_save) < 0)
                    VIR_WARN("Failed to remove the managed state %s", managed_save);
                else
                    vm->hasManagedSave = false;
            }

6054
            if (ret > 0) {
E
Eric Blake 已提交
6055
                VIR_WARN("Ignoring incomplete managed state %s", managed_save);
6056 6057 6058
            } else {
                VIR_WARN("Unable to restore from managed state %s. "
                         "Maybe the file is corrupted?", managed_save);
E
Eric Blake 已提交
6059
                goto cleanup;
6060
            }
6061
        }
J
Jiri Denemark 已提交
6062 6063
    }

6064 6065
    ret = qemuProcessStart(conn, driver, vm, NULL, -1, NULL, NULL,
                           VIR_NETDEV_VPORT_PROFILE_OP_CREATE, start_flags);
6066
    virDomainAuditStart(vm, "booted", ret >= 0);
6067
    if (ret >= 0) {
6068
        virObjectEventPtr event =
6069
            virDomainEventLifecycleNewFromObj(vm,
J
Jiri Denemark 已提交
6070 6071
                                     VIR_DOMAIN_EVENT_STARTED,
                                     VIR_DOMAIN_EVENT_STARTED_BOOTED);
6072
        if (event) {
J
Jiri Denemark 已提交
6073
            qemuDomainEventQueue(driver, event);
6074
            if (start_paused) {
6075
                event = virDomainEventLifecycleNewFromObj(vm,
6076 6077 6078 6079 6080 6081
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 VIR_DOMAIN_EVENT_SUSPENDED_PAUSED);
                if (event)
                    qemuDomainEventQueue(driver, event);
            }
        }
J
Jiri Denemark 已提交
6082 6083 6084 6085 6086 6087 6088
    }

cleanup:
    VIR_FREE(managed_save);
    return ret;
}

6089
static int
6090
qemuDomainCreateWithFlags(virDomainPtr dom, unsigned int flags)
6091
{
6092
    virQEMUDriverPtr driver = dom->conn->privateData;
6093 6094
    virDomainObjPtr vm;
    int ret = -1;
6095

6096
    virCheckFlags(VIR_DOMAIN_START_PAUSED |
6097
                  VIR_DOMAIN_START_AUTODESTROY |
6098 6099
                  VIR_DOMAIN_START_BYPASS_CACHE |
                  VIR_DOMAIN_START_FORCE_BOOT, -1);
6100

6101 6102
    virNWFilterReadLockFilterUpdates();

6103 6104
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
6105

6106 6107 6108
    if (virDomainCreateWithFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

6109
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
6110 6111 6112
        goto cleanup;

    if (virDomainObjIsActive(vm)) {
6113 6114
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is already running"));
6115 6116 6117
        goto endjob;
    }

6118
    if (qemuDomainObjStart(dom->conn, driver, vm, flags) < 0)
6119 6120 6121
        goto endjob;

    ret = 0;
6122

6123
endjob:
E
Eric Blake 已提交
6124
    if (!qemuDomainObjEndJob(driver, vm))
6125
        vm = NULL;
6126

6127
cleanup:
6128
    if (vm)
6129
        virObjectUnlock(vm);
6130
    virNWFilterUnlockFilterUpdates();
6131
    return ret;
D
Daniel P. Berrange 已提交
6132 6133
}

6134
static int
6135
qemuDomainCreate(virDomainPtr dom)
6136
{
6137
    return qemuDomainCreateWithFlags(dom, 0);
6138 6139
}

6140
static virDomainPtr qemuDomainDefineXML(virConnectPtr conn, const char *xml) {
6141
    virQEMUDriverPtr driver = conn->privateData;
6142
    virDomainDefPtr def = NULL;
6143
    virDomainDefPtr oldDef = NULL;
6144
    virDomainObjPtr vm = NULL;
6145
    virDomainPtr dom = NULL;
6146
    virObjectEventPtr event = NULL;
6147
    virQEMUCapsPtr qemuCaps = NULL;
6148
    virQEMUDriverConfigPtr cfg;
6149
    virCapsPtr caps = NULL;
6150

6151
    cfg = virQEMUDriverGetConfig(driver);
6152 6153 6154 6155

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

6156
    if (!(def = virDomainDefParseString(xml, caps, driver->xmlopt,
M
Matthias Bolte 已提交
6157
                                        QEMU_EXPECTED_VIRT_TYPES,
6158
                                        VIR_DOMAIN_XML_INACTIVE)))
6159
        goto cleanup;
6160

6161 6162 6163
    if (virDomainDefineXMLEnsureACL(conn, def) < 0)
        goto cleanup;

6164
    if (virSecurityManagerVerify(driver->securityManager, def) < 0)
6165 6166
        goto cleanup;

6167
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
6168 6169
        goto cleanup;

6170
    if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
6171 6172
        goto cleanup;

6173
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
6174 6175
        goto cleanup;

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

6181
    def = NULL;
E
Eric Blake 已提交
6182 6183 6184
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
6185
        virDomainObjAssignDef(vm, NULL, false, NULL);
E
Eric Blake 已提交
6186 6187
        goto cleanup;
    }
6188
    vm->persistent = 1;
6189

6190
    if (virDomainSaveConfig(cfg->configDir,
6191
                            vm->newDef ? vm->newDef : vm->def) < 0) {
6192
        if (oldDef) {
M
Michal Privoznik 已提交
6193 6194 6195 6196
            /* 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))
6197
                vm->newDef = oldDef;
M
Michal Privoznik 已提交
6198
            else
6199 6200
                vm->def = oldDef;
            oldDef = NULL;
M
Michal Privoznik 已提交
6201 6202 6203 6204 6205 6206
        } else {
            /* Brand new domain. Remove it */
            VIR_INFO("Deleting domain '%s'", vm->def->name);
            qemuDomainRemoveInactive(driver, vm);
            vm = NULL;
        }
6207
        goto cleanup;
6208 6209
    }

6210
    event = virDomainEventLifecycleNewFromObj(vm,
6211
                                     VIR_DOMAIN_EVENT_DEFINED,
6212
                                     !oldDef ?
6213 6214
                                     VIR_DOMAIN_EVENT_DEFINED_ADDED :
                                     VIR_DOMAIN_EVENT_DEFINED_UPDATED);
6215

6216
    VIR_INFO("Creating domain '%s'", vm->def->name);
6217
    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
6218
    if (dom) dom->id = vm->def->id;
6219 6220

cleanup:
6221
    virDomainDefFree(oldDef);
6222
    virDomainDefFree(def);
6223
    if (vm)
6224
        virObjectUnlock(vm);
6225 6226
    if (event)
        qemuDomainEventQueue(driver, event);
6227
    virObjectUnref(qemuCaps);
6228
    virObjectUnref(caps);
6229
    virObjectUnref(cfg);
6230
    return dom;
D
Daniel P. Berrange 已提交
6231 6232
}

6233 6234
static int
qemuDomainUndefineFlags(virDomainPtr dom,
6235
                        unsigned int flags)
6236
{
6237
    virQEMUDriverPtr driver = dom->conn->privateData;
6238
    virDomainObjPtr vm;
6239
    virObjectEventPtr event = NULL;
6240
    char *name = NULL;
6241
    int ret = -1;
6242
    int nsnapshots;
6243
    virQEMUDriverConfigPtr cfg = NULL;
D
Daniel P. Berrange 已提交
6244

6245 6246
    virCheckFlags(VIR_DOMAIN_UNDEFINE_MANAGED_SAVE |
                  VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA, -1);
6247

6248 6249
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
6250

6251
    cfg = virQEMUDriverGetConfig(driver);
D
Daniel P. Berrange 已提交
6252

6253 6254 6255
    if (virDomainUndefineFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

6256
    if (!vm->persistent) {
6257 6258
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot undefine transient domain"));
6259 6260 6261
        goto cleanup;
    }

6262
    if (!virDomainObjIsActive(vm) &&
6263
        (nsnapshots = virDomainSnapshotObjListNum(vm->snapshots, NULL, 0))) {
6264
        if (!(flags & VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA)) {
6265 6266 6267 6268
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("cannot delete inactive domain with %d "
                             "snapshots"),
                           nsnapshots);
6269 6270
            goto cleanup;
        }
6271
        if (qemuDomainSnapshotDiscardAllMetadata(driver, vm) < 0)
6272
            goto cleanup;
6273 6274
    }

6275 6276 6277 6278 6279 6280 6281
    name = qemuDomainManagedSavePath(driver, vm);
    if (name == NULL)
        goto cleanup;

    if (virFileExists(name)) {
        if (flags & VIR_DOMAIN_UNDEFINE_MANAGED_SAVE) {
            if (unlink(name) < 0) {
6282 6283 6284
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Failed to remove domain managed "
                                 "save image"));
6285 6286 6287
                goto cleanup;
            }
        } else {
6288 6289 6290
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("Refusing to undefine while domain managed "
                             "save image exists"));
6291 6292 6293 6294
            goto cleanup;
        }
    }

6295
    if (virDomainDeleteConfig(cfg->configDir, cfg->autostartDir, vm) < 0)
6296
        goto cleanup;
D
Daniel P. Berrange 已提交
6297

6298
    event = virDomainEventLifecycleNewFromObj(vm,
6299 6300
                                     VIR_DOMAIN_EVENT_UNDEFINED,
                                     VIR_DOMAIN_EVENT_UNDEFINED_REMOVED);
6301

6302
    VIR_INFO("Undefining domain '%s'", vm->def->name);
6303 6304 6305 6306 6307 6308 6309 6310

    /* 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 {
6311
        qemuDomainRemoveInactive(driver, vm);
6312 6313 6314
        vm = NULL;
    }

6315
    ret = 0;
D
Daniel P. Berrange 已提交
6316

6317
cleanup:
6318
    VIR_FREE(name);
6319
    if (vm)
6320
        virObjectUnlock(vm);
6321 6322
    if (event)
        qemuDomainEventQueue(driver, event);
6323
    virObjectUnref(cfg);
6324
    return ret;
D
Daniel P. Berrange 已提交
6325 6326
}

6327
static int
6328
qemuDomainUndefine(virDomainPtr dom)
6329 6330 6331 6332
{
    return qemuDomainUndefineFlags(dom, 0);
}

6333
static int
6334
qemuDomainAttachDeviceControllerLive(virQEMUDriverPtr driver,
6335
                                     virDomainObjPtr vm,
6336
                                     virDomainDeviceDefPtr dev)
6337 6338 6339 6340 6341 6342
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
6343
        ret = qemuDomainAttachControllerDevice(driver, vm, cont);
6344 6345
        break;
    default:
6346 6347
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot plugged."),
6348
                       virDomainControllerTypeToString(cont->type));
6349 6350 6351 6352 6353 6354 6355 6356
        break;
    }
    return ret;
}

static int
qemuDomainAttachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
6357
                           virDomainPtr dom)
6358
{
6359
    virQEMUDriverPtr driver = dom->conn->privateData;
6360 6361 6362 6363
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
6364
        qemuDomainObjCheckDiskTaint(driver, vm, dev->data.disk, -1);
6365
        ret = qemuDomainAttachDeviceDiskLive(dom->conn, driver, vm, dev);
6366 6367 6368 6369 6370
        if (!ret)
            dev->data.disk = NULL;
        break;

    case VIR_DOMAIN_DEVICE_CONTROLLER:
6371
        ret = qemuDomainAttachDeviceControllerLive(driver, vm, dev);
6372 6373 6374 6375
        if (!ret)
            dev->data.controller = NULL;
        break;

6376 6377 6378 6379 6380 6381 6382
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainAttachLease(driver, vm,
                                    dev->data.lease);
        if (ret == 0)
            dev->data.lease = NULL;
        break;

6383
    case VIR_DOMAIN_DEVICE_NET:
6384
        qemuDomainObjCheckNetTaint(driver, vm, dev->data.net, -1);
6385
        ret = qemuDomainAttachNetDevice(dom->conn, driver, vm,
6386
                                        dev->data.net);
6387 6388 6389 6390 6391 6392
        if (!ret)
            dev->data.net = NULL;
        break;

    case VIR_DOMAIN_DEVICE_HOSTDEV:
        ret = qemuDomainAttachHostDevice(driver, vm,
6393
                                         dev->data.hostdev);
6394 6395 6396 6397
        if (!ret)
            dev->data.hostdev = NULL;
        break;

6398 6399 6400 6401 6402 6403 6404
    case VIR_DOMAIN_DEVICE_REDIRDEV:
        ret = qemuDomainAttachRedirdevDevice(driver, vm,
                                             dev->data.redirdev);
        if (!ret)
            dev->data.redirdev = NULL;
        break;

6405 6406 6407 6408 6409 6410 6411
    case VIR_DOMAIN_DEVICE_CHR:
        ret = qemuDomainAttachChrDevice(driver, vm,
                                        dev->data.chr);
        if (!ret)
            dev->data.chr = NULL;
        break;

6412
    default:
6413 6414
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("live attach of device '%s' is not supported"),
6415
                       virDomainDeviceTypeToString(dev->type));
6416 6417 6418
        break;
    }

6419 6420 6421
    if (ret == 0)
        qemuDomainUpdateDeviceList(driver, vm);

6422 6423 6424 6425
    return ret;
}

static int
6426
qemuDomainDetachDeviceControllerLive(virQEMUDriverPtr driver,
6427
                                     virDomainObjPtr vm,
6428
                                     virDomainDeviceDefPtr dev)
6429 6430 6431 6432 6433 6434
{
    virDomainControllerDefPtr cont = dev->data.controller;
    int ret = -1;

    switch (cont->type) {
    case VIR_DOMAIN_CONTROLLER_TYPE_SCSI:
6435
        ret = qemuDomainDetachControllerDevice(driver, vm, dev);
6436 6437
        break;
    default :
6438 6439
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("'%s' controller cannot be hot unplugged."),
6440
                       virDomainControllerTypeToString(cont->type));
6441 6442 6443 6444 6445 6446 6447
    }
    return ret;
}

static int
qemuDomainDetachDeviceLive(virDomainObjPtr vm,
                           virDomainDeviceDefPtr dev,
6448
                           virDomainPtr dom)
6449
{
6450
    virQEMUDriverPtr driver = dom->conn->privateData;
6451 6452 6453 6454
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
6455
        ret = qemuDomainDetachDeviceDiskLive(driver, vm, dev);
6456 6457
        break;
    case VIR_DOMAIN_DEVICE_CONTROLLER:
6458
        ret = qemuDomainDetachDeviceControllerLive(driver, vm, dev);
6459
        break;
6460 6461 6462
    case VIR_DOMAIN_DEVICE_LEASE:
        ret = qemuDomainDetachLease(driver, vm, dev->data.lease);
        break;
6463
    case VIR_DOMAIN_DEVICE_NET:
6464
        ret = qemuDomainDetachNetDevice(driver, vm, dev);
6465 6466
        break;
    case VIR_DOMAIN_DEVICE_HOSTDEV:
6467
        ret = qemuDomainDetachHostDevice(driver, vm, dev);
6468
        break;
6469 6470 6471
    case VIR_DOMAIN_DEVICE_CHR:
        ret = qemuDomainDetachChrDevice(driver, vm, dev->data.chr);
        break;
6472
    default:
6473 6474 6475
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("live detach of device '%s' is not supported"),
                       virDomainDeviceTypeToString(dev->type));
6476 6477 6478
        break;
    }

6479 6480 6481
    if (ret == 0)
        qemuDomainUpdateDeviceList(driver, vm);

6482 6483 6484
    return ret;
}

6485
static int
6486 6487
qemuDomainChangeDiskMediaLive(virConnectPtr conn,
                              virDomainObjPtr vm,
6488
                              virDomainDeviceDefPtr dev,
6489
                              virQEMUDriverPtr driver,
6490 6491 6492
                              bool force)
{
    virDomainDiskDefPtr disk = dev->data.disk;
6493 6494 6495 6496
    virDomainDiskDefPtr orig_disk = NULL;
    virDomainDiskDefPtr tmp = NULL;
    virDomainDeviceDefPtr dev_copy = NULL;
    virCapsPtr caps = NULL;
6497
    int ret = -1;
6498

6499 6500 6501
    if (qemuTranslateDiskSourcePool(conn, disk) < 0)
        goto end;

6502 6503 6504
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
        goto end;

6505 6506
    if (qemuSetupDiskCgroup(vm, disk) < 0)
        goto end;
6507 6508 6509 6510

    switch (disk->device) {
    case VIR_DOMAIN_DISK_DEVICE_CDROM:
    case VIR_DOMAIN_DISK_DEVICE_FLOPPY:
6511 6512 6513 6514 6515 6516 6517 6518 6519 6520 6521 6522 6523 6524 6525
        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;

6526 6527
        if (!(dev_copy = virDomainDeviceDefCopy(dev, vm->def,
                                                caps, driver->xmlopt))) {
6528 6529 6530 6531 6532
            dev->data.disk = tmp;
            goto end;
        }
        dev->data.disk = tmp;

6533
        /* Add the new disk src into shared disk hash table */
6534
        if (qemuAddSharedDevice(driver, dev, vm->def->name) < 0)
6535 6536
            goto end;

6537
        ret = qemuDomainChangeEjectableMedia(driver, vm, disk, orig_disk, force);
6538 6539 6540 6541 6542 6543 6544
        /* '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.
         */
6545
        if (ret == 0) {
6546
            dev->data.disk = NULL;
6547 6548
            ignore_value(qemuRemoveSharedDevice(driver, dev_copy,
                                                vm->def->name));
6549
        }
6550 6551
        break;
    default:
6552 6553 6554
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk bus '%s' cannot be updated."),
                       virDomainDiskBusTypeToString(disk->bus));
6555 6556 6557
        break;
    }

6558 6559 6560 6561 6562
    if (ret != 0 &&
        qemuTeardownDiskCgroup(vm, disk) < 0)
        VIR_WARN("Failed to teardown cgroup for disk path %s",
                 NULLSTR(disk->src));

6563
end:
6564 6565
    virObjectUnref(caps);
    virDomainDeviceDefFree(dev_copy);
6566 6567 6568 6569
    return ret;
}

static int
6570 6571
qemuDomainUpdateDeviceLive(virConnectPtr conn,
                           virDomainObjPtr vm,
6572 6573 6574 6575
                           virDomainDeviceDefPtr dev,
                           virDomainPtr dom,
                           bool force)
{
6576
    virQEMUDriverPtr driver = dom->conn->privateData;
6577 6578 6579 6580
    int ret = -1;

    switch (dev->type) {
    case VIR_DOMAIN_DEVICE_DISK:
6581
        ret = qemuDomainChangeDiskMediaLive(conn, vm, dev, driver, force);
6582 6583 6584 6585
        break;
    case VIR_DOMAIN_DEVICE_GRAPHICS:
        ret = qemuDomainChangeGraphics(driver, vm, dev->data.graphics);
        break;
6586
    case VIR_DOMAIN_DEVICE_NET:
6587
        ret = qemuDomainChangeNet(driver, vm, dom, dev);
6588
        break;
6589
    default:
6590
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
6591
                       _("live update of device '%s' is not supported"),
6592
                       virDomainDeviceTypeToString(dev->type));
6593 6594 6595 6596 6597 6598
        break;
    }

    return ret;
}

6599
static int
6600
qemuDomainAttachDeviceConfig(virQEMUCapsPtr qemuCaps,
6601
                             virDomainDefPtr vmdef,
6602 6603
                             virDomainDeviceDefPtr dev)
{
6604
    virDomainDiskDefPtr disk;
6605
    virDomainNetDefPtr net;
6606
    virDomainHostdevDefPtr hostdev;
6607
    virDomainLeaseDefPtr lease;
6608
    virDomainControllerDefPtr controller;
6609

6610
    switch (dev->type) {
6611 6612
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6613
        if (virDomainDiskIndexByName(vmdef, disk->dst, true) >= 0) {
6614 6615
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("target %s already exists"), disk->dst);
6616 6617
            return -1;
        }
6618
        if (virDomainDiskInsert(vmdef, disk))
6619 6620 6621 6622 6623 6624
            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;
6625
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6626 6627 6628
            return -1;
        break;

6629 6630
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
6631
        if (virDomainNetInsert(vmdef, net))
6632 6633
            return -1;
        dev->data.net = NULL;
6634
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6635 6636
            return -1;
        break;
6637

6638 6639 6640
    case VIR_DOMAIN_DEVICE_HOSTDEV:
        hostdev = dev->data.hostdev;
        if (virDomainHostdevFind(vmdef, hostdev, NULL) >= 0) {
6641
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6642
                           _("device is already in the domain configuration"));
6643 6644
            return -1;
        }
6645
        if (virDomainHostdevInsert(vmdef, hostdev))
6646 6647
            return -1;
        dev->data.hostdev = NULL;
6648
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6649 6650 6651
            return -1;
        break;

6652 6653 6654
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
        if (virDomainLeaseIndex(vmdef, lease) >= 0) {
6655
            virReportError(VIR_ERR_OPERATION_INVALID,
6656 6657
                           _("Lease %s in lockspace %s already exists"),
                           lease->key, NULLSTR(lease->lockspace));
6658 6659 6660 6661 6662 6663 6664 6665 6666
            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;

6667 6668 6669
    case VIR_DOMAIN_DEVICE_CONTROLLER:
        controller = dev->data.controller;
        if (virDomainControllerFind(vmdef, controller->type,
6670
                                    controller->idx) >= 0) {
6671
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6672 6673 6674 6675 6676 6677 6678 6679
                           _("Target already exists"));
            return -1;
        }

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

6680
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6681 6682 6683
            return -1;
        break;

6684 6685 6686 6687 6688 6689
    case VIR_DOMAIN_DEVICE_CHR:
        if (qemuDomainChrInsert(vmdef, dev->data.chr) < 0)
            return -1;
        dev->data.chr = NULL;
        break;

6690
    default:
6691 6692 6693
         virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                        _("persistent attach of device '%s' is not supported"),
                        virDomainDeviceTypeToString(dev->type));
6694 6695 6696 6697 6698 6699 6700
         return -1;
    }
    return 0;
}


static int
6701
qemuDomainDetachDeviceConfig(virDomainDefPtr vmdef,
6702 6703
                             virDomainDeviceDefPtr dev)
{
6704
    virDomainDiskDefPtr disk, det_disk;
6705
    virDomainNetDefPtr net;
6706
    virDomainHostdevDefPtr hostdev, det_hostdev;
6707
    virDomainLeaseDefPtr lease, det_lease;
6708
    virDomainControllerDefPtr cont, det_cont;
6709
    virDomainChrDefPtr chr;
6710
    int idx;
6711
    char mac[VIR_MAC_STRING_BUFLEN];
6712

6713
    switch (dev->type) {
6714 6715
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6716
        if (!(det_disk = virDomainDiskRemoveByName(vmdef, disk->dst))) {
6717 6718
            virReportError(VIR_ERR_INVALID_ARG,
                           _("no target device %s"), disk->dst);
6719 6720
            return -1;
        }
6721
        virDomainDiskDefFree(det_disk);
6722
        break;
6723

6724 6725
    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
6726 6727 6728 6729 6730 6731 6732 6733 6734
        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"));
6735 6736
            return -1;
        }
6737 6738
        /* this is guaranteed to succeed */
        virDomainNetDefFree(virDomainNetRemove(vmdef, idx));
6739
        break;
6740

6741 6742 6743
    case VIR_DOMAIN_DEVICE_HOSTDEV: {
        hostdev = dev->data.hostdev;
        if ((idx = virDomainHostdevFind(vmdef, hostdev, &det_hostdev)) < 0) {
6744 6745
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("device not present in domain configuration"));
6746 6747 6748 6749 6750 6751 6752
            return -1;
        }
        virDomainHostdevRemove(vmdef, idx);
        virDomainHostdevDefFree(det_hostdev);
        break;
    }

6753 6754
    case VIR_DOMAIN_DEVICE_LEASE:
        lease = dev->data.lease;
6755
        if (!(det_lease = virDomainLeaseRemove(vmdef, lease))) {
6756 6757 6758
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Lease %s in lockspace %s does not exist"),
                           lease->key, NULLSTR(lease->lockspace));
6759 6760
            return -1;
        }
6761
        virDomainLeaseDefFree(det_lease);
6762 6763
        break;

6764 6765 6766 6767 6768 6769 6770 6771 6772 6773 6774 6775 6776
    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;

6777 6778 6779 6780 6781 6782 6783 6784 6785
    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;

6786
    default:
6787 6788 6789
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("persistent detach of device '%s' is not supported"),
                       virDomainDeviceTypeToString(dev->type));
6790 6791 6792 6793 6794 6795
        return -1;
    }
    return 0;
}

static int
6796
qemuDomainUpdateDeviceConfig(virQEMUCapsPtr qemuCaps,
6797
                             virDomainDefPtr vmdef,
6798 6799
                             virDomainDeviceDefPtr dev)
{
6800
    virDomainDiskDefPtr orig, disk;
6801
    virDomainNetDefPtr net;
6802
    int pos;
6803 6804
    char mac[VIR_MAC_STRING_BUFLEN];

6805

6806
    switch (dev->type) {
6807 6808
    case VIR_DOMAIN_DEVICE_DISK:
        disk = dev->data.disk;
6809
        pos = virDomainDiskIndexByName(vmdef, disk->dst, false);
6810
        if (pos < 0) {
6811 6812
            virReportError(VIR_ERR_INVALID_ARG,
                           _("target %s doesn't exist."), disk->dst);
6813 6814 6815 6816 6817
            return -1;
        }
        orig = vmdef->disks[pos];
        if (!(orig->device == VIR_DOMAIN_DISK_DEVICE_CDROM) &&
            !(orig->device == VIR_DOMAIN_DISK_DEVICE_FLOPPY)) {
6818 6819
            virReportError(VIR_ERR_INVALID_ARG, "%s",
                           _("this disk doesn't support update"));
6820 6821 6822 6823 6824 6825 6826 6827 6828 6829 6830 6831 6832 6833 6834
            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;
        }
6835 6836
        if (disk->format)
            orig->format = disk->format;
6837 6838
        disk->src = NULL;
        break;
6839 6840 6841

    case VIR_DOMAIN_DEVICE_NET:
        net = dev->data.net;
6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853
        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);
6854 6855 6856
            return -1;
        }

6857
        virDomainNetDefFree(vmdef->nets[pos]);
6858 6859 6860 6861

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

6862
        if (qemuDomainAssignAddresses(vmdef, qemuCaps, NULL) < 0)
6863 6864 6865
            return -1;
        break;

6866
    default:
6867 6868 6869
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("persistent update of device '%s' is not supported"),
                       virDomainDeviceTypeToString(dev->type));
6870 6871 6872 6873 6874
        return -1;
    }
    return 0;
}

6875

6876 6877
static int qemuDomainAttachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
6878
{
6879
    virQEMUDriverPtr driver = dom->conn->privateData;
6880
    virDomainObjPtr vm = NULL;
6881
    virDomainDefPtr vmdef = NULL;
6882
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
6883
    int ret = -1;
6884
    unsigned int affect, parse_flags = 0;
6885
    virQEMUCapsPtr qemuCaps = NULL;
6886
    qemuDomainObjPrivatePtr priv;
6887
    virQEMUDriverConfigPtr cfg = NULL;
6888
    virCapsPtr caps = NULL;
6889

6890
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
6891
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
6892

6893 6894
    cfg = virQEMUDriverGetConfig(driver);

6895 6896
    affect = flags & (VIR_DOMAIN_AFFECT_LIVE | VIR_DOMAIN_AFFECT_CONFIG);

6897 6898 6899
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

6900
    if (!(vm = qemuDomObjFromDomain(dom)))
6901
        goto cleanup;
6902

6903
    priv = vm->privateData;
6904

6905 6906 6907
    if (virDomainAttachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

6911
    if (virDomainObjIsActive(vm)) {
6912
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
6913
            flags |= VIR_DOMAIN_AFFECT_LIVE;
6914
    } else {
6915
        if (affect == VIR_DOMAIN_AFFECT_CURRENT)
6916
            flags |= VIR_DOMAIN_AFFECT_CONFIG;
6917
        /* check consistency between flags and the vm state */
6918
        if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6919
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
6920 6921
                           _("cannot do live update a device on "
                             "inactive domain"));
6922 6923
            goto endjob;
        }
6924
    }
6925

6926
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) && !vm->persistent) {
6927 6928
         virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                        _("cannot modify device on transient domain"));
6929 6930
         goto endjob;
    }
6931

6932 6933 6934 6935
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) &&
        !(flags & VIR_DOMAIN_AFFECT_LIVE))
        parse_flags |= VIR_DOMAIN_XML_INACTIVE;

6936 6937
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
                                             caps, driver->xmlopt,
6938
                                             parse_flags);
6939 6940 6941 6942 6943 6944 6945 6946 6947
    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.
         */
6948
        dev_copy = virDomainDeviceDefCopy(dev, vm->def, caps, driver->xmlopt);
6949
        if (!dev_copy)
6950
            goto endjob;
6951
    }
6952

6953 6954 6955
    if (priv->qemuCaps)
        qemuCaps = virObjectRef(priv->qemuCaps);
    else if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, vm->def->emulator)))
6956 6957
        goto cleanup;

6958
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6959
        if (virDomainDefCompatibleDevice(vm->def, dev) < 0)
6960 6961
            goto endjob;

6962
        /* Make a copy for updated domain. */
6963
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
6964 6965
        if (!vmdef)
            goto endjob;
6966
        if ((ret = qemuDomainAttachDeviceConfig(qemuCaps, vmdef, dev)) < 0)
6967 6968 6969 6970
            goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
6971 6972 6973
        if (virDomainDefCompatibleDevice(vm->def, dev_copy) < 0)
            goto endjob;

6974
        if ((ret = qemuDomainAttachDeviceLive(vm, dev_copy, dom)) < 0)
6975
            goto endjob;
6976 6977
        /*
         * update domain status forcibly because the domain status may be
6978 6979
         * changed even if we failed to attach the device. For example,
         * a new controller may be created.
6980
         */
6981
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0) {
6982
            ret = -1;
6983 6984
            goto endjob;
        }
6985
    }
6986

6987
    /* Finally, if no error until here, we can save config. */
6988
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
6989
        ret = virDomainSaveConfig(cfg->configDir, vmdef);
6990
        if (!ret) {
6991
            virDomainObjAssignDef(vm, vmdef, false, NULL);
6992 6993 6994
            vmdef = NULL;
        }
    }
6995 6996

endjob:
E
Eric Blake 已提交
6997
    if (!qemuDomainObjEndJob(driver, vm))
6998 6999 7000
        vm = NULL;

cleanup:
7001
    virObjectUnref(qemuCaps);
7002
    virDomainDefFree(vmdef);
7003 7004
    if (dev != dev_copy)
        virDomainDeviceDefFree(dev_copy);
7005 7006
    virDomainDeviceDefFree(dev);
    if (vm)
7007
        virObjectUnlock(vm);
7008
    virObjectUnref(caps);
7009
    virObjectUnref(cfg);
7010 7011 7012
    return ret;
}

7013 7014 7015
static int qemuDomainAttachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainAttachDeviceFlags(dom, xml,
7016
                                       VIR_DOMAIN_AFFECT_LIVE);
7017
}
7018

7019

7020 7021 7022 7023
static int qemuDomainUpdateDeviceFlags(virDomainPtr dom,
                                       const char *xml,
                                       unsigned int flags)
{
7024 7025 7026 7027 7028 7029 7030 7031 7032 7033 7034 7035 7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 7046 7047 7048 7049 7050 7051
    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;

7052 7053 7054
    if (virDomainUpdateDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

7055 7056 7057 7058 7059 7060 7061 7062 7063 7064 7065 7066 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 7095 7096 7097 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
    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 已提交
7141
    if (!qemuDomainObjEndJob(driver, vm))
7142 7143 7144 7145 7146 7147 7148 7149 7150 7151 7152 7153 7154
        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;
7155 7156
}

7157

7158 7159 7160
static int qemuDomainDetachDeviceFlags(virDomainPtr dom, const char *xml,
                                       unsigned int flags)
{
7161 7162 7163 7164 7165
    virQEMUDriverPtr driver = dom->conn->privateData;
    virDomainObjPtr vm = NULL;
    virDomainDefPtr vmdef = NULL;
    virDomainDeviceDefPtr dev = NULL, dev_copy = NULL;
    int ret = -1;
7166
    unsigned int affect, parse_flags = 0;
7167 7168 7169 7170 7171 7172 7173 7174 7175 7176 7177 7178 7179 7180 7181 7182 7183 7184 7185 7186
    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;

7187 7188 7189
    if (virDomainDetachDeviceFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

7190 7191 7192 7193 7194 7195 7196 7197 7198 7199 7200 7201 7202 7203 7204 7205 7206 7207 7208 7209 7210 7211 7212 7213
    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;
    }

7214 7215 7216 7217
    if ((flags & VIR_DOMAIN_AFFECT_CONFIG) &&
        !(flags & VIR_DOMAIN_AFFECT_LIVE))
        parse_flags |= VIR_DOMAIN_XML_INACTIVE;

7218 7219
    dev = dev_copy = virDomainDeviceDefParse(xml, vm->def,
                                             caps, driver->xmlopt,
7220
                                             parse_flags);
7221 7222 7223 7224 7225 7226 7227 7228 7229 7230 7231 7232 7233 7234 7235 7236 7237 7238 7239 7240 7241 7242 7243 7244 7245 7246 7247 7248 7249 7250 7251 7252 7253 7254 7255 7256 7257 7258 7259 7260 7261 7262 7263 7264 7265 7266 7267 7268 7269 7270 7271 7272 7273 7274 7275 7276 7277 7278
    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 已提交
7279
    if (!qemuDomainObjEndJob(driver, vm))
7280 7281 7282 7283 7284 7285 7286 7287 7288 7289 7290 7291 7292
        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;
7293 7294
}

7295 7296 7297
static int qemuDomainDetachDevice(virDomainPtr dom, const char *xml)
{
    return qemuDomainDetachDeviceFlags(dom, xml,
7298
                                       VIR_DOMAIN_AFFECT_LIVE);
7299 7300
}

7301 7302
static int qemuDomainGetAutostart(virDomainPtr dom,
                                  int *autostart) {
7303 7304
    virDomainObjPtr vm;
    int ret = -1;
7305

7306
    if (!(vm = qemuDomObjFromDomain(dom)))
7307
        goto cleanup;
7308

7309 7310 7311
    if (virDomainGetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

7312
    *autostart = vm->autostart;
7313
    ret = 0;
7314

7315
cleanup:
7316
    if (vm)
7317
        virObjectUnlock(vm);
7318
    return ret;
7319 7320
}

7321 7322
static int qemuDomainSetAutostart(virDomainPtr dom,
                                  int autostart) {
7323
    virQEMUDriverPtr driver = dom->conn->privateData;
7324
    virDomainObjPtr vm;
7325 7326
    char *configFile = NULL, *autostartLink = NULL;
    int ret = -1;
7327
    virQEMUDriverConfigPtr cfg = NULL;
7328

7329 7330 7331
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;

7332
    cfg = virQEMUDriverGetConfig(driver);
7333

7334 7335 7336
    if (virDomainSetAutostartEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

7337
    if (!vm->persistent) {
7338 7339
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cannot set autostart for transient domain"));
7340
        goto cleanup;
7341 7342
    }

7343 7344
    autostart = (autostart != 0);

7345
    if (vm->autostart != autostart) {
7346
        if ((configFile = virDomainConfigFile(cfg->configDir, vm->def->name)) == NULL)
7347
            goto cleanup;
7348
        if ((autostartLink = virDomainConfigFile(cfg->autostartDir, vm->def->name)) == NULL)
7349
            goto cleanup;
7350

7351
        if (autostart) {
7352
            if (virFileMakePath(cfg->autostartDir) < 0) {
7353
                virReportSystemError(errno,
7354
                                     _("cannot create autostart directory %s"),
7355
                                     cfg->autostartDir);
7356 7357
                goto cleanup;
            }
7358

7359
            if (symlink(configFile, autostartLink) < 0) {
7360
                virReportSystemError(errno,
7361 7362
                                     _("Failed to create symlink '%s to '%s'"),
                                     autostartLink, configFile);
7363 7364 7365 7366
                goto cleanup;
            }
        } else {
            if (unlink(autostartLink) < 0 && errno != ENOENT && errno != ENOTDIR) {
7367
                virReportSystemError(errno,
7368 7369
                                     _("Failed to delete symlink '%s'"),
                                     autostartLink);
7370 7371
                goto cleanup;
            }
7372 7373
        }

7374
        vm->autostart = autostart;
7375
    }
7376
    ret = 0;
7377

7378 7379 7380
cleanup:
    VIR_FREE(configFile);
    VIR_FREE(autostartLink);
7381
    if (vm)
7382
        virObjectUnlock(vm);
7383
    virObjectUnref(cfg);
7384
    return ret;
7385 7386
}

7387

7388 7389
static char *qemuDomainGetSchedulerType(virDomainPtr dom,
                                        int *nparams)
7390
{
7391
    char *ret = NULL;
7392 7393 7394
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;

7395
    if (!(vm = qemuDomObjFromDomain(dom)))
7396
        goto cleanup;
7397

7398
    priv = vm->privateData;
7399

7400 7401 7402
    if (virDomainGetSchedulerTypeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

7403 7404 7405 7406 7407 7408 7409 7410
    /* Domain not running, thus no cgroups - return defaults */
    if (!virDomainObjIsActive(vm)) {
        if (nparams)
            *nparams = 5;
        ignore_value(VIR_STRDUP(ret, "posix"));
        goto cleanup;
    }

7411
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
7412 7413
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
7414
        goto cleanup;
7415 7416
    }

7417
    if (nparams) {
7418
        if (virCgroupSupportsCpuBW(priv->cgroup))
7419
            *nparams = 5;
7420 7421
        else
            *nparams = 1;
7422
    }
7423

7424
    ignore_value(VIR_STRDUP(ret, "posix"));
7425 7426

cleanup:
7427 7428
    if (vm)
        virObjectUnlock(vm);
7429 7430 7431
    return ret;
}

7432
/* blkioDeviceStr in the form of /device/path,weight,/device/path,weight
7433 7434 7435
 * for example, /dev/disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0,800
 */
static int
7436 7437
qemuDomainParseBlkioDeviceStr(char *blkioDeviceStr, const char *type,
                              virBlkioDevicePtr *dev, size_t *size)
7438 7439 7440 7441
{
    char *temp;
    int ndevices = 0;
    int nsep = 0;
7442
    size_t i;
7443
    virBlkioDevicePtr result = NULL;
7444

7445
    *dev = NULL;
7446 7447
    *size = 0;

7448
    if (STREQ(blkioDeviceStr, ""))
7449 7450
        return 0;

7451
    temp = blkioDeviceStr;
7452 7453 7454 7455 7456 7457 7458 7459 7460 7461 7462 7463 7464 7465 7466
    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;

7467
    if (VIR_ALLOC_N(result, ndevices) < 0)
7468 7469 7470
        return -1;

    i = 0;
7471
    temp = blkioDeviceStr;
7472 7473 7474 7475 7476 7477 7478 7479
    while (temp) {
        char *p = temp;

        /* device path */
        p = strchr(p, ',');
        if (!p)
            goto error;

7480
        if (VIR_STRNDUP(result[i].path, temp, p - temp) < 0)
7481 7482
            goto cleanup;

7483
        /* value */
7484 7485
        temp = p + 1;

7486 7487 7488 7489 7490 7491 7492 7493 7494 7495 7496 7497 7498 7499 7500 7501
        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 {
7502
            goto error;
7503
        }
7504 7505 7506 7507 7508 7509 7510 7511 7512 7513 7514 7515 7516

        i++;

        if (*p == '\0')
            break;
        else if (*p != ',')
            goto error;
        temp = p + 1;
    }

    if (!i)
        VIR_FREE(result);

7517
    *dev = result;
7518 7519 7520 7521 7522
    *size = i;

    return 0;

error:
7523
    virReportError(VIR_ERR_INVALID_ARG,
7524 7525
                   _("unable to parse blkio device '%s' '%s'"),
                   type, blkioDeviceStr);
7526
cleanup:
7527
    virBlkioDeviceArrayClear(result, ndevices);
7528 7529 7530 7531
    VIR_FREE(result);
    return -1;
}

7532
/* Modify dest_array to reflect all blkio device changes described in
7533
 * src_array.  */
7534
static int
7535 7536 7537 7538 7539
qemuDomainMergeBlkioDevice(virBlkioDevicePtr *dest_array,
                           size_t *dest_size,
                           virBlkioDevicePtr src_array,
                           size_t src_size,
                           const char *type)
7540
{
7541
    size_t i, j;
7542
    virBlkioDevicePtr dest, src;
7543

7544
    for (i = 0; i < src_size; i++) {
7545 7546
        bool found = false;

7547 7548 7549 7550
        src = &src_array[i];
        for (j = 0; j < *dest_size; j++) {
            dest = &(*dest_array)[j];
            if (STREQ(src->path, dest->path)) {
7551
                found = true;
7552 7553 7554 7555 7556 7557 7558 7559 7560 7561 7562 7563 7564 7565 7566 7567

                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;
                }
7568 7569 7570 7571
                break;
            }
        }
        if (!found) {
7572
            if (!src->weight && !src->riops && !src->wiops && !src->rbps && !src->wbps)
7573
                continue;
7574
            if (VIR_EXPAND_N(*dest_array, *dest_size, 1) < 0)
7575
                return -1;
7576
            dest = &(*dest_array)[*dest_size - 1];
7577 7578 7579 7580 7581 7582 7583 7584 7585 7586 7587 7588 7589 7590 7591 7592

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

7593 7594
            dest->path = src->path;
            src->path = NULL;
7595 7596 7597 7598 7599 7600
        }
    }

    return 0;
}

7601 7602 7603 7604 7605
static int
qemuDomainSetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int nparams,
                             unsigned int flags)
7606
{
7607
    virQEMUDriverPtr driver = dom->conn->privateData;
7608
    size_t i;
7609
    virDomainObjPtr vm = NULL;
7610
    virDomainDefPtr persistentDef = NULL;
7611
    int ret = -1;
7612
    virQEMUDriverConfigPtr cfg = NULL;
7613
    virCapsPtr caps = NULL;
7614
    qemuDomainObjPrivatePtr priv;
7615

7616 7617
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
7618 7619 7620 7621 7622
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_BLKIO_WEIGHT,
                               VIR_TYPED_PARAM_UINT,
                               VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                               VIR_TYPED_PARAM_STRING,
7623 7624 7625 7626 7627 7628 7629 7630
                               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,
7631
                               NULL) < 0)
7632
        return -1;
7633

7634 7635 7636
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;

7637
    priv = vm->privateData;
7638
    cfg = virQEMUDriverGetConfig(driver);
7639 7640 7641 7642

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

7643 7644
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;
7645

7646
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
7647 7648
                                        &persistentDef) < 0)
        goto cleanup;
7649

7650
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7651
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
7652 7653
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
7654 7655 7656 7657
            goto cleanup;
        }
    }

7658
    ret = 0;
7659 7660 7661 7662 7663 7664
    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) {
7665 7666
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
7667 7668 7669
                    ret = -1;
                    continue;
                }
7670

7671
                if (virCgroupSetBlkioWeight(priv->cgroup, params[i].value.ui) < 0)
7672
                    ret = -1;
7673 7674 7675 7676 7677
            } 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)) {
7678
                size_t ndevices;
7679
                virBlkioDevicePtr devices = NULL;
7680
                size_t j;
7681

7682 7683 7684 7685
                if (qemuDomainParseBlkioDeviceStr(params[i].value.s,
                                                  param->field,
                                                  &devices,
                                                  &ndevices) < 0) {
7686 7687 7688
                    ret = -1;
                    continue;
                }
7689 7690 7691 7692 7693 7694 7695 7696 7697 7698 7699 7700 7701 7702 7703 7704 7705 7706 7707 7708 7709 7710 7711 7712 7713 7714 7715 7716 7717 7718 7719 7720 7721 7722 7723 7724 7725 7726 7727 7728 7729 7730 7731 7732 7733

                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;
                        }
7734
                    }
7735 7736 7737 7738 7739 7740 7741 7742
                } else {
                    virReportError(VIR_ERR_INVALID_ARG, _("Unknown blkio parameter %s"),
                                   param->field);
                    ret = -1;
                    virBlkioDeviceArrayClear(devices, ndevices);
                    VIR_FREE(devices);

                    continue;
7743
                }
7744

7745
                if (j != ndevices ||
7746 7747 7748
                    qemuDomainMergeBlkioDevice(&vm->def->blkio.devices,
                                               &vm->def->blkio.ndevices,
                                               devices, ndevices, param->field) < 0)
7749
                    ret = -1;
7750
                virBlkioDeviceArrayClear(devices, ndevices);
7751
                VIR_FREE(devices);
7752
            }
7753
        }
E
Eric Blake 已提交
7754 7755 7756 7757
    }
    if (ret < 0)
        goto cleanup;
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
E
Eric Blake 已提交
7758 7759 7760
        /* Clang can't see that if we get here, persistentDef was set.  */
        sa_assert(persistentDef);

7761 7762 7763 7764 7765
        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) {
7766 7767
                    virReportError(VIR_ERR_INVALID_ARG, "%s",
                                   _("out of blkio weight range."));
7768 7769 7770 7771 7772
                    ret = -1;
                    continue;
                }

                persistentDef->blkio.weight = params[i].value.ui;
7773 7774 7775 7776 7777
            } 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)) {
7778
                virBlkioDevicePtr devices = NULL;
7779
                size_t ndevices;
7780

7781 7782 7783 7784
                if (qemuDomainParseBlkioDeviceStr(params[i].value.s,
                                                  params->field,
                                                  &devices,
                                                  &ndevices) < 0) {
7785 7786 7787
                    ret = -1;
                    continue;
                }
7788 7789 7790
                if (qemuDomainMergeBlkioDevice(&persistentDef->blkio.devices,
                                               &persistentDef->blkio.ndevices,
                                               devices, ndevices, param->field) < 0)
7791
                    ret = -1;
7792
                virBlkioDeviceArrayClear(devices, ndevices);
7793
                VIR_FREE(devices);
7794 7795
            }
        }
A
Alex Jia 已提交
7796

7797
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
A
Alex Jia 已提交
7798
            ret = -1;
7799 7800 7801 7802
    }

cleanup:
    if (vm)
7803
        virObjectUnlock(vm);
7804
    virObjectUnref(caps);
7805
    virObjectUnref(cfg);
7806 7807 7808
    return ret;
}

7809 7810 7811 7812 7813
static int
qemuDomainGetBlkioParameters(virDomainPtr dom,
                             virTypedParameterPtr params,
                             int *nparams,
                             unsigned int flags)
7814
{
7815
    virQEMUDriverPtr driver = dom->conn->privateData;
7816
    size_t i, j;
7817
    virDomainObjPtr vm = NULL;
7818
    virDomainDefPtr persistentDef = NULL;
7819 7820
    unsigned int val;
    int ret = -1;
7821
    virCapsPtr caps = NULL;
7822
    qemuDomainObjPrivatePtr priv;
7823

7824
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
7825 7826
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
7827

7828 7829 7830
    /* 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.  */
7831 7832
    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

7833 7834
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
7835

7836 7837
    priv = vm->privateData;

7838 7839 7840
    if (virDomainGetBlkioParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

7841 7842 7843
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

7844 7845 7846 7847 7848 7849 7850
    if ((*nparams) == 0) {
        /* Current number of blkio parameters supported by cgroups */
        *nparams = QEMU_NB_BLKIO_PARAM;
        ret = 0;
        goto cleanup;
    }

7851
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
7852 7853
                                        &persistentDef) < 0)
        goto cleanup;
7854

7855
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7856
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_BLKIO)) {
7857 7858
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("blkio cgroup isn't mounted"));
7859 7860 7861 7862 7863
            goto cleanup;
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
7864
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
7865 7866 7867 7868 7869
            virTypedParameterPtr param = &params[i];
            val = 0;

            switch (i) {
            case 0: /* fill blkio weight here */
7870
                if (virCgroupGetBlkioWeight(priv->cgroup, &val) < 0)
7871
                    goto cleanup;
7872 7873
                if (virTypedParameterAssign(param, VIR_DOMAIN_BLKIO_WEIGHT,
                                            VIR_TYPED_PARAM_UINT, val) < 0)
7874 7875
                    goto cleanup;
                break;
7876

7877 7878 7879 7880
            case 1: /* blkiotune.device_weight */
                if (vm->def->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
                    bool comma = false;
7881

7882 7883 7884 7885 7886 7887 7888 7889 7890 7891 7892 7893 7894 7895 7896 7897 7898
                    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);
                }
7899 7900 7901 7902
                if (virTypedParameterAssign(param,
                                            VIR_DOMAIN_BLKIO_DEVICE_WEIGHT,
                                            VIR_TYPED_PARAM_STRING,
                                            param->value.s) < 0)
7903 7904
                    goto cleanup;
                break;
7905

7906 7907 7908 7909 7910 7911 7912 7913 7914 7915 7916 7917 7918 7919 7920 7921 7922 7923 7924 7925 7926 7927 7928 7929 7930 7931 7932 7933 7934 7935 7936 7937 7938 7939 7940 7941 7942 7943 7944 7945 7946 7947 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
            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;

8022 8023 8024
            default:
                break;
                /* should not hit here */
8025
            }
8026 8027
        }
    } else if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8028
        for (i = 0; i < *nparams && i < QEMU_NB_BLKIO_PARAM; i++) {
8029 8030 8031 8032 8033 8034 8035 8036
            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) {
8037 8038 8039
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_WEIGHT);
8040 8041 8042 8043
                    goto cleanup;
                }
                param->value.ui = persistentDef->blkio.weight;
                break;
8044

8045 8046 8047
            case 1: /* blkiotune.device_weight */
                if (persistentDef->blkio.ndevices > 0) {
                    virBuffer buf = VIR_BUFFER_INITIALIZER;
8048 8049
                    bool comma = false;

8050
                    for (j = 0; j < persistentDef->blkio.ndevices; j++) {
8051 8052 8053
                        if (!persistentDef->blkio.devices[j].weight)
                            continue;
                        if (comma)
8054
                            virBufferAddChar(&buf, ',');
8055 8056
                        else
                            comma = true;
8057 8058 8059 8060 8061 8062 8063 8064 8065
                        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);
8066
                }
8067 8068
                if (!param->value.s && VIR_STRDUP(param->value.s, "") < 0)
                    goto cleanup;
8069 8070 8071
                param->type = VIR_TYPED_PARAM_STRING;
                if (virStrcpyStatic(param->field,
                                    VIR_DOMAIN_BLKIO_DEVICE_WEIGHT) == NULL) {
8072 8073 8074
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("Field name '%s' too long"),
                                   VIR_DOMAIN_BLKIO_DEVICE_WEIGHT);
8075 8076 8077 8078
                    goto cleanup;
                }
                break;

8079 8080 8081 8082 8083 8084 8085 8086 8087 8088 8089 8090 8091 8092 8093 8094 8095 8096 8097 8098 8099 8100 8101 8102 8103 8104 8105 8106 8107 8108 8109 8110 8111 8112 8113 8114 8115 8116 8117 8118 8119 8120 8121 8122 8123 8124 8125 8126 8127 8128 8129 8130 8131 8132 8133 8134 8135 8136 8137 8138 8139 8140 8141 8142 8143 8144 8145 8146 8147 8148 8149 8150 8151 8152 8153 8154 8155 8156 8157 8158 8159 8160 8161 8162 8163 8164 8165 8166 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
            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;


8214 8215 8216 8217
            default:
                break;
                /* should not hit here */
            }
8218 8219 8220
        }
    }

8221 8222
    if (QEMU_NB_BLKIO_PARAM < *nparams)
        *nparams = QEMU_NB_BLKIO_PARAM;
8223 8224 8225 8226
    ret = 0;

cleanup:
    if (vm)
8227
        virObjectUnlock(vm);
8228
    virObjectUnref(caps);
8229 8230
    return ret;
}
8231

8232 8233 8234 8235 8236
static int
qemuDomainSetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int nparams,
                              unsigned int flags)
8237
{
8238
    virQEMUDriverPtr driver = dom->conn->privateData;
8239
    virDomainDefPtr persistentDef = NULL;
8240
    virDomainObjPtr vm = NULL;
8241
    unsigned long long swap_hard_limit;
8242 8243
    unsigned long long hard_limit = 0;
    unsigned long long soft_limit = 0;
8244
    bool set_swap_hard_limit = false;
8245 8246
    bool set_hard_limit = false;
    bool set_soft_limit = false;
8247
    virQEMUDriverConfigPtr cfg = NULL;
8248
    int rc;
8249
    int ret = -1;
8250
    virCapsPtr caps = NULL;
8251
    qemuDomainObjPrivatePtr priv;
8252

8253 8254
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
8255

8256 8257 8258 8259 8260 8261 8262 8263
    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)
8264
        return -1;
8265 8266


8267 8268
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
8269

8270
    priv = vm->privateData;
8271 8272
    cfg = virQEMUDriverGetConfig(driver);

8273 8274 8275
    if (virDomainSetMemoryParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

8276 8277 8278
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

8279
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8280 8281
                                        &persistentDef) < 0)
        goto cleanup;
8282

8283
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8284
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
8285 8286
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
8287 8288 8289 8290
            goto cleanup;
        }
    }

8291
#define VIR_GET_LIMIT_PARAMETER(PARAM, VALUE)                                \
8292
    if ((rc = virTypedParamsGetULLong(params, nparams, PARAM, &VALUE)) < 0)  \
8293 8294 8295 8296 8297 8298
        goto cleanup;                                                        \
                                                                             \
    if (rc == 1)                                                             \
        set_ ## VALUE = true;

    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT, swap_hard_limit)
8299 8300
    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_HARD_LIMIT, hard_limit)
    VIR_GET_LIMIT_PARAMETER(VIR_DOMAIN_MEMORY_SOFT_LIMIT, soft_limit)
8301 8302 8303

#undef VIR_GET_LIMIT_PARAMETER

8304 8305 8306 8307 8308
    /* 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;
8309

8310 8311
        if (set_swap_hard_limit)
            swap_limit = swap_hard_limit;
8312

8313 8314 8315 8316 8317 8318
        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 "
8319
                             "than or equal to swap_hard_limit"));
8320
            goto cleanup;
8321
        }
8322
    }
8323

8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337
#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;                                   \
8338 8339
    }

8340 8341
    /* Soft limit doesn't clash with the others */
    QEMU_SET_MEM_PARAMETER(virCgroupSetMemorySoftLimit, soft_limit);
8342

8343 8344 8345 8346 8347
    /* 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;
8348
    }
8349

8350
    QEMU_SET_MEM_PARAMETER(virCgroupSetMemSwapHardLimit, swap_hard_limit);
8351

8352 8353 8354 8355
    /* otherwise increase it after swap hard limit */
    QEMU_SET_MEM_PARAMETER(virCgroupSetMemoryHardLimit, hard_limit);

#undef QEMU_SET_MEM_PARAMETER
8356

8357 8358 8359 8360 8361 8362
    if (flags & VIR_DOMAIN_AFFECT_CONFIG &&
        virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
        goto cleanup;

    ret = 0;

8363
cleanup:
8364
    virObjectUnlock(vm);
8365
    virObjectUnref(caps);
8366
    virObjectUnref(cfg);
8367 8368 8369
    return ret;
}

8370 8371 8372 8373 8374
static int
qemuDomainGetMemoryParameters(virDomainPtr dom,
                              virTypedParameterPtr params,
                              int *nparams,
                              unsigned int flags)
8375
{
8376
    virQEMUDriverPtr driver = dom->conn->privateData;
8377
    size_t i;
8378
    virDomainObjPtr vm = NULL;
8379
    virDomainDefPtr persistentDef = NULL;
8380
    int ret = -1;
8381
    virCapsPtr caps = NULL;
8382
    qemuDomainObjPrivatePtr priv;
8383

8384
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
8385 8386
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
8387

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

8391 8392
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
8393

8394
    priv = vm->privateData;
8395 8396 8397 8398

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

8399 8400 8401
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

8402
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8403 8404
                                        &persistentDef) < 0)
        goto cleanup;
8405

8406
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8407
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
8408 8409
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
8410 8411 8412 8413
            goto cleanup;
        }
    }

8414 8415 8416 8417 8418 8419 8420
    if ((*nparams) == 0) {
        /* Current number of memory parameters supported by cgroups */
        *nparams = QEMU_NB_MEM_PARAM;
        ret = 0;
        goto cleanup;
    }

8421
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8422
        for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
8423
            virMemoryParameterPtr param = &params[i];
8424
            unsigned long long value;
8425 8426 8427

            switch (i) {
            case 0: /* fill memory hard limit here */
8428 8429 8430 8431
                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)
8432 8433 8434 8435
                    goto cleanup;
                break;

            case 1: /* fill memory soft limit here */
8436 8437 8438 8439
                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)
8440 8441 8442 8443
                    goto cleanup;
                break;

            case 2: /* fill swap hard limit here */
8444 8445 8446 8447
                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)
8448 8449 8450 8451 8452 8453 8454 8455 8456
                    goto cleanup;
                break;

            default:
                break;
                /* should not hit here */
            }
        }
        goto out;
8457 8458
    }

8459
    for (i = 0; i < *nparams && i < QEMU_NB_MEM_PARAM; i++) {
8460
        virTypedParameterPtr param = &params[i];
8461
        unsigned long long val = 0;
8462

8463
        switch (i) {
8464
        case 0: /* fill memory hard limit here */
8465
            if (virCgroupGetMemoryHardLimit(priv->cgroup, &val) < 0)
8466
                goto cleanup;
8467 8468 8469
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
8470
                goto cleanup;
8471 8472 8473
            break;

        case 1: /* fill memory soft limit here */
8474
            if (virCgroupGetMemorySoftLimit(priv->cgroup, &val) < 0)
8475
                goto cleanup;
8476 8477 8478
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SOFT_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
8479
                goto cleanup;
8480 8481 8482
            break;

        case 2: /* fill swap hard limit here */
8483 8484 8485
            if (virCgroupGetMemSwapHardLimit(priv->cgroup, &val) < 0) {
                if (!virLastErrorIsSystemErrno(ENOENT) &&
                    !virLastErrorIsSystemErrno(EOPNOTSUPP))
8486 8487
                    goto cleanup;
                val = VIR_DOMAIN_MEMORY_PARAM_UNLIMITED;
8488
            }
8489 8490 8491
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_MEMORY_SWAP_HARD_LIMIT,
                                        VIR_TYPED_PARAM_ULLONG, val) < 0)
8492
                goto cleanup;
8493 8494 8495 8496 8497 8498 8499 8500
            break;

        default:
            break;
            /* should not hit here */
        }
    }

8501
out:
8502 8503
    if (QEMU_NB_MEM_PARAM < *nparams)
        *nparams = QEMU_NB_MEM_PARAM;
8504 8505
    ret = 0;

8506 8507
cleanup:
    if (vm)
8508
        virObjectUnlock(vm);
8509
    virObjectUnref(caps);
8510 8511 8512
    return ret;
}

8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531
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;
    }

8532
    /* Get existing nodeset values */
8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562
    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;
        if (virBitmapGetBit(nodeset, i, &result) < 0) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("Failed to get cpuset bit values"));
            goto cleanup;
        }
        if (result && (virBitmapSetBit(temp_nodeset, i) < 0)) {
            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);

8563
    /* Ensure the cpuset string is formatted before passing to cgroup */
8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590
    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;
}

8591 8592 8593 8594 8595 8596
static int
qemuDomainSetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
{
8597
    virQEMUDriverPtr driver = dom->conn->privateData;
8598
    size_t i;
8599 8600 8601
    virDomainDefPtr persistentDef = NULL;
    virDomainObjPtr vm = NULL;
    int ret = -1;
8602
    virQEMUDriverConfigPtr cfg = NULL;
8603
    virCapsPtr caps = NULL;
8604
    qemuDomainObjPrivatePtr priv;
8605 8606 8607

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
8608

8609 8610 8611 8612 8613 8614
    if (virTypedParamsValidate(params, nparams,
                               VIR_DOMAIN_NUMA_MODE,
                               VIR_TYPED_PARAM_INT,
                               VIR_DOMAIN_NUMA_NODESET,
                               VIR_TYPED_PARAM_STRING,
                               NULL) < 0)
8615
        return -1;
8616

8617 8618
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
8619

8620
    priv = vm->privateData;
8621
    cfg = virQEMUDriverGetConfig(driver);
8622

8623 8624 8625
    if (virDomainSetNumaParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

8626 8627 8628
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

8629
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8630 8631 8632 8633
                                        &persistentDef) < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8634
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUSET)) {
8635 8636
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("cgroup cpuset controller is not mounted"));
8637 8638 8639 8640 8641 8642 8643 8644
            goto cleanup;
        }
    }

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

        if (STREQ(param->field, VIR_DOMAIN_NUMA_MODE)) {
8645 8646
            int mode = param->value.i;

8647 8648 8649 8650 8651 8652 8653 8654
            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;
            }

8655
            if ((flags & VIR_DOMAIN_AFFECT_LIVE) &&
8656
                vm->def->numatune.memory.mode != mode) {
8657 8658
                virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                               _("can't change numa mode for running domain"));
8659 8660 8661
                goto cleanup;
            }

8662 8663 8664
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                persistentDef->numatune.memory.mode = mode;

8665
        } else if (STREQ(param->field, VIR_DOMAIN_NUMA_NODESET)) {
8666
            virBitmapPtr nodeset = NULL;
8667

8668
            if (virBitmapParse(param->value.s, 0, &nodeset,
8669
                               VIR_DOMAIN_CPUMASK_LEN) < 0) {
8670
                goto cleanup;
8671
            }
8672 8673

            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8674
                if (qemuDomainSetNumaParamsLive(vm, caps, nodeset) < 0) {
8675
                    virBitmapFree(nodeset);
8676
                    goto cleanup;
8677 8678 8679 8680
                }

                /* update vm->def here so that dumpxml can read the new
                 * values from vm->def. */
8681
                virBitmapFree(vm->def->numatune.memory.nodemask);
8682

8683
                vm->def->numatune.memory.placement_mode =
G
Gao feng 已提交
8684
                    VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC;
8685
                vm->def->numatune.memory.nodemask = virBitmapNewCopy(nodeset);
8686 8687 8688
            }

            if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8689
                virBitmapFree(persistentDef->numatune.memory.nodemask);
8690 8691

                persistentDef->numatune.memory.nodemask = nodeset;
8692
                persistentDef->numatune.memory.placement_mode =
G
Gao feng 已提交
8693
                    VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_STATIC;
8694
                nodeset = NULL;
8695
            }
8696
            virBitmapFree(nodeset);
8697 8698 8699 8700
        }
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
8701 8702
        if (!persistentDef->numatune.memory.placement_mode)
            persistentDef->numatune.memory.placement_mode =
G
Gao feng 已提交
8703
                VIR_NUMA_TUNE_MEM_PLACEMENT_MODE_AUTO;
8704
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
8705
            goto cleanup;
8706 8707
    }

8708 8709
    ret = 0;

8710 8711
cleanup:
    if (vm)
8712
        virObjectUnlock(vm);
8713
    virObjectUnref(caps);
8714
    virObjectUnref(cfg);
8715 8716 8717 8718 8719 8720 8721 8722 8723
    return ret;
}

static int
qemuDomainGetNumaParameters(virDomainPtr dom,
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
{
8724
    virQEMUDriverPtr driver = dom->conn->privateData;
8725
    size_t i;
8726 8727 8728 8729
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    char *nodeset = NULL;
    int ret = -1;
8730
    virCapsPtr caps = NULL;
8731
    qemuDomainObjPrivatePtr priv;
8732 8733 8734 8735 8736 8737 8738 8739 8740 8741

    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;

8742 8743
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
8744

8745 8746
    priv = vm->privateData;

8747 8748 8749
    if (virDomainGetNumaParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

8750 8751 8752
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

8753
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8754 8755 8756 8757 8758 8759 8760 8761 8762 8763
                                        &persistentDef) < 0)
        goto cleanup;

    if ((*nparams) == 0) {
        *nparams = QEMU_NB_NUMA_PARAM;
        ret = 0;
        goto cleanup;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8764
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_MEMORY)) {
8765 8766
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup memory controller is not mounted"));
8767 8768 8769 8770 8771 8772 8773 8774 8775
            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 */
8776 8777
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_MODE,
                                        VIR_TYPED_PARAM_INT, 0) < 0)
8778 8779 8780 8781 8782 8783 8784 8785 8786
                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) {
8787
                nodeset = virBitmapFormat(persistentDef->numatune.memory.nodemask);
8788 8789
                if (!nodeset && VIR_STRDUP(nodeset, "") < 0)
                    goto cleanup;
8790
            } else {
8791
                if (virCgroupGetCpusetMems(priv->cgroup, &nodeset) < 0)
8792 8793
                    goto cleanup;
            }
8794 8795
            if (virTypedParameterAssign(param, VIR_DOMAIN_NUMA_NODESET,
                                        VIR_TYPED_PARAM_STRING, nodeset) < 0)
8796
                goto cleanup;
S
Stefan Berger 已提交
8797 8798 8799

            nodeset = NULL;

8800 8801 8802 8803 8804 8805 8806 8807 8808 8809 8810 8811 8812
            break;

        default:
            break;
            /* should not hit here */
        }
    }

    if (*nparams > QEMU_NB_NUMA_PARAM)
        *nparams = QEMU_NB_NUMA_PARAM;
    ret = 0;

cleanup:
S
Stefan Berger 已提交
8813
    VIR_FREE(nodeset);
8814
    if (vm)
8815
        virObjectUnlock(vm);
8816
    virObjectUnref(caps);
8817 8818 8819
    return ret;
}

8820 8821 8822 8823
static int
qemuSetVcpusBWLive(virDomainObjPtr vm, virCgroupPtr cgroup,
                   unsigned long long period, long long quota)
{
8824
    size_t i;
8825 8826 8827 8828 8829 8830
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virCgroupPtr cgroup_vcpu = NULL;

    if (period == 0 && quota == 0)
        return 0;

W
Wen Congyang 已提交
8831 8832 8833 8834 8835 8836
    /* 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++) {
8837
            if (virCgroupNewVcpu(cgroup, i, false, &cgroup_vcpu) < 0)
W
Wen Congyang 已提交
8838 8839 8840 8841 8842 8843 8844
                goto cleanup;

            if (qemuSetupCgroupVcpuBW(cgroup_vcpu, period, quota) < 0)
                goto cleanup;

            virCgroupFree(&cgroup_vcpu);
        }
8845 8846 8847 8848 8849 8850 8851 8852 8853
    }

    return 0;

cleanup:
    virCgroupFree(&cgroup_vcpu);
    return -1;
}

8854 8855 8856 8857 8858 8859 8860 8861 8862 8863 8864 8865 8866 8867
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;
    }

8868
    if (virCgroupNewEmulator(cgroup, false, &cgroup_emulator) < 0)
8869 8870 8871 8872 8873 8874 8875 8876 8877 8878 8879 8880 8881
        goto cleanup;

    if (qemuSetupCgroupVcpuBW(cgroup_emulator, period, quota) < 0)
        goto cleanup;

    virCgroupFree(&cgroup_emulator);
    return 0;

cleanup:
    virCgroupFree(&cgroup_emulator);
    return -1;
}

8882 8883 8884 8885 8886 8887 8888 8889 8890
#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;                                                       \
    }

8891
static int
8892 8893 8894 8895
qemuDomainSetSchedulerParametersFlags(virDomainPtr dom,
                                      virTypedParameterPtr params,
                                      int nparams,
                                      unsigned int flags)
8896
{
8897
    virQEMUDriverPtr driver = dom->conn->privateData;
8898
    size_t i;
8899
    virDomainObjPtr vm = NULL;
8900
    virDomainDefPtr vmdef = NULL;
8901 8902
    unsigned long long value_ul;
    long long value_l;
8903
    int ret = -1;
8904
    int rc;
8905
    virQEMUDriverConfigPtr cfg = NULL;
8906
    virCapsPtr caps = NULL;
8907
    qemuDomainObjPrivatePtr priv;
8908

8909 8910
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
8911 8912 8913 8914 8915 8916 8917 8918 8919 8920 8921 8922
    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)
8923
        return -1;
8924

8925 8926
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
8927

8928
    priv = vm->privateData;
8929 8930
    cfg = virQEMUDriverGetConfig(driver);

8931 8932 8933
    if (virDomainSetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

8934 8935 8936
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

8937
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
8938 8939
                                        &vmdef) < 0)
        goto cleanup;
8940

8941 8942
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        /* Make a copy for updated domain. */
8943
        vmdef = virDomainObjCopyPersistentDef(vm, caps, driver->xmlopt);
8944 8945
        if (!vmdef)
            goto cleanup;
8946 8947
    }

8948
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8949
        if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
8950 8951
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("cgroup CPU controller is not mounted"));
8952 8953 8954 8955
            goto cleanup;
        }
    }

8956
    for (i = 0; i < nparams; i++) {
8957
        virTypedParameterPtr param = &params[i];
8958 8959
        value_ul = param->value.ul;
        value_l = param->value.l;
8960

8961
        if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_CPU_SHARES)) {
8962
            if (flags & VIR_DOMAIN_AFFECT_LIVE) {
8963
                if (virCgroupSetCpuShares(priv->cgroup, value_ul) < 0)
8964
                    goto cleanup;
8965
                vm->def->cputune.shares = value_ul;
8966
            }
8967

8968 8969 8970
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.shares = value_ul;

8971
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD)) {
8972 8973 8974
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

8975
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
8976
                if ((rc = qemuSetVcpusBWLive(vm, priv->cgroup, value_ul, 0)))
8977
                    goto cleanup;
8978

8979
                vm->def->cputune.period = value_ul;
8980 8981
            }

8982
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
8983
                vmdef->cputune.period = params[i].value.ul;
8984

8985
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA)) {
8986 8987 8988
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

8989
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
8990
                if ((rc = qemuSetVcpusBWLive(vm, priv->cgroup, 0, value_l)))
8991
                    goto cleanup;
8992

8993
                vm->def->cputune.quota = value_l;
8994 8995
            }

8996 8997 8998
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.quota = value_l;

8999
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD)) {
9000 9001 9002
            SCHED_RANGE_CHECK(value_ul, VIR_DOMAIN_SCHEDULER_EMULATOR_PERIOD,
                              QEMU_SCHED_MIN_PERIOD, QEMU_SCHED_MAX_PERIOD);

9003
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_ul) {
9004 9005
                if ((rc = qemuSetEmulatorBandwidthLive(vm, priv->cgroup,
                                                       value_ul, 0)))
9006 9007
                    goto cleanup;

9008
                vm->def->cputune.emulator_period = value_ul;
9009 9010
            }

9011 9012 9013
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_period = value_ul;

9014
        } else if (STREQ(param->field, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA)) {
9015 9016 9017
            SCHED_RANGE_CHECK(value_l, VIR_DOMAIN_SCHEDULER_EMULATOR_QUOTA,
                              QEMU_SCHED_MIN_QUOTA, QEMU_SCHED_MAX_QUOTA);

9018
            if (flags & VIR_DOMAIN_AFFECT_LIVE && value_l) {
9019 9020
                if ((rc = qemuSetEmulatorBandwidthLive(vm, priv->cgroup,
                                                       0, value_l)))
9021 9022
                    goto cleanup;

9023
                vm->def->cputune.emulator_quota = value_l;
9024 9025
            }

9026 9027
            if (flags & VIR_DOMAIN_AFFECT_CONFIG)
                vmdef->cputune.emulator_quota = value_l;
9028 9029
        }
    }
9030

9031
    if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0)
9032 9033 9034 9035
        goto cleanup;


    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
9036
        rc = virDomainSaveConfig(cfg->configDir, vmdef);
9037 9038 9039
        if (rc < 0)
            goto cleanup;

9040
        virDomainObjAssignDef(vm, vmdef, false, NULL);
9041 9042 9043
        vmdef = NULL;
    }

9044 9045 9046
    ret = 0;

cleanup:
9047
    virDomainDefFree(vmdef);
9048
    if (vm)
9049
        virObjectUnlock(vm);
9050
    virObjectUnref(caps);
9051
    virObjectUnref(cfg);
9052 9053
    return ret;
}
9054
#undef SCHED_RANGE_CHECK
9055

9056
static int
9057 9058 9059
qemuDomainSetSchedulerParameters(virDomainPtr dom,
                                 virTypedParameterPtr params,
                                 int nparams)
9060
{
9061 9062 9063 9064
    return qemuDomainSetSchedulerParametersFlags(dom,
                                                 params,
                                                 nparams,
                                                 VIR_DOMAIN_AFFECT_CURRENT);
9065 9066
}

9067 9068 9069 9070
static int
qemuGetVcpuBWLive(virCgroupPtr cgroup, unsigned long long *period,
                  long long *quota)
{
9071
    if (virCgroupGetCpuCfsPeriod(cgroup, period) < 0)
9072 9073
        return -1;

9074
    if (virCgroupGetCpuCfsQuota(cgroup, quota) < 0)
9075 9076 9077 9078 9079 9080
        return -1;

    return 0;
}

static int
9081
qemuGetVcpusBWLive(virDomainObjPtr vm,
9082 9083 9084 9085 9086 9087 9088 9089 9090 9091
                   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 */
9092
        rc = qemuGetVcpuBWLive(priv->cgroup, period, quota);
9093 9094 9095 9096 9097 9098 9099 9100 9101
        if (rc < 0)
            goto cleanup;

        if (*quota > 0)
            *quota /= vm->def->vcpus;
        goto out;
    }

    /* get period and quota for vcpu0 */
9102
    if (virCgroupNewVcpu(priv->cgroup, 0, false, &cgroup_vcpu) < 0)
9103 9104 9105 9106 9107 9108 9109 9110 9111 9112 9113 9114 9115 9116
        goto cleanup;

    rc = qemuGetVcpuBWLive(cgroup_vcpu, period, quota);
    if (rc < 0)
        goto cleanup;

out:
    ret = 0;

cleanup:
    virCgroupFree(&cgroup_vcpu);
    return ret;
}

9117 9118 9119 9120 9121 9122 9123 9124 9125 9126 9127 9128 9129 9130 9131 9132 9133 9134
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 */
9135
    if (virCgroupNewEmulator(cgroup, false, &cgroup_emulator) < 0)
9136 9137 9138 9139 9140 9141 9142 9143 9144 9145 9146 9147 9148
        goto cleanup;

    rc = qemuGetVcpuBWLive(cgroup_emulator, period, quota);
    if (rc < 0)
        goto cleanup;

    ret = 0;

cleanup:
    virCgroupFree(&cgroup_emulator);
    return ret;
}

9149
static int
9150 9151 9152 9153
qemuDomainGetSchedulerParametersFlags(virDomainPtr dom,
                                      virTypedParameterPtr params,
                                      int *nparams,
                                      unsigned int flags)
9154
{
9155
    virQEMUDriverPtr driver = dom->conn->privateData;
9156
    virDomainObjPtr vm = NULL;
9157 9158 9159
    unsigned long long shares;
    unsigned long long period;
    long long quota;
9160 9161
    unsigned long long emulator_period;
    long long emulator_quota;
9162 9163
    int ret = -1;
    int rc;
9164
    bool cpu_bw_status = false;
9165
    int saved_nparams = 0;
9166
    virDomainDefPtr persistentDef;
9167
    virCapsPtr caps = NULL;
9168
    qemuDomainObjPrivatePtr priv;
9169

9170
    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
9171 9172
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);
9173

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

9177 9178 9179 9180 9181
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;

    priv = vm->privateData;

9182 9183 9184
    if (virDomainGetSchedulerParametersFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

9185 9186
    if (*nparams > 1)
        cpu_bw_status = virCgroupSupportsCpuBW(priv->cgroup);
9187

9188 9189 9190
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

9191
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
9192 9193
                                        &persistentDef) < 0)
        goto cleanup;
9194

9195
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
9196
        shares = persistentDef->cputune.shares;
9197
        if (*nparams > 1) {
9198 9199
            period = persistentDef->cputune.period;
            quota = persistentDef->cputune.quota;
9200 9201
            emulator_period = persistentDef->cputune.emulator_period;
            emulator_quota = persistentDef->cputune.emulator_quota;
9202
            cpu_bw_status = true; /* Allow copy of data to params[] */
9203
        }
9204
        goto out;
9205 9206
    }

9207
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPU)) {
9208 9209
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPU controller is not mounted"));
9210 9211 9212
        goto cleanup;
    }

9213
    if (virCgroupGetCpuShares(priv->cgroup, &shares) < 0)
9214
        goto cleanup;
9215 9216

    if (*nparams > 1 && cpu_bw_status) {
9217
        rc = qemuGetVcpusBWLive(vm, &period, &quota);
9218 9219 9220
        if (rc != 0)
            goto cleanup;
    }
9221 9222

    if (*nparams > 3 && cpu_bw_status) {
9223
        rc = qemuGetEmulatorBandwidthLive(vm, priv->cgroup, &emulator_period,
9224 9225 9226 9227 9228
                                          &emulator_quota);
        if (rc != 0)
            goto cleanup;
    }

9229
out:
9230 9231
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_SCHEDULER_CPU_SHARES,
                                VIR_TYPED_PARAM_ULLONG, shares) < 0)
C
Chris Lalancette 已提交
9232
        goto cleanup;
9233 9234 9235 9236
    saved_nparams++;

    if (cpu_bw_status) {
        if (*nparams > saved_nparams) {
9237 9238 9239
            if (virTypedParameterAssign(&params[1],
                                        VIR_DOMAIN_SCHEDULER_VCPU_PERIOD,
                                        VIR_TYPED_PARAM_ULLONG, period) < 0)
9240 9241 9242 9243 9244
                goto cleanup;
            saved_nparams++;
        }

        if (*nparams > saved_nparams) {
9245 9246 9247
            if (virTypedParameterAssign(&params[2],
                                        VIR_DOMAIN_SCHEDULER_VCPU_QUOTA,
                                        VIR_TYPED_PARAM_LLONG, quota) < 0)
9248 9249 9250
                goto cleanup;
            saved_nparams++;
        }
9251 9252 9253 9254 9255 9256 9257 9258 9259 9260 9261 9262 9263 9264 9265 9266 9267 9268

        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++;
        }
9269 9270 9271 9272
    }

    *nparams = saved_nparams;

9273 9274 9275 9276
    ret = 0;

cleanup:
    if (vm)
9277
        virObjectUnlock(vm);
9278
    virObjectUnref(caps);
9279 9280 9281
    return ret;
}

9282
static int
9283 9284 9285
qemuDomainGetSchedulerParameters(virDomainPtr dom,
                                 virTypedParameterPtr params,
                                 int *nparams)
9286
{
9287 9288
    return qemuDomainGetSchedulerParametersFlags(dom, params, nparams,
                                                 VIR_DOMAIN_AFFECT_CURRENT);
9289
}
9290

9291 9292 9293 9294 9295 9296 9297
/**
 * 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 已提交
9298 9299 9300 9301
qemuDomainBlockResize(virDomainPtr dom,
                      const char *path,
                      unsigned long long size,
                      unsigned int flags)
9302
{
9303
    virQEMUDriverPtr driver = dom->conn->privateData;
9304 9305
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
9306
    int ret = -1, idx;
9307 9308 9309
    char *device = NULL;
    virDomainDiskDefPtr disk = NULL;

E
Eric Blake 已提交
9310
    virCheckFlags(VIR_DOMAIN_BLOCK_RESIZE_BYTES, -1);
9311 9312

    if (path[0] == '\0') {
9313 9314
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("empty path"));
9315 9316 9317
        return -1;
    }

E
Eric Blake 已提交
9318 9319 9320
    /* We prefer operating on bytes.  */
    if ((flags & VIR_DOMAIN_BLOCK_RESIZE_BYTES) == 0) {
        if (size > ULLONG_MAX / 1024) {
9321 9322 9323
            virReportError(VIR_ERR_OVERFLOW,
                           _("size must be less than %llu"),
                           ULLONG_MAX / 1024);
E
Eric Blake 已提交
9324 9325 9326
            return -1;
        }
        size *= 1024;
9327 9328
    }

9329
    if (!(vm = qemuDomObjFromDomain(dom)))
9330 9331 9332 9333
        goto cleanup;

    priv = vm->privateData;

9334 9335 9336
    if (virDomainBlockResizeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

9337 9338 9339 9340
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

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

9346
    if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
9347 9348
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
9349
        goto endjob;
9350
    }
9351
    disk = vm->def->disks[idx];
9352 9353

    if (virAsprintf(&device, "%s%s", QEMU_DRIVE_HOST_PREFIX,
9354
                    disk->info.alias) < 0)
9355 9356 9357 9358 9359 9360 9361 9362 9363 9364 9365 9366
        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 已提交
9367
    if (!qemuDomainObjEndJob(driver, vm))
9368 9369 9370 9371 9372
        vm = NULL;

cleanup:
    VIR_FREE(device);
    if (vm)
9373
        virObjectUnlock(vm);
9374 9375 9376
    return ret;
}

9377 9378 9379 9380 9381
/* 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
9382 9383 9384
qemuDomainBlockStats(virDomainPtr dom,
                     const char *path,
                     struct _virDomainBlockStats *stats)
9385
{
9386
    virQEMUDriverPtr driver = dom->conn->privateData;
9387 9388
    int idx;
    int ret = -1;
9389
    virDomainObjPtr vm;
9390
    virDomainDiskDefPtr disk = NULL;
9391
    qemuDomainObjPrivatePtr priv;
9392

9393
    if (!(vm = qemuDomObjFromDomain(dom)))
9394
        goto cleanup;
9395

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

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

9402
    if (!virDomainObjIsActive(vm)) {
9403 9404
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9405
        goto endjob;
9406 9407
    }

9408
    if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
9409 9410
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path: %s"), path);
9411
        goto endjob;
9412
    }
9413
    disk = vm->def->disks[idx];
9414

9415
    if (!disk->info.alias) {
9416 9417
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("missing disk device alias name for %s"), disk->dst);
9418
        goto endjob;
9419
    }
9420

9421
    priv = vm->privateData;
9422

9423
    qemuDomainObjEnterMonitor(driver, vm);
9424 9425 9426 9427
    ret = qemuMonitorGetBlockStatsInfo(priv->mon,
                                       disk->info.alias,
                                       &stats->rd_req,
                                       &stats->rd_bytes,
9428
                                       NULL,
9429 9430
                                       &stats->wr_req,
                                       &stats->wr_bytes,
9431 9432 9433
                                       NULL,
                                       NULL,
                                       NULL,
9434 9435
                                       &stats->errs);
    qemuDomainObjExitMonitor(driver, vm);
9436

9437
endjob:
E
Eric Blake 已提交
9438
    if (!qemuDomainObjEndJob(driver, vm))
9439
        vm = NULL;
9440

9441
cleanup:
9442
    if (vm)
9443
        virObjectUnlock(vm);
9444
    return ret;
9445 9446
}

9447
static int
9448 9449 9450 9451 9452
qemuDomainBlockStatsFlags(virDomainPtr dom,
                          const char *path,
                          virTypedParameterPtr params,
                          int *nparams,
                          unsigned int flags)
9453
{
9454
    virQEMUDriverPtr driver = dom->conn->privateData;
9455 9456
    int idx;
    int tmp, ret = -1;
9457 9458 9459 9460 9461
    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;
9462
    virTypedParameterPtr param;
9463

9464 9465 9466 9467
    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

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

9469
    if (!(vm = qemuDomObjFromDomain(dom)))
9470 9471
        goto cleanup;

9472 9473 9474
    if (virDomainBlockStatsFlagsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

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

9478
    if (!virDomainObjIsActive(vm)) {
9479 9480
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9481
        goto endjob;
9482 9483 9484
    }

    if (*nparams != 0) {
9485
        if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
9486 9487
            virReportError(VIR_ERR_INVALID_ARG,
                           _("invalid path: %s"), path);
9488
            goto endjob;
9489
        }
9490
        disk = vm->def->disks[idx];
9491 9492

        if (!disk->info.alias) {
9493 9494 9495
             virReportError(VIR_ERR_INTERNAL_ERROR,
                            _("missing disk device alias name for %s"),
                            disk->dst);
9496
             goto endjob;
9497 9498 9499 9500 9501 9502 9503 9504 9505 9506
        }
    }

    priv = vm->privateData;
    VIR_DEBUG("priv=%p, params=%p, flags=%x", priv, params, flags);

    qemuDomainObjEnterMonitor(driver, vm);
    tmp = *nparams;
    ret = qemuMonitorGetBlockStatsParamsNumber(priv->mon, nparams);

9507
    if (tmp == 0 || ret < 0) {
9508 9509 9510 9511 9512 9513 9514 9515 9516 9517 9518 9519 9520 9521 9522 9523 9524 9525 9526 9527 9528
        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;

9529 9530
    tmp = 0;
    ret = -1;
9531

9532 9533
    if (tmp < *nparams && wr_bytes != -1) {
        param = &params[tmp];
9534 9535
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_BYTES,
                                    VIR_TYPED_PARAM_LLONG, wr_bytes) < 0)
9536 9537 9538
            goto endjob;
        tmp++;
    }
9539

9540
    if (tmp < *nparams && wr_req != -1) {
9541
        param = &params[tmp];
9542 9543
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_WRITE_REQ,
                                    VIR_TYPED_PARAM_LLONG, wr_req) < 0)
9544 9545 9546
            goto endjob;
        tmp++;
    }
9547

9548
    if (tmp < *nparams && rd_bytes != -1) {
9549
        param = &params[tmp];
9550 9551
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_BYTES,
                                    VIR_TYPED_PARAM_LLONG, rd_bytes) < 0)
9552 9553 9554
            goto endjob;
        tmp++;
    }
9555

9556
    if (tmp < *nparams && rd_req != -1) {
9557
        param = &params[tmp];
9558 9559
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_READ_REQ,
                                    VIR_TYPED_PARAM_LLONG, rd_req) < 0)
9560 9561 9562
            goto endjob;
        tmp++;
    }
9563

9564
    if (tmp < *nparams && flush_req != -1) {
9565
        param = &params[tmp];
9566 9567
        if (virTypedParameterAssign(param, VIR_DOMAIN_BLOCK_STATS_FLUSH_REQ,
                                    VIR_TYPED_PARAM_LLONG, flush_req) < 0)
9568 9569 9570
            goto endjob;
        tmp++;
    }
9571

9572
    if (tmp < *nparams && wr_total_times != -1) {
9573
        param = &params[tmp];
9574 9575 9576
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_WRITE_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, wr_total_times) < 0)
9577 9578 9579
            goto endjob;
        tmp++;
    }
9580

9581
    if (tmp < *nparams && rd_total_times != -1) {
9582
        param = &params[tmp];
9583 9584 9585
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_READ_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG, rd_total_times) < 0)
9586 9587 9588
            goto endjob;
        tmp++;
    }
9589

9590
    if (tmp < *nparams && flush_total_times != -1) {
9591
        param = &params[tmp];
9592 9593 9594 9595
        if (virTypedParameterAssign(param,
                                    VIR_DOMAIN_BLOCK_STATS_FLUSH_TOTAL_TIMES,
                                    VIR_TYPED_PARAM_LLONG,
                                    flush_total_times) < 0)
9596 9597
            goto endjob;
        tmp++;
9598 9599
    }

9600 9601 9602 9603 9604
    /* Field 'errs' is meaningless for QEMU, won't set it. */

    ret = 0;
    *nparams = tmp;

9605
endjob:
E
Eric Blake 已提交
9606
    if (!qemuDomainObjEndJob(driver, vm))
9607 9608 9609 9610
        vm = NULL;

cleanup:
    if (vm)
9611
        virObjectUnlock(vm);
9612 9613 9614
    return ret;
}

9615
#ifdef __linux__
9616
static int
9617 9618 9619
qemuDomainInterfaceStats(virDomainPtr dom,
                         const char *path,
                         struct _virDomainInterfaceStats *stats)
9620
{
9621
    virDomainObjPtr vm;
9622
    size_t i;
9623
    int ret = -1;
9624

9625
    if (!(vm = qemuDomObjFromDomain(dom)))
9626
        goto cleanup;
9627

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

D
Daniel P. Berrange 已提交
9631
    if (!virDomainObjIsActive(vm)) {
9632 9633
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
9634
        goto cleanup;
9635 9636 9637
    }

    /* Check the path is one of the domain's network interfaces. */
9638
    for (i = 0; i < vm->def->nnets; i++) {
9639
        if (vm->def->nets[i]->ifname &&
9640
            STREQ(vm->def->nets[i]->ifname, path)) {
9641 9642 9643
            ret = 0;
            break;
        }
9644 9645
    }

9646
    if (ret == 0)
9647
        ret = linuxDomainInterfaceStats(path, stats);
9648
    else
9649 9650
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path, '%s' is not a known interface"), path);
9651

9652
cleanup:
9653
    if (vm)
9654
        virObjectUnlock(vm);
9655 9656
    return ret;
}
9657
#else
9658
static int
E
Eric Blake 已提交
9659
qemuDomainInterfaceStats(virDomainPtr dom ATTRIBUTE_UNUSED,
9660 9661
                         const char *path ATTRIBUTE_UNUSED,
                         struct _virDomainInterfaceStats *stats ATTRIBUTE_UNUSED)
9662
{
9663 9664
    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                   _("interface stats not implemented on this platform"));
9665 9666
    return -1;
}
9667
#endif
9668

9669 9670 9671 9672 9673 9674 9675
static int
qemuDomainSetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int nparams,
                                 unsigned int flags)
{
9676
    virQEMUDriverPtr driver = dom->conn->privateData;
9677
    size_t i;
9678 9679 9680 9681
    virDomainObjPtr vm = NULL;
    virDomainDefPtr persistentDef = NULL;
    int ret = -1;
    virDomainNetDefPtr net = NULL, persistentNet = NULL;
9682
    virNetDevBandwidthPtr bandwidth = NULL, newBandwidth = NULL;
9683
    virQEMUDriverConfigPtr cfg = NULL;
9684
    virCapsPtr caps = NULL;
9685 9686 9687

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
9688 9689 9690 9691 9692 9693 9694 9695 9696 9697 9698 9699 9700 9701
    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)
9702
        return -1;
9703

9704 9705
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
9706

9707 9708
    cfg = virQEMUDriverGetConfig(driver);

9709 9710 9711
    if (virDomainSetInterfaceParametersEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

9712 9713 9714
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

9715
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
9716 9717 9718 9719 9720 9721
                                        &persistentDef) < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        net = virDomainNetFind(vm->def, device);
        if (!net) {
9722 9723
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
9724 9725 9726 9727 9728 9729
            goto cleanup;
        }
    }
    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
        persistentNet = virDomainNetFind(persistentDef, device);
        if (!persistentNet) {
9730 9731
            virReportError(VIR_ERR_INVALID_ARG,
                           _("Can't find device %s"), device);
9732 9733 9734 9735
            goto cleanup;
        }
    }

9736 9737
    if ((VIR_ALLOC(bandwidth) < 0) ||
        (VIR_ALLOC(bandwidth->in) < 0) ||
9738
        (VIR_ALLOC(bandwidth->out) < 0))
9739 9740 9741 9742 9743 9744 9745 9746 9747 9748 9749 9750 9751 9752 9753 9754 9755 9756 9757 9758
        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;
        }
    }

9759
    /* average is mandatory, peak and burst are optional. So if no
9760
     * average is given, we free inbound/outbound here which causes
9761
     * inbound/outbound to not be set. */
9762 9763 9764 9765 9766 9767 9768 9769
    if (!bandwidth->in->average) {
        VIR_FREE(bandwidth->in);
    }
    if (!bandwidth->out->average) {
        VIR_FREE(bandwidth->out);
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
9770
        if (VIR_ALLOC(newBandwidth) < 0)
9771 9772 9773 9774
            goto cleanup;

        /* virNetDevBandwidthSet() will clear any previous value of
         * bandwidth parameters, so merge with old bandwidth parameters
9775
         * here to prevent them from being lost. */
9776 9777
        if (bandwidth->in ||
            (net->bandwidth && net->bandwidth->in)) {
9778
            if (VIR_ALLOC(newBandwidth->in) < 0)
9779
                goto cleanup;
9780 9781 9782 9783 9784 9785 9786

            memcpy(newBandwidth->in,
                   bandwidth->in ? bandwidth->in : net->bandwidth->in,
                   sizeof(*newBandwidth->in));
        }
        if (bandwidth->out ||
            (net->bandwidth && net->bandwidth->out)) {
9787
            if (VIR_ALLOC(newBandwidth->out) < 0)
9788
                goto cleanup;
9789 9790 9791 9792

            memcpy(newBandwidth->out,
                   bandwidth->out ? bandwidth->out : net->bandwidth->out,
                   sizeof(*newBandwidth->out));
9793 9794
        }

9795
        if (virNetDevBandwidthSet(net->ifname, newBandwidth, false) < 0) {
9796 9797 9798
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("cannot set bandwidth limits on %s"),
                           device);
9799 9800 9801 9802 9803
            goto cleanup;
        }

        virNetDevBandwidthFree(net->bandwidth);
        net->bandwidth = newBandwidth;
E
Eric Blake 已提交
9804
        newBandwidth = NULL;
9805 9806 9807 9808 9809 9810 9811 9812 9813 9814 9815 9816 9817 9818 9819 9820 9821 9822
    }
    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;
            }
        }

9823
        if (virDomainSaveConfig(cfg->configDir, persistentDef) < 0)
9824 9825 9826 9827 9828 9829
            goto cleanup;
    }

    ret = 0;
cleanup:
    virNetDevBandwidthFree(bandwidth);
9830
    virNetDevBandwidthFree(newBandwidth);
9831
    if (vm)
9832
        virObjectUnlock(vm);
9833
    virObjectUnref(caps);
9834
    virObjectUnref(cfg);
9835 9836 9837 9838 9839 9840 9841 9842 9843 9844
    return ret;
}

static int
qemuDomainGetInterfaceParameters(virDomainPtr dom,
                                 const char *device,
                                 virTypedParameterPtr params,
                                 int *nparams,
                                 unsigned int flags)
{
9845
    virQEMUDriverPtr driver = dom->conn->privateData;
9846
    size_t i;
9847 9848 9849 9850 9851
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainDefPtr persistentDef = NULL;
    virDomainNetDefPtr net = NULL;
    int ret = -1;
9852
    virCapsPtr caps = NULL;
9853 9854 9855 9856 9857 9858 9859

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG |
                  VIR_TYPED_PARAM_STRING_OKAY, -1);

    flags &= ~VIR_TYPED_PARAM_STRING_OKAY;

9860 9861
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
9862

9863 9864 9865
    if (virDomainGetInterfaceParametersEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

9866 9867 9868
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

9869
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
9870 9871 9872 9873 9874 9875 9876 9877 9878 9879 9880 9881 9882 9883 9884
                                        &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) {
9885 9886
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Can't find device %s"), device);
9887 9888 9889 9890
        goto cleanup;
    }

    for (i = 0; i < *nparams && i < QEMU_NB_BANDWIDTH_PARAM; i++) {
9891
        switch (i) {
9892
        case 0: /* inbound.average */
9893 9894 9895
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9896 9897 9898 9899 9900
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->average;
            break;
        case 1: /* inbound.peak */
9901 9902 9903
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9904 9905 9906 9907 9908
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->peak;
            break;
        case 2: /* inbound.burst */
9909 9910 9911
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_IN_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9912 9913 9914 9915 9916
                goto cleanup;
            if (net->bandwidth && net->bandwidth->in)
                params[i].value.ui = net->bandwidth->in->burst;
            break;
        case 3: /* outbound.average */
9917 9918 9919
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_AVERAGE,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9920 9921 9922 9923 9924
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->average;
            break;
        case 4: /* outbound.peak */
9925 9926 9927
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_PEAK,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9928 9929 9930 9931 9932
                goto cleanup;
            if (net->bandwidth && net->bandwidth->out)
                params[i].value.ui = net->bandwidth->out->peak;
            break;
        case 5: /* outbound.burst */
9933 9934 9935
            if (virTypedParameterAssign(&params[i],
                                        VIR_DOMAIN_BANDWIDTH_OUT_BURST,
                                        VIR_TYPED_PARAM_UINT, 0) < 0)
9936 9937 9938 9939 9940 9941 9942 9943 9944 9945 9946 9947 9948 9949 9950 9951
                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)
9952
        virObjectUnlock(vm);
9953
    virObjectUnref(caps);
9954 9955 9956
    return ret;
}

9957
static int
9958 9959 9960 9961
qemuDomainMemoryStats(virDomainPtr dom,
                      struct _virDomainMemoryStat *stats,
                      unsigned int nr_stats,
                      unsigned int flags)
9962
{
9963
    virQEMUDriverPtr driver = dom->conn->privateData;
9964
    virDomainObjPtr vm;
M
Martin Kletzander 已提交
9965
    int ret = -1;
9966

9967 9968
    virCheckFlags(0, -1);

9969
    if (!(vm = qemuDomObjFromDomain(dom)))
9970 9971
        goto cleanup;

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

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

M
Martin Kletzander 已提交
9978
    if (!virDomainObjIsActive(vm)) {
9979 9980
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
M
Martin Kletzander 已提交
9981
    } else {
9982
        qemuDomainObjPrivatePtr priv = vm->privateData;
9983
        qemuDomainObjEnterMonitor(driver, vm);
9984
        ret = qemuMonitorGetMemoryStats(priv->mon, stats, nr_stats);
9985
        qemuDomainObjExitMonitor(driver, vm);
M
Martin Kletzander 已提交
9986 9987 9988

        if (ret >= 0 && ret < nr_stats) {
            long rss;
9989
            if (qemuGetProcessInfo(NULL, NULL, &rss, vm->pid, 0) < 0) {
9990 9991
                virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                               _("cannot get RSS for domain"));
M
Martin Kletzander 已提交
9992 9993 9994 9995 9996 9997 9998
            } else {
                stats[ret].tag = VIR_DOMAIN_MEMORY_STAT_RSS;
                stats[ret].val = rss;
                ret++;
            }

        }
9999 10000
    }

E
Eric Blake 已提交
10001
    if (!qemuDomainObjEndJob(driver, vm))
10002 10003
        vm = NULL;

10004 10005
cleanup:
    if (vm)
10006
        virObjectUnlock(vm);
10007 10008 10009
    return ret;
}

10010
static int
10011 10012 10013 10014 10015
qemuDomainBlockPeek(virDomainPtr dom,
                    const char *path,
                    unsigned long long offset, size_t size,
                    void *buffer,
                    unsigned int flags)
10016
{
10017
    virQEMUDriverPtr driver = dom->conn->privateData;
10018
    virDomainObjPtr vm;
10019 10020
    int fd = -1, ret = -1;
    const char *actual;
10021

E
Eric Blake 已提交
10022 10023
    virCheckFlags(0, -1);

10024
    if (!(vm = qemuDomObjFromDomain(dom)))
10025
        goto cleanup;
10026

10027 10028 10029
    if (virDomainBlockPeekEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

10030
    if (!path || path[0] == '\0') {
10031 10032
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("NULL or empty path"));
10033
        goto cleanup;
10034 10035
    }

10036 10037
    /* Check the path belongs to this domain.  */
    if (!(actual = virDomainDiskPathByName(vm->def, path))) {
10038 10039
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path '%s'"), path);
10040
        goto cleanup;
10041
    }
10042
    path = actual;
10043

10044 10045
    fd = qemuOpenFile(driver, vm, path, O_RDONLY, NULL, NULL);
    if (fd == -1)
10046
        goto cleanup;
10047

10048 10049 10050 10051 10052 10053 10054 10055 10056
    /* 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;
10057 10058
    }

10059 10060
    ret = 0;

10061
cleanup:
10062
    VIR_FORCE_CLOSE(fd);
10063
    if (vm)
10064
        virObjectUnlock(vm);
10065 10066 10067
    return ret;
}

R
Richard W.M. Jones 已提交
10068
static int
10069 10070 10071 10072
qemuDomainMemoryPeek(virDomainPtr dom,
                     unsigned long long offset, size_t size,
                     void *buffer,
                     unsigned int flags)
R
Richard W.M. Jones 已提交
10073
{
10074
    virQEMUDriverPtr driver = dom->conn->privateData;
10075
    virDomainObjPtr vm;
10076
    char *tmp = NULL;
R
Richard W.M. Jones 已提交
10077
    int fd = -1, ret = -1;
10078
    qemuDomainObjPrivatePtr priv;
10079
    virQEMUDriverConfigPtr cfg = NULL;
R
Richard W.M. Jones 已提交
10080

10081 10082
    virCheckFlags(VIR_MEMORY_VIRTUAL | VIR_MEMORY_PHYSICAL, -1);

10083
    if (!(vm = qemuDomObjFromDomain(dom)))
10084 10085
        goto cleanup;

10086 10087
    cfg = virQEMUDriverGetConfig(driver);

10088 10089 10090
    if (virDomainMemoryPeekEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

10091
    if (flags != VIR_MEMORY_VIRTUAL && flags != VIR_MEMORY_PHYSICAL) {
10092 10093
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("flags parameter must be VIR_MEMORY_VIRTUAL or VIR_MEMORY_PHYSICAL"));
10094
        goto cleanup;
R
Richard W.M. Jones 已提交
10095 10096
    }

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

D
Daniel P. Berrange 已提交
10100
    if (!virDomainObjIsActive(vm)) {
10101 10102
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
10103
        goto endjob;
R
Richard W.M. Jones 已提交
10104 10105
    }

10106
    if (virAsprintf(&tmp, "%s/qemu.mem.XXXXXX", cfg->cacheDir) < 0)
10107
        goto endjob;
10108

R
Richard W.M. Jones 已提交
10109
    /* Create a temporary filename. */
10110
    if ((fd = mkostemp(tmp, O_CLOEXEC)) == -1) {
10111
        virReportSystemError(errno,
10112
                             _("mkostemp(\"%s\") failed"), tmp);
10113
        goto endjob;
R
Richard W.M. Jones 已提交
10114 10115
    }

10116
    virSecurityManagerSetSavedStateLabel(qemu_driver->securityManager, vm->def, tmp);
10117

10118
    priv = vm->privateData;
10119
    qemuDomainObjEnterMonitor(driver, vm);
10120
    if (flags == VIR_MEMORY_VIRTUAL) {
10121
        if (qemuMonitorSaveVirtualMemory(priv->mon, offset, size, tmp) < 0) {
10122
            qemuDomainObjExitMonitor(driver, vm);
10123
            goto endjob;
10124
        }
10125
    } else {
10126
        if (qemuMonitorSavePhysicalMemory(priv->mon, offset, size, tmp) < 0) {
10127
            qemuDomainObjExitMonitor(driver, vm);
10128
            goto endjob;
10129
        }
R
Richard W.M. Jones 已提交
10130
    }
10131
    qemuDomainObjExitMonitor(driver, vm);
R
Richard W.M. Jones 已提交
10132 10133

    /* Read the memory file into buffer. */
10134
    if (saferead(fd, buffer, size) == (ssize_t) -1) {
10135 10136 10137
        virReportSystemError(errno,
                             _("failed to read temporary file "
                               "created with template %s"), tmp);
10138
        goto endjob;
R
Richard W.M. Jones 已提交
10139 10140 10141
    }

    ret = 0;
10142

10143
endjob:
E
Eric Blake 已提交
10144
    if (!qemuDomainObjEndJob(driver, vm))
10145
        vm = NULL;
10146

10147
cleanup:
10148
    VIR_FORCE_CLOSE(fd);
10149 10150
    if (tmp)
        unlink(tmp);
W
Wen Congyang 已提交
10151
    VIR_FREE(tmp);
10152
    if (vm)
10153
        virObjectUnlock(vm);
10154
    virObjectUnref(cfg);
R
Richard W.M. Jones 已提交
10155 10156 10157
    return ret;
}

10158

10159 10160 10161 10162 10163 10164
static int
qemuDomainGetBlockInfo(virDomainPtr dom,
                       const char *path,
                       virDomainBlockInfoPtr info,
                       unsigned int flags)
{
10165
    virQEMUDriverPtr driver = dom->conn->privateData;
10166 10167 10168 10169
    virDomainObjPtr vm;
    int ret = -1;
    int fd = -1;
    off_t end;
10170
    virStorageFileMetadata *meta = NULL;
10171
    virDomainDiskDefPtr disk = NULL;
10172
    struct stat sb;
10173
    int idx;
10174
    int format;
10175
    int activeFail = false;
10176
    virQEMUDriverConfigPtr cfg = NULL;
10177
    char *alias = NULL;
10178 10179 10180

    virCheckFlags(0, -1);

10181
    if (!(vm = qemuDomObjFromDomain(dom)))
10182 10183
        goto cleanup;

10184 10185
    cfg = virQEMUDriverGetConfig(driver);

10186 10187 10188
    if (virDomainGetBlockInfoEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

10189
    if (!path || path[0] == '\0') {
10190 10191
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("NULL or empty path"));
10192 10193 10194 10195
        goto cleanup;
    }

    /* Check the path belongs to this domain. */
10196
    if ((idx = virDomainDiskIndexByName(vm->def, path, false)) < 0) {
10197 10198
        virReportError(VIR_ERR_INVALID_ARG,
                       _("invalid path %s not assigned to domain"), path);
10199 10200
        goto cleanup;
    }
10201
    disk = vm->def->disks[idx];
10202
    if (!disk->src) {
10203 10204 10205
        virReportError(VIR_ERR_INVALID_ARG,
                       _("disk %s does not currently have a source assigned"),
                       path);
10206 10207 10208
        goto cleanup;
    }
    path = disk->src;
10209 10210

    /* The path is correct, now try to open it and get its size. */
10211 10212
    fd = qemuOpenFile(driver, vm, path, O_RDONLY, NULL, NULL);
    if (fd == -1)
10213 10214 10215
        goto cleanup;

    /* Probe for magic formats */
10216 10217
    if (disk->format) {
        format = disk->format;
10218
    } else {
10219 10220 10221 10222
        if (cfg->allowDiskFormatProbing) {
            if ((format = virStorageFileProbeFormat(disk->src,
                                                    cfg->user,
                                                    cfg->group)) < 0)
10223 10224
                goto cleanup;
        } else {
10225 10226 10227
            virReportError(VIR_ERR_INTERNAL_ERROR,
                           _("no disk format for %s and probing is disabled"),
                           disk->src);
10228
            goto cleanup;
10229
        }
10230 10231
    }

10232
    if (!(meta = virStorageFileGetMetadataFromFD(path, fd, format)))
10233 10234 10235 10236 10237 10238 10239 10240 10241 10242
        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)) {
10243
#ifndef WIN32
10244 10245 10246 10247 10248 10249 10250 10251 10252 10253 10254 10255 10256
        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.
         */
10257
        end = lseek(fd, 0, SEEK_END);
10258 10259 10260 10261 10262 10263 10264 10265 10266 10267 10268
        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 */
10269 10270
    if (meta->capacity)
        info->capacity = meta->capacity;
10271

10272
    /* Set default value .. */
10273 10274
    info->allocation = info->physical;

10275 10276 10277
    /* ..but if guest is not using raw disk format and on a block device,
     * then query highest allocated extent from QEMU
     */
10278
    if (disk->type == VIR_DOMAIN_DISK_TYPE_BLOCK &&
10279
        format != VIR_STORAGE_FILE_RAW &&
10280
        S_ISBLK(sb.st_mode)) {
10281
        qemuDomainObjPrivatePtr priv = vm->privateData;
10282

10283 10284 10285 10286 10287 10288 10289 10290 10291
        /* 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;
        }

10292 10293 10294
        if (VIR_STRDUP(alias, disk->info.alias) < 0)
            goto cleanup;

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

10298
        if (virDomainObjIsActive(vm)) {
10299
            qemuDomainObjEnterMonitor(driver, vm);
10300
            ret = qemuMonitorGetBlockExtent(priv->mon,
10301
                                            alias,
10302 10303
                                            &info->allocation);
            qemuDomainObjExitMonitor(driver, vm);
10304
        } else {
10305
            activeFail = true;
10306
            ret = 0;
10307
        }
10308

E
Eric Blake 已提交
10309
        if (!qemuDomainObjEndJob(driver, vm))
10310
            vm = NULL;
10311 10312 10313
    } else {
        ret = 0;
    }
10314 10315

cleanup:
10316
    VIR_FREE(alias);
10317
    virStorageFileFreeMetadata(meta);
10318
    VIR_FORCE_CLOSE(fd);
10319 10320 10321 10322 10323 10324 10325 10326 10327

    /* 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;
    }
10328
    if (vm)
10329
        virObjectUnlock(vm);
10330
    virObjectUnref(cfg);
10331 10332 10333 10334
    return ret;
}


10335
static int
10336 10337 10338 10339
qemuConnectDomainEventRegister(virConnectPtr conn,
                               virConnectDomainEventCallback callback,
                               void *opaque,
                               virFreeCallback freecb)
10340
{
10341
    virQEMUDriverPtr driver = conn->privateData;
10342
    int ret = -1;
10343

10344 10345 10346 10347 10348 10349 10350
    if (virConnectDomainEventRegisterEnsureACL(conn) < 0)
        goto cleanup;

    if (virDomainEventStateRegister(conn,
                                    driver->domainEventState,
                                    callback, opaque, freecb) < 0)
        goto cleanup;
10351

10352 10353 10354
    ret = 0;

cleanup:
10355
    return ret;
10356 10357
}

10358

10359
static int
10360 10361
qemuConnectDomainEventDeregister(virConnectPtr conn,
                                 virConnectDomainEventCallback callback)
10362
{
10363
    virQEMUDriverPtr driver = conn->privateData;
10364
    int ret = -1;
10365

10366 10367 10368 10369 10370 10371 10372 10373 10374
    if (virConnectDomainEventDeregisterEnsureACL(conn) < 0)
        goto cleanup;

    if (virDomainEventStateDeregister(conn,
                                      driver->domainEventState,
                                      callback) < 0)
        goto cleanup;

    ret = 0;
10375

10376
cleanup:
10377
    return ret;
10378 10379
}

10380 10381

static int
10382 10383 10384 10385 10386 10387
qemuConnectDomainEventRegisterAny(virConnectPtr conn,
                                  virDomainPtr dom,
                                  int eventID,
                                  virConnectDomainEventGenericCallback callback,
                                  void *opaque,
                                  virFreeCallback freecb)
10388
{
10389
    virQEMUDriverPtr driver = conn->privateData;
10390 10391 10392 10393
    int ret = -1;

    if (virConnectDomainEventRegisterAnyEnsureACL(conn) < 0)
        goto cleanup;
10394

10395 10396 10397 10398
    if (virDomainEventStateRegisterID(conn,
                                      driver->domainEventState,
                                      dom, eventID,
                                      callback, opaque, freecb, &ret) < 0)
10399
        ret = -1;
10400 10401

cleanup:
10402 10403 10404 10405 10406
    return ret;
}


static int
10407 10408
qemuConnectDomainEventDeregisterAny(virConnectPtr conn,
                                    int callbackID)
10409
{
10410
    virQEMUDriverPtr driver = conn->privateData;
10411
    int ret = -1;
10412

10413 10414
    if (virConnectDomainEventDeregisterAnyEnsureACL(conn) < 0)
        goto cleanup;
10415

10416
    if (virObjectEventStateDeregisterID(conn,
10417 10418 10419 10420 10421 10422 10423
                                        driver->domainEventState,
                                        callbackID) < 0)
        goto cleanup;

    ret = 0;

cleanup:
10424 10425 10426 10427
    return ret;
}


10428 10429 10430
/*******************************************************************
 * Migration Protocol Version 2
 *******************************************************************/
D
Daniel Veillard 已提交
10431

C
Chris Lalancette 已提交
10432 10433 10434 10435 10436 10437
/* 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
10438 10439 10440 10441 10442 10443
qemuDomainMigratePrepareTunnel(virConnectPtr dconn,
                               virStreamPtr st,
                               unsigned long flags,
                               const char *dname,
                               unsigned long resource ATTRIBUTE_UNUSED,
                               const char *dom_xml)
C
Chris Lalancette 已提交
10444
{
10445
    virQEMUDriverPtr driver = dconn->privateData;
10446
    virDomainDefPtr def = NULL;
10447
    char *origname = NULL;
C
Chris Lalancette 已提交
10448
    int ret = -1;
10449

10450
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
10451

C
Chris Lalancette 已提交
10452
    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
10453 10454
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("PrepareTunnel called but no TUNNELLED flag set"));
C
Chris Lalancette 已提交
10455 10456 10457
        goto cleanup;
    }

10458
    if (virLockManagerPluginUsesState(driver->lockManager)) {
10459 10460 10461
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
10462 10463 10464
        goto cleanup;
    }

10465
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
10466 10467
        goto cleanup;

10468 10469 10470
    if (virDomainMigratePrepareTunnelEnsureACL(dconn, def) < 0)
        goto cleanup;

10471 10472
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     NULL, 0, NULL, NULL, /* No cookies in v2 */
10473
                                     st, &def, origname, flags);
10474

C
Chris Lalancette 已提交
10475
cleanup:
10476
    VIR_FREE(origname);
10477
    virDomainDefFree(def);
C
Chris Lalancette 已提交
10478 10479 10480
    return ret;
}

D
Daniel Veillard 已提交
10481 10482 10483 10484
/* Prepare is the first step, and it runs on the destination host.
 *
 * This starts an empty VM listening on a TCP port.
 */
10485
static int ATTRIBUTE_NONNULL(5)
10486 10487 10488 10489 10490 10491 10492 10493 10494
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 已提交
10495
{
10496
    virQEMUDriverPtr driver = dconn->privateData;
10497
    virDomainDefPtr def = NULL;
10498
    char *origname = NULL;
10499
    int ret = -1;
10500

10501
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
10502

C
Chris Lalancette 已提交
10503 10504 10505 10506
    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
10507 10508 10509
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Tunnelled migration requested but invalid "
                         "RPC method called"));
C
Chris Lalancette 已提交
10510 10511 10512
        goto cleanup;
    }

10513
    if (virLockManagerPluginUsesState(driver->lockManager)) {
10514
        virReportError(VIR_ERR_INTERNAL_ERROR,
10515 10516
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
10517
        goto cleanup;
D
Daniel Veillard 已提交
10518 10519
    }

10520
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
10521 10522
        goto cleanup;

10523 10524 10525
    if (virDomainMigratePrepare2EnsureACL(dconn, def) < 0)
        goto cleanup;

10526 10527 10528 10529
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
10530
    ret = qemuMigrationPrepareDirect(driver, dconn,
10531
                                     NULL, 0, NULL, NULL, /* No cookies */
10532
                                     uri_in, uri_out,
10533
                                     &def, origname, NULL, flags);
D
Daniel Veillard 已提交
10534

10535
cleanup:
10536
    VIR_FREE(origname);
10537
    virDomainDefFree(def);
10538 10539
    return ret;
}
C
Chris Lalancette 已提交
10540

D
Daniel Veillard 已提交
10541

10542 10543
/* Perform is the second step, and it runs on the source host. */
static int
10544 10545 10546 10547 10548 10549 10550
qemuDomainMigratePerform(virDomainPtr dom,
                         const char *cookie,
                         int cookielen,
                         const char *uri,
                         unsigned long flags,
                         const char *dname,
                         unsigned long resource)
10551
{
10552
    virQEMUDriverPtr driver = dom->conn->privateData;
10553 10554
    virDomainObjPtr vm;
    int ret = -1;
10555
    const char *dconnuri = NULL;
10556

10557
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
C
Chris Lalancette 已提交
10558

10559
    if (virLockManagerPluginUsesState(driver->lockManager)) {
10560 10561 10562
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("Cannot use migrate v2 protocol with lock manager %s"),
                       virLockManagerPluginGetName(driver->lockManager));
10563 10564 10565
        goto cleanup;
    }

10566
    if (!(vm = qemuDomObjFromDomain(dom)))
10567
        goto cleanup;
D
Daniel Veillard 已提交
10568

10569 10570 10571
    if (virDomainMigratePerformEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

10572 10573 10574 10575 10576
    if (flags & VIR_MIGRATE_PEER2PEER) {
        dconnuri = uri;
        uri = NULL;
    }

10577 10578 10579 10580 10581 10582
    /* 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
     */
10583
    ret = qemuMigrationPerform(driver, dom->conn, vm,
10584 10585
                               NULL, dconnuri, uri, NULL, NULL,
                               cookie, cookielen,
10586
                               NULL, NULL, /* No output cookies in v2 */
10587
                               flags, dname, resource, false);
10588

10589
cleanup:
10590
    return ret;
D
Daniel Veillard 已提交
10591 10592
}

10593

D
Daniel Veillard 已提交
10594 10595
/* Finish is the third and final step, and it runs on the destination host. */
static virDomainPtr
10596 10597 10598 10599 10600 10601 10602
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 已提交
10603
{
10604
    virQEMUDriverPtr driver = dconn->privateData;
10605 10606
    virDomainObjPtr vm;
    virDomainPtr dom = NULL;
D
Daniel Veillard 已提交
10607

10608
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
C
Chris Lalancette 已提交
10609

10610
    vm = virDomainObjListFindByName(driver->domains, dname);
D
Daniel Veillard 已提交
10611
    if (!vm) {
10612 10613
        virReportError(VIR_ERR_NO_DOMAIN,
                       _("no domain with matching name '%s'"), dname);
10614
        goto cleanup;
D
Daniel Veillard 已提交
10615 10616
    }

10617 10618 10619
    if (virDomainMigrateFinish2EnsureACL(dconn, vm->def) < 0)
        goto cleanup;

10620 10621 10622 10623
    /* Do not use cookies in v2 protocol, since the cookie
     * length was not sufficiently large, causing failures
     * migrating between old & new libvirtd
     */
10624
    dom = qemuMigrationFinish(driver, dconn, vm,
10625
                              NULL, 0, NULL, NULL, /* No cookies */
10626
                              flags, retcode, false);
10627

10628 10629
cleanup:
    return dom;
D
Daniel Veillard 已提交
10630 10631
}

10632

10633 10634 10635 10636 10637 10638
/*******************************************************************
 * Migration Protocol Version 3
 *******************************************************************/

static char *
qemuDomainMigrateBegin3(virDomainPtr domain,
10639
                        const char *xmlin,
10640 10641 10642
                        char **cookieout,
                        int *cookieoutlen,
                        unsigned long flags,
10643
                        const char *dname,
10644 10645 10646 10647
                        unsigned long resource ATTRIBUTE_UNUSED)
{
    virDomainObjPtr vm;

10648
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
10649

10650 10651
    if (!(vm = qemuDomObjFromDomain(domain)))
        return NULL;
10652

10653
    if (virDomainMigrateBegin3EnsureACL(domain->conn, vm->def) < 0) {
10654
        virObjectUnlock(vm);
10655
        return NULL;
10656
    }
10657 10658 10659

    return qemuMigrationBegin(domain->conn, vm, xmlin, dname,
                              cookieout, cookieoutlen, flags);
10660 10661
}

10662 10663 10664 10665 10666 10667 10668 10669 10670 10671 10672 10673 10674 10675 10676 10677 10678 10679 10680 10681 10682 10683 10684 10685 10686 10687 10688 10689 10690 10691 10692 10693 10694 10695 10696 10697 10698
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);
}


10699 10700 10701 10702 10703 10704 10705 10706 10707 10708 10709 10710 10711
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)
{
10712
    virQEMUDriverPtr driver = dconn->privateData;
10713
    virDomainDefPtr def = NULL;
10714
    char *origname = NULL;
10715 10716
    int ret = -1;

10717
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
10718 10719 10720 10721 10722

    if (flags & VIR_MIGRATE_TUNNELLED) {
        /* this is a logical error; we never should have gotten here with
         * VIR_MIGRATE_TUNNELLED set
         */
10723 10724 10725
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("Tunnelled migration requested but invalid "
                         "RPC method called"));
10726 10727 10728
        goto cleanup;
    }

10729
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
10730 10731
        goto cleanup;

10732 10733 10734
    if (virDomainMigratePrepare3EnsureACL(dconn, def) < 0)
        goto cleanup;

10735 10736 10737 10738
    ret = qemuMigrationPrepareDirect(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
                                     uri_in, uri_out,
10739
                                     &def, origname, NULL, flags);
10740 10741

cleanup:
10742
    VIR_FREE(origname);
10743
    virDomainDefFree(def);
10744 10745 10746
    return ret;
}

10747 10748 10749 10750 10751 10752 10753 10754 10755 10756 10757 10758
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;
10759
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
10760 10761 10762 10763
    virDomainDefPtr def = NULL;
    const char *dom_xml = NULL;
    const char *dname = NULL;
    const char *uri_in = NULL;
10764
    const char *listenAddress = cfg->migrationAddress;
10765
    char *origname = NULL;
10766 10767
    int ret = -1;

10768
    virCheckFlagsGoto(QEMU_MIGRATION_FLAGS, cleanup);
10769
    if (virTypedParamsValidate(params, nparams, QEMU_MIGRATION_PARAMETERS) < 0)
10770
        goto cleanup;
10771 10772 10773 10774 10775 10776 10777 10778 10779

    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,
10780 10781 10782 10783
                                &uri_in) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_LISTEN_ADDRESS,
                                &listenAddress) < 0)
10784
        goto cleanup;
10785 10786 10787 10788 10789 10790 10791 10792 10793 10794 10795

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

10796
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
10797 10798 10799 10800 10801 10802 10803 10804 10805
        goto cleanup;

    if (virDomainMigratePrepare3ParamsEnsureACL(dconn, def) < 0)
        goto cleanup;

    ret = qemuMigrationPrepareDirect(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
                                     uri_in, uri_out,
10806
                                     &def, origname, listenAddress, flags);
10807 10808

cleanup:
10809
    VIR_FREE(origname);
10810
    virDomainDefFree(def);
10811
    virObjectUnref(cfg);
10812 10813 10814
    return ret;
}

10815 10816 10817 10818 10819 10820 10821 10822 10823 10824 10825 10826 10827

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)
{
10828
    virQEMUDriverPtr driver = dconn->privateData;
10829
    virDomainDefPtr def = NULL;
10830
    char *origname = NULL;
10831 10832
    int ret = -1;

10833
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
10834 10835

    if (!(flags & VIR_MIGRATE_TUNNELLED)) {
10836 10837
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("PrepareTunnel called but no TUNNELLED flag set"));
10838 10839 10840
        goto cleanup;
    }

10841
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
10842 10843
        goto cleanup;

10844 10845 10846
    if (virDomainMigratePrepareTunnel3EnsureACL(dconn, def) < 0)
        goto cleanup;

10847 10848 10849
    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
10850
                                     st, &def, origname, flags);
10851 10852

cleanup:
10853
    VIR_FREE(origname);
10854
    virDomainDefFree(def);
10855 10856 10857
    return ret;
}

10858 10859 10860 10861 10862 10863 10864 10865 10866 10867 10868 10869 10870 10871 10872
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;
10873
    char *origname = NULL;
10874 10875 10876 10877 10878 10879 10880 10881 10882 10883 10884 10885 10886 10887 10888 10889 10890 10891 10892 10893
    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;
    }

10894
    if (!(def = qemuMigrationPrepareDef(driver, dom_xml, dname, &origname)))
10895 10896 10897 10898 10899 10900 10901 10902
        goto cleanup;

    if (virDomainMigratePrepareTunnel3ParamsEnsureACL(dconn, def) < 0)
        goto cleanup;

    ret = qemuMigrationPrepareTunnel(driver, dconn,
                                     cookiein, cookieinlen,
                                     cookieout, cookieoutlen,
10903
                                     st, &def, origname, flags);
10904 10905

cleanup:
10906
    VIR_FREE(origname);
10907 10908 10909 10910
    virDomainDefFree(def);
    return ret;
}

10911 10912 10913

static int
qemuDomainMigratePerform3(virDomainPtr dom,
10914
                          const char *xmlin,
10915 10916 10917 10918
                          const char *cookiein,
                          int cookieinlen,
                          char **cookieout,
                          int *cookieoutlen,
10919
                          const char *dconnuri,
10920 10921 10922 10923 10924
                          const char *uri,
                          unsigned long flags,
                          const char *dname,
                          unsigned long resource)
{
10925
    virQEMUDriverPtr driver = dom->conn->privateData;
10926 10927
    virDomainObjPtr vm;

10928
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
10929

10930 10931
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
10932

10933 10934 10935 10936 10937
    if (virDomainMigratePerform3EnsureACL(dom->conn, vm->def) < 0) {
        virObjectUnlock(vm);
        return -1;
    }

10938
    return qemuMigrationPerform(driver, dom->conn, vm, xmlin,
10939 10940
                                dconnuri, uri, NULL, NULL,
                                cookiein, cookieinlen,
10941 10942
                                cookieout, cookieoutlen,
                                flags, dname, resource, true);
10943 10944
}

10945 10946 10947 10948 10949 10950 10951 10952 10953 10954 10955 10956 10957 10958 10959 10960
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;
10961
    const char *graphicsuri = NULL;
10962
    const char *listenAddress = NULL;
10963 10964 10965 10966 10967 10968 10969 10970 10971 10972 10973 10974 10975 10976 10977 10978 10979
    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,
10980 10981 10982
                                &bandwidth) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_GRAPHICS_URI,
10983 10984 10985 10986
                                &graphicsuri) < 0 ||
        virTypedParamsGetString(params, nparams,
                                VIR_MIGRATE_PARAM_LISTEN_ADDRESS,
                                &listenAddress) < 0)
10987 10988 10989 10990 10991 10992 10993 10994 10995 10996 10997
        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,
10998
                                dconnuri, uri, graphicsuri, listenAddress,
10999
                                cookiein, cookieinlen, cookieout, cookieoutlen,
11000 11001 11002
                                flags, dname, bandwidth, true);
}

11003

11004
static virDomainPtr
11005 11006 11007 11008 11009 11010
qemuDomainMigrateFinish3(virConnectPtr dconn,
                         const char *dname,
                         const char *cookiein,
                         int cookieinlen,
                         char **cookieout,
                         int *cookieoutlen,
11011
                         const char *dconnuri ATTRIBUTE_UNUSED,
11012 11013
                         const char *uri ATTRIBUTE_UNUSED,
                         unsigned long flags,
11014
                         int cancelled)
11015
{
11016
    virQEMUDriverPtr driver = dconn->privateData;
11017 11018
    virDomainObjPtr vm;

11019
    virCheckFlags(QEMU_MIGRATION_FLAGS, NULL);
11020

11021 11022
    if (!dname ||
        !(vm = virDomainObjListFindByName(driver->domains, dname))) {
11023
        virReportError(VIR_ERR_NO_DOMAIN,
11024 11025 11026
                       _("no domain with matching name '%s'"),
                       NULLSTR(dname));
        return NULL;
11027 11028
    }

11029 11030 11031 11032
    if (virDomainMigrateFinish3EnsureACL(dconn, vm->def) < 0) {
        virObjectUnlock(vm);
        return NULL;
    }
11033

11034 11035 11036 11037 11038
    return qemuMigrationFinish(driver, dconn, vm,
                               cookiein, cookieinlen,
                               cookieout, cookieoutlen,
                               flags, cancelled, true);
}
11039

11040 11041 11042 11043 11044 11045 11046 11047 11048 11049 11050 11051 11052 11053 11054 11055 11056 11057 11058 11059 11060 11061 11062 11063 11064 11065 11066 11067 11068 11069 11070 11071 11072 11073 11074 11075 11076 11077 11078 11079 11080
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);
11081 11082
}

11083

11084 11085 11086 11087 11088 11089 11090 11091 11092
static int
qemuDomainMigrateConfirm3(virDomainPtr domain,
                          const char *cookiein,
                          int cookieinlen,
                          unsigned long flags,
                          int cancelled)
{
    virDomainObjPtr vm;

11093
    virCheckFlags(QEMU_MIGRATION_FLAGS, -1);
11094

11095 11096
    if (!(vm = qemuDomObjFromDomain(domain)))
        return -1;
11097

11098 11099 11100
    if (virDomainMigrateConfirm3EnsureACL(domain->conn, vm->def) < 0) {
        virObjectUnlock(vm);
        return -1;
11101 11102
    }

11103 11104
    return qemuMigrationConfirm(domain->conn, vm, cookiein, cookieinlen,
                                flags, cancelled);
11105 11106
}

11107 11108 11109 11110 11111 11112 11113 11114 11115 11116 11117 11118 11119 11120 11121 11122 11123 11124 11125 11126 11127 11128 11129 11130 11131 11132 11133 11134
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);
}

11135

11136
static int
11137
qemuNodeDeviceGetPciInfo(virNodeDeviceDefPtr def,
11138 11139 11140 11141
                         unsigned *domain,
                         unsigned *bus,
                         unsigned *slot,
                         unsigned *function)
11142 11143 11144 11145 11146 11147 11148 11149 11150 11151 11152 11153 11154 11155 11156 11157 11158 11159
{
    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) {
11160
        virReportError(VIR_ERR_INVALID_ARG,
11161
                       _("device %s is not a PCI device"), def->name);
11162 11163 11164 11165 11166 11167 11168 11169 11170
        goto out;
    }

    ret = 0;
out:
    return ret;
}

static int
11171 11172 11173
qemuNodeDeviceDetachFlags(virNodeDevicePtr dev,
                          const char *driverName,
                          unsigned int flags)
11174
{
11175
    virQEMUDriverPtr driver = dev->conn->privateData;
11176
    virPCIDevicePtr pci = NULL;
11177
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
11178
    int ret = -1;
11179 11180
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
11181 11182
    bool legacy = qemuHostdevHostSupportsPassthroughLegacy();
    bool vfio = qemuHostdevHostSupportsPassthroughVFIO();
11183

11184 11185
    virCheckFlags(0, -1);

11186 11187 11188 11189 11190 11191 11192 11193 11194 11195 11196 11197 11198
    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;
11199

11200
    pci = virPCIDeviceNew(domain, bus, slot, function);
11201
    if (!pci)
11202
        goto cleanup;
11203

11204
    if (!driverName) {
11205
        if (vfio) {
11206
            driverName = "vfio";
11207
        } else if (legacy) {
11208
            driverName = "kvm";
11209 11210 11211 11212 11213 11214
        } else {
            virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                           _("neither VFIO nor KVM device assignment is "
                             "currently supported on this system"));
            goto cleanup;
        }
11215 11216
    }

11217 11218 11219 11220 11221 11222 11223
    if (STREQ(driverName, "vfio")) {
        if (!vfio) {
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("VFIO device assignment is currently not "
                             "supported on this system"));
            goto cleanup;
        }
11224 11225
        if (virPCIDeviceSetStubDriver(pci, "vfio-pci") < 0)
            goto cleanup;
11226
    } else if (STREQ(driverName, "kvm")) {
11227 11228 11229 11230 11231 11232
        if (!legacy) {
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("KVM device assignment is currently not "
                             "supported on this system"));
            goto cleanup;
        }
11233 11234
        if (virPCIDeviceSetStubDriver(pci, "pci-stub") < 0)
            goto cleanup;
11235 11236 11237
    } else {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("unknown driver name '%s'"), driverName);
11238
        goto cleanup;
11239 11240
    }

11241 11242
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);
11243

11244
    if (virPCIDeviceDetach(pci, driver->activePciHostdevs,
11245
                           driver->inactivePciHostdevs) < 0) {
11246
        goto out;
11247
    }
11248 11249 11250

    ret = 0;
out:
11251 11252
    virObjectUnlock(driver->inactivePciHostdevs);
    virObjectUnlock(driver->activePciHostdevs);
11253
cleanup:
11254
    virPCIDeviceFree(pci);
11255 11256
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
11257 11258 11259
    return ret;
}

11260 11261 11262 11263 11264 11265
static int
qemuNodeDeviceDettach(virNodeDevicePtr dev)
{
    return qemuNodeDeviceDetachFlags(dev, NULL, 0);
}

11266
static int
11267
qemuNodeDeviceReAttach(virNodeDevicePtr dev)
11268
{
11269
    virQEMUDriverPtr driver = dev->conn->privateData;
11270
    virPCIDevicePtr pci = NULL;
11271
    virPCIDevicePtr other;
11272
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
11273
    int ret = -1;
11274 11275
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
11276

11277 11278 11279 11280 11281 11282 11283 11284 11285 11286 11287 11288 11289
    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;
11290

11291
    pci = virPCIDeviceNew(domain, bus, slot, function);
11292
    if (!pci)
11293
        goto cleanup;
11294

11295 11296
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);
11297
    other = virPCIDeviceListFind(driver->activePciHostdevs, pci);
11298
    if (other) {
11299
        const char *other_name = virPCIDeviceGetUsedBy(other);
11300 11301

        if (other_name)
11302 11303
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is still in use by domain %s"),
11304
                           virPCIDeviceGetName(pci), other_name);
11305
        else
11306 11307
            virReportError(VIR_ERR_OPERATION_INVALID,
                           _("PCI device %s is still in use"),
11308
                           virPCIDeviceGetName(pci));
11309
        goto out;
11310 11311
    }

11312
    virPCIDeviceReattachInit(pci);
11313

11314
    if (virPCIDeviceReattach(pci, driver->activePciHostdevs,
11315
                             driver->inactivePciHostdevs) < 0)
11316 11317 11318 11319
        goto out;

    ret = 0;
out:
11320 11321
    virObjectUnlock(driver->inactivePciHostdevs);
    virObjectUnlock(driver->activePciHostdevs);
11322
    virPCIDeviceFree(pci);
11323 11324 11325
cleanup:
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
11326 11327 11328 11329
    return ret;
}

static int
11330
qemuNodeDeviceReset(virNodeDevicePtr dev)
11331
{
11332
    virQEMUDriverPtr driver = dev->conn->privateData;
11333
    virPCIDevicePtr pci;
11334
    unsigned domain = 0, bus = 0, slot = 0, function = 0;
11335
    int ret = -1;
11336 11337
    virNodeDeviceDefPtr def = NULL;
    char *xml = NULL;
11338

11339 11340 11341 11342 11343 11344 11345 11346 11347 11348 11349 11350 11351
    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;
11352

11353
    pci = virPCIDeviceNew(domain, bus, slot, function);
11354
    if (!pci)
11355
        goto cleanup;
11356

11357 11358
    virObjectLock(driver->activePciHostdevs);
    virObjectLock(driver->inactivePciHostdevs);
11359

11360 11361
    if (virPCIDeviceReset(pci, driver->activePciHostdevs,
                          driver->inactivePciHostdevs) < 0)
11362 11363 11364 11365
        goto out;

    ret = 0;
out:
11366 11367
    virObjectUnlock(driver->inactivePciHostdevs);
    virObjectUnlock(driver->activePciHostdevs);
11368
    virPCIDeviceFree(pci);
11369 11370 11371
cleanup:
    virNodeDeviceDefFree(def);
    VIR_FREE(xml);
11372 11373 11374
    return ret;
}

11375
static int
11376 11377 11378
qemuConnectCompareCPU(virConnectPtr conn,
                      const char *xmlDesc,
                      unsigned int flags)
11379
{
11380
    virQEMUDriverPtr driver = conn->privateData;
11381
    int ret = VIR_CPU_COMPARE_ERROR;
11382
    virCapsPtr caps = NULL;
11383

E
Eric Blake 已提交
11384 11385
    virCheckFlags(0, VIR_CPU_COMPARE_ERROR);

11386 11387 11388
    if (virConnectCompareCPUEnsureACL(conn) < 0)
        goto cleanup;

11389 11390 11391 11392 11393
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

    if (!caps->host.cpu ||
        !caps->host.cpu->model) {
11394 11395
        VIR_WARN("cannot get host CPU capabilities");
        ret = VIR_CPU_COMPARE_INCOMPATIBLE;
E
Eric Blake 已提交
11396
    } else {
11397
        ret = cpuCompareXML(caps->host.cpu, xmlDesc);
E
Eric Blake 已提交
11398
    }
11399

11400 11401
cleanup:
    virObjectUnref(caps);
11402 11403 11404
    return ret;
}

11405

11406
static char *
11407 11408 11409 11410
qemuConnectBaselineCPU(virConnectPtr conn ATTRIBUTE_UNUSED,
                       const char **xmlCPUs,
                       unsigned int ncpus,
                       unsigned int flags)
11411
{
11412
    char *cpu = NULL;
11413

11414
    virCheckFlags(VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES, NULL);
E
Eric Blake 已提交
11415

11416 11417 11418
    if (virConnectBaselineCPUEnsureACL(conn) < 0)
        goto cleanup;

11419
    cpu = cpuBaselineXML(xmlCPUs, ncpus, NULL, 0, flags);
11420

11421
cleanup:
11422 11423 11424
    return cpu;
}

11425 11426 11427 11428 11429 11430 11431

static int qemuDomainGetJobInfo(virDomainPtr dom,
                                virDomainJobInfoPtr info) {
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

11432
    if (!(vm = qemuDomObjFromDomain(dom)))
11433 11434 11435 11436
        goto cleanup;

    priv = vm->privateData;

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

11440
    if (virDomainObjIsActive(vm)) {
11441
        if (priv->job.asyncJob && !priv->job.dump_memory_only) {
11442
            memcpy(info, &priv->job.info, sizeof(*info));
11443 11444 11445 11446 11447 11448

            /* 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
             */
11449
            if (virTimeMillisNow(&info->timeElapsed) < 0)
11450
                goto cleanup;
11451
            info->timeElapsed -= priv->job.start;
11452 11453 11454 11455 11456
        } else {
            memset(info, 0, sizeof(*info));
            info->type = VIR_DOMAIN_JOB_NONE;
        }
    } else {
11457 11458
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
11459 11460 11461 11462 11463 11464 11465
        goto cleanup;
    }

    ret = 0;

cleanup:
    if (vm)
11466
        virObjectUnlock(vm);
11467 11468 11469 11470
    return ret;
}


11471 11472 11473 11474 11475 11476 11477 11478 11479 11480 11481 11482 11483 11484 11485 11486 11487 11488 11489 11490 11491
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;

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

11495 11496 11497 11498 11499 11500 11501 11502 11503 11504 11505 11506 11507 11508 11509 11510 11511 11512 11513 11514 11515 11516 11517 11518 11519 11520 11521 11522 11523 11524 11525 11526 11527 11528 11529 11530 11531 11532 11533 11534 11535 11536 11537 11538 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
    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;
}


11614
static int qemuDomainAbortJob(virDomainPtr dom) {
11615
    virQEMUDriverPtr driver = dom->conn->privateData;
11616 11617 11618 11619
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

11620
    if (!(vm = qemuDomObjFromDomain(dom)))
11621 11622
        goto cleanup;

11623 11624 11625
    if (virDomainAbortJobEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

11626 11627
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_ABORT) < 0)
        goto cleanup;
11628

11629
    if (!virDomainObjIsActive(vm)) {
11630 11631
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
11632
        goto endjob;
11633 11634
    }

11635 11636
    priv = vm->privateData;

11637
    if (!priv->job.asyncJob || priv->job.dump_memory_only) {
11638 11639
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("no job is active on the domain"));
11640 11641
        goto endjob;
    } else if (priv->job.asyncJob == QEMU_ASYNC_JOB_MIGRATION_IN) {
11642 11643 11644
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot abort incoming migration;"
                         " use virDomainDestroy instead"));
11645 11646 11647 11648
        goto endjob;
    }

    VIR_DEBUG("Cancelling job at client request");
11649
    qemuDomainObjAbortAsyncJob(vm);
11650
    qemuDomainObjEnterMonitor(driver, vm);
11651 11652 11653 11654
    ret = qemuMonitorMigrateCancel(priv->mon);
    qemuDomainObjExitMonitor(driver, vm);

endjob:
E
Eric Blake 已提交
11655
    if (!qemuDomainObjEndJob(driver, vm))
11656
        vm = NULL;
11657 11658 11659

cleanup:
    if (vm)
11660
        virObjectUnlock(vm);
11661 11662 11663 11664
    return ret;
}


11665 11666 11667 11668 11669
static int
qemuDomainMigrateSetMaxDowntime(virDomainPtr dom,
                                unsigned long long downtime,
                                unsigned int flags)
{
11670
    virQEMUDriverPtr driver = dom->conn->privateData;
11671 11672 11673 11674
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

11675
    virCheckFlags(0, -1);
11676

11677 11678
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
11679

11680 11681 11682
    if (virDomainMigrateSetMaxDowntimeEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

11683 11684 11685
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
        goto cleanup;

11686
    if (!virDomainObjIsActive(vm)) {
11687 11688
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
11689
        goto endjob;
11690 11691 11692 11693
    }

    priv = vm->privateData;

11694
    if (priv->job.asyncJob != QEMU_ASYNC_JOB_MIGRATION_OUT) {
11695 11696
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not being migrated"));
11697
        goto endjob;
11698 11699
    }

11700
    VIR_DEBUG("Setting migration downtime to %llums", downtime);
11701
    qemuDomainObjEnterMonitor(driver, vm);
11702 11703 11704 11705
    ret = qemuMonitorSetMigrationDowntime(priv->mon, downtime);
    qemuDomainObjExitMonitor(driver, vm);

endjob:
E
Eric Blake 已提交
11706
    if (!qemuDomainObjEndJob(driver, vm))
11707
        vm = NULL;
11708 11709 11710

cleanup:
    if (vm)
11711
        virObjectUnlock(vm);
11712 11713 11714
    return ret;
}

11715 11716 11717 11718 11719 11720 11721 11722 11723 11724 11725 11726 11727 11728 11729
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;

11730 11731 11732
    if (virDomainMigrateGetCompressionCacheEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

11733 11734 11735 11736 11737 11738 11739 11740 11741 11742 11743 11744 11745 11746 11747 11748 11749 11750 11751 11752 11753 11754 11755 11756 11757 11758 11759 11760
    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 已提交
11761
    if (!qemuDomainObjEndJob(driver, vm))
11762 11763 11764 11765 11766 11767 11768 11769 11770 11771 11772 11773 11774 11775 11776 11777 11778 11779 11780 11781 11782 11783 11784
        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;

11785 11786 11787
    if (virDomainMigrateSetCompressionCacheEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

11788 11789 11790 11791 11792 11793 11794 11795 11796 11797 11798 11799 11800 11801 11802 11803 11804 11805 11806 11807 11808 11809 11810 11811 11812 11813 11814 11815 11816
    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 已提交
11817
    if (!qemuDomainObjEndJob(driver, vm))
11818 11819 11820 11821 11822 11823 11824 11825
        vm = NULL;

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

11826 11827 11828 11829 11830
static int
qemuDomainMigrateSetMaxSpeed(virDomainPtr dom,
                             unsigned long bandwidth,
                             unsigned int flags)
{
11831
    virQEMUDriverPtr driver = dom->conn->privateData;
11832 11833 11834 11835 11836 11837
    virDomainObjPtr vm;
    qemuDomainObjPrivatePtr priv;
    int ret = -1;

    virCheckFlags(0, -1);

11838 11839
    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
11840 11841

    priv = vm->privateData;
11842 11843 11844 11845

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

11846 11847 11848
    if (virDomainObjIsActive(vm)) {
        if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MIGRATION_OP) < 0)
            goto cleanup;
11849

11850
        if (!virDomainObjIsActive(vm)) {
11851 11852
            virReportError(VIR_ERR_OPERATION_INVALID,
                           "%s", _("domain is not running"));
11853 11854 11855
            goto endjob;
        }

11856 11857 11858 11859
        VIR_DEBUG("Setting migration bandwidth to %luMbs", bandwidth);
        qemuDomainObjEnterMonitor(driver, vm);
        ret = qemuMonitorSetMigrationSpeed(priv->mon, bandwidth);
        qemuDomainObjExitMonitor(driver, vm);
11860

11861 11862
        if (ret == 0)
            priv->migMaxBandwidth = bandwidth;
11863

11864
endjob:
E
Eric Blake 已提交
11865
        if (!qemuDomainObjEndJob(driver, vm))
11866 11867 11868 11869 11870
            vm = NULL;
    } else {
        priv->migMaxBandwidth = bandwidth;
        ret = 0;
    }
11871 11872 11873

cleanup:
    if (vm)
11874
        virObjectUnlock(vm);
11875 11876 11877
    return ret;
}

11878 11879 11880 11881 11882 11883
static int
qemuDomainMigrateGetMaxSpeed(virDomainPtr dom,
                             unsigned long *bandwidth,
                             unsigned int flags)
{
    virDomainObjPtr vm;
J
Jim Fehlig 已提交
11884
    qemuDomainObjPrivatePtr priv;
11885 11886 11887 11888
    int ret = -1;

    virCheckFlags(0, -1);

11889
    if (!(vm = qemuDomObjFromDomain(dom)))
11890 11891
        goto cleanup;

J
Jim Fehlig 已提交
11892
    priv = vm->privateData;
11893 11894 11895 11896

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

J
Jim Fehlig 已提交
11897
    *bandwidth = priv->migMaxBandwidth;
11898 11899 11900 11901
    ret = 0;

cleanup:
    if (vm)
11902
        virObjectUnlock(vm);
11903 11904 11905
    return ret;
}

11906 11907 11908 11909 11910 11911 11912 11913 11914 11915 11916 11917
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
11918
qemuDomainPrepareDiskChainElement(virQEMUDriverPtr driver,
11919 11920
                                  virDomainObjPtr vm,
                                  virDomainDiskDefPtr disk,
11921
                                  const char *file,
11922 11923 11924 11925 11926 11927 11928 11929 11930 11931
                                  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;
11932
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
11933

11934
    disk->src = (char *) file; /* casting away const is safe here */
11935 11936 11937 11938 11939 11940 11941 11942
    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);
11943
        if (qemuTeardownDiskCgroup(vm, disk) < 0)
11944 11945 11946
            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);
11947
    } else if (virDomainLockDiskAttach(driver->lockManager, cfg->uri,
11948
                                       vm, disk) < 0 ||
11949
               qemuSetupDiskCgroup(vm, disk) < 0 ||
11950 11951 11952 11953 11954 11955 11956 11957 11958 11959 11960 11961
               virSecurityManagerSetImageLabel(driver->securityManager,
                                               vm->def, disk) < 0) {
        goto cleanup;
    }

    ret = 0;

cleanup:
    disk->src = origsrc;
    disk->format = origformat;
    disk->backingChain = origchain;
    disk->readonly = origreadonly;
11962
    virObjectUnref(cfg);
11963 11964 11965 11966
    return ret;
}


11967
static int
11968
qemuDomainSnapshotFSFreeze(virDomainObjPtr vm) {
11969 11970 11971 11972
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int freezed;

    if (priv->agentError) {
11973
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
11974 11975
                       _("QEMU guest agent is not "
                         "available due to an error"));
11976 11977 11978
        return -1;
    }
    if (!priv->agent) {
11979 11980
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("QEMU guest agent is not configured"));
11981 11982 11983
        return -1;
    }

11984
    qemuDomainObjEnterAgent(vm);
11985
    freezed = qemuAgentFSFreeze(priv->agent);
11986
    qemuDomainObjExitAgent(vm);
11987 11988 11989 11990 11991

    return freezed;
}

static int
11992
qemuDomainSnapshotFSThaw(virDomainObjPtr vm, bool report)
E
Eric Blake 已提交
11993
{
11994 11995
    qemuDomainObjPrivatePtr priv = vm->privateData;
    int thawed;
E
Eric Blake 已提交
11996
    virErrorPtr err = NULL;
11997 11998

    if (priv->agentError) {
E
Eric Blake 已提交
11999
        if (report)
12000
            virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
12001 12002
                           _("QEMU guest agent is not "
                             "available due to an error"));
12003 12004 12005
        return -1;
    }
    if (!priv->agent) {
E
Eric Blake 已提交
12006
        if (report)
12007 12008
            virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                           _("QEMU guest agent is not configured"));
12009 12010 12011
        return -1;
    }

12012
    qemuDomainObjEnterAgent(vm);
E
Eric Blake 已提交
12013
    if (!report)
12014
        err = virSaveLastError();
12015
    thawed = qemuAgentFSThaw(priv->agent);
12016 12017
    if (!report)
        virSetError(err);
12018
    qemuDomainObjExitAgent(vm);
12019

12020
    virFreeError(err);
12021 12022 12023
    return thawed;
}

12024 12025
/* The domain is expected to be locked and inactive. */
static int
12026
qemuDomainSnapshotCreateInactiveInternal(virQEMUDriverPtr driver,
12027 12028
                                         virDomainObjPtr vm,
                                         virDomainSnapshotObjPtr snap)
12029
{
E
Eric Blake 已提交
12030
    return qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-c", false);
12031 12032
}

12033 12034
/* The domain is expected to be locked and inactive. */
static int
12035
qemuDomainSnapshotCreateInactiveExternal(virQEMUDriverPtr driver,
12036 12037 12038 12039
                                         virDomainObjPtr vm,
                                         virDomainSnapshotObjPtr snap,
                                         bool reuse)
{
12040
    size_t i;
12041 12042 12043 12044
    virDomainSnapshotDiskDefPtr snapdisk;
    virDomainDiskDefPtr defdisk;
    virCommandPtr cmd = NULL;
    const char *qemuImgPath;
12045 12046
    virBitmapPtr created = NULL;
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
12047 12048 12049
    int ret = -1;

    if (!(qemuImgPath = qemuFindQemuImgBinary(driver)))
12050
        goto cleanup;
12051

12052
    if (!(created = virBitmapNew(snap->def->ndisks)))
12053
        goto cleanup;
12054 12055 12056 12057 12058 12059 12060 12061 12062 12063 12064 12065 12066 12067 12068 12069 12070 12071 12072 12073 12074 12075 12076 12077 12078 12079 12080 12081

    /* 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 {
12082
            if (!cfg->allowDiskFormatProbing) {
12083 12084 12085 12086 12087 12088 12089 12090 12091 12092 12093 12094 12095 12096 12097 12098 12099 12100 12101 12102 12103 12104 12105 12106 12107 12108 12109 12110 12111 12112 12113 12114
                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);
12115
            if (VIR_STRDUP(defdisk->src, snapdisk->file) < 0) {
12116 12117 12118 12119 12120 12121 12122 12123 12124 12125 12126 12127 12128
                /* 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 */
12129
    if (ret < 0 && created) {
12130 12131 12132 12133 12134 12135 12136 12137 12138
        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);
12139
    virObjectUnref(cfg);
12140 12141 12142 12143

    return ret;
}

12144

12145 12146
/* The domain is expected to be locked and active. */
static int
12147
qemuDomainSnapshotCreateActiveInternal(virConnectPtr conn,
12148
                                       virQEMUDriverPtr driver,
12149 12150 12151
                                       virDomainObjPtr *vmptr,
                                       virDomainSnapshotObjPtr snap,
                                       unsigned int flags)
12152 12153 12154
{
    virDomainObjPtr vm = *vmptr;
    qemuDomainObjPrivatePtr priv = vm->privateData;
12155
    virObjectEventPtr event = NULL;
12156 12157
    bool resume = false;
    int ret = -1;
12158

12159
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
12160 12161
        return -1;

12162
    if (!virDomainObjIsActive(vm)) {
12163 12164
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
12165 12166 12167
        goto endjob;
    }

J
Jiri Denemark 已提交
12168
    if (virDomainObjGetState(vm, NULL) == VIR_DOMAIN_RUNNING) {
12169 12170 12171 12172
        /* 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.
         */
12173 12174
        if (qemuProcessStopCPUs(driver, vm, VIR_DOMAIN_PAUSED_SAVE,
                                QEMU_ASYNC_JOB_NONE) < 0)
12175 12176 12177 12178
            goto cleanup;

        resume = true;
        if (!virDomainObjIsActive(vm)) {
12179 12180
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("guest unexpectedly quit"));
12181 12182 12183 12184
            goto cleanup;
        }
    }

12185
    qemuDomainObjEnterMonitor(driver, vm);
12186
    ret = qemuMonitorCreateSnapshot(priv->mon, snap->def->name);
12187
    qemuDomainObjExitMonitor(driver, vm);
12188 12189 12190 12191
    if (ret < 0)
        goto cleanup;

    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
12192
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
12193
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
12194
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
12195 12196 12197 12198 12199 12200 12201
        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;
    }
12202

12203 12204
cleanup:
    if (resume && virDomainObjIsActive(vm) &&
J
Jiri Denemark 已提交
12205
        qemuProcessStartCPUs(driver, vm, conn,
12206
                             VIR_DOMAIN_RUNNING_UNPAUSED,
12207
                             QEMU_ASYNC_JOB_NONE) < 0) {
12208
        event = virDomainEventLifecycleNewFromObj(vm,
12209 12210 12211 12212 12213 12214
                                         VIR_DOMAIN_EVENT_SUSPENDED,
                                         VIR_DOMAIN_EVENT_SUSPENDED_API_ERROR);
        if (virGetLastError() == NULL) {
            virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                           _("resuming after snapshot failed"));
        }
12215 12216
    }

12217
endjob:
E
Eric Blake 已提交
12218
    if (vm && !qemuDomainObjEndJob(driver, vm)) {
12219 12220
        /* Only possible if a transient vm quit while our locks were down,
         * in which case we don't want to save snapshot metadata.  */
12221
        *vmptr = NULL;
12222 12223
        ret = -1;
    }
12224

12225 12226 12227
    if (event)
        qemuDomainEventQueue(driver, event);

12228 12229 12230
    return ret;
}

12231
static int
12232
qemuDomainSnapshotPrepareDiskExternalBackingInactive(virDomainDiskDefPtr disk)
12233 12234 12235 12236 12237 12238 12239 12240 12241 12242 12243 12244 12245 12246 12247 12248 12249 12250 12251 12252 12253 12254 12255 12256 12257 12258 12259 12260 12261 12262 12263 12264 12265 12266 12267 12268 12269 12270 12271 12272 12273 12274
{
    int actualType = qemuDiskGetActualType(disk);

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


12275 12276 12277 12278 12279 12280 12281 12282 12283 12284 12285 12286 12287 12288 12289 12290 12291
static int
qemuDomainSnapshotPrepareDiskExternalBackingActive(virDomainDiskDefPtr disk)
{
    int actualType = qemuDiskGetActualType(disk);

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


12292 12293 12294 12295 12296 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 12337 12338 12339 12340 12341 12342 12343 12344 12345 12346 12347 12348 12349 12350 12351 12352 12353 12354 12355 12356 12357
static int
qemuDomainSnapshotPrepareDiskExternalOverlayActive(virDomainSnapshotDiskDefPtr disk)
{
    int actualType = qemuSnapshotDiskGetActualType(disk);

    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 active snapshots are not supported on "
                         "'%s' disks"), virDomainDiskTypeToString(actualType));
        return -1;
    }

    return 0;
}


static int
qemuDomainSnapshotPrepareDiskExternalOverlayInactive(virDomainSnapshotDiskDefPtr disk)
{
    int actualType = qemuSnapshotDiskGetActualType(disk);

    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)
{
    int actualType;
    struct stat st;

    if (qemuTranslateSnapshotDiskSourcePool(conn, snapdisk) < 0)
        return -1;

    if (!active) {
        if (qemuTranslateDiskSourcePool(conn, disk) < 0)
            return -1;

12358
        if (qemuDomainSnapshotPrepareDiskExternalBackingInactive(disk) < 0)
12359 12360 12361 12362 12363
            return -1;

        if (qemuDomainSnapshotPrepareDiskExternalOverlayInactive(snapdisk) < 0)
            return -1;
    } else {
12364 12365 12366
        if (qemuDomainSnapshotPrepareDiskExternalBackingActive(disk) < 0)
            return -1;

12367 12368 12369 12370 12371 12372 12373 12374 12375 12376 12377 12378 12379 12380 12381 12382 12383 12384 12385 12386 12387 12388 12389 12390 12391 12392 12393 12394 12395 12396 12397 12398 12399 12400 12401 12402 12403 12404 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 12432 12433 12434 12435 12436 12437 12438 12439 12440 12441 12442 12443 12444 12445 12446 12447 12448 12449 12450 12451 12452 12453 12454 12455 12456 12457 12458 12459 12460 12461 12462 12463 12464 12465 12466
        if (qemuDomainSnapshotPrepareDiskExternalOverlayActive(snapdisk) < 0)
            return -1;
    }

    actualType = qemuSnapshotDiskGetActualType(snapdisk);

    switch ((enum virDomainDiskType) actualType) {
    case VIR_DOMAIN_DISK_TYPE_BLOCK:
    case VIR_DOMAIN_DISK_TYPE_FILE:
        if (stat(snapdisk->file, &st) < 0) {
            if (errno != ENOENT) {
                virReportSystemError(errno,
                                     _("unable to stat for disk %s: %s"),
                                     snapdisk->name, snapdisk->file);
                return -1;
            } else if (reuse) {
                virReportSystemError(errno,
                                     _("missing existing file for disk %s: %s"),
                                     snapdisk->name, snapdisk->file);
                return -1;
            }
        } 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);
            return -1;
        }
        break;

    case VIR_DOMAIN_DISK_TYPE_NETWORK:
    case VIR_DOMAIN_DISK_TYPE_DIR:
    case VIR_DOMAIN_DISK_TYPE_VOLUME:
    case VIR_DOMAIN_DISK_TYPE_LAST:
        break;
    }

    return 0;
}


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;

    actualType = qemuDiskGetActualType(disk);

    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 已提交
12467
                          unsigned int *flags)
12468 12469
{
    int ret = -1;
12470
    size_t i;
12471
    bool active = virDomainObjIsActive(vm);
12472
    bool reuse = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
12473
    bool atomic = (*flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC) != 0;
12474
    bool found_internal = false;
12475 12476
    int external = 0;
    qemuDomainObjPrivatePtr priv = vm->privateData;
12477

E
Eric Blake 已提交
12478
    if (def->state == VIR_DOMAIN_DISK_SNAPSHOT &&
12479
        reuse && !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
12480 12481
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("reuse is not supported with this QEMU binary"));
12482 12483 12484
        goto cleanup;
    }

12485 12486
    for (i = 0; i < def->ndisks; i++) {
        virDomainSnapshotDiskDefPtr disk = &def->disks[i];
E
Eric Blake 已提交
12487
        virDomainDiskDefPtr dom_disk = vm->def->disks[i];
12488 12489

        switch (disk->snapshot) {
E
Eric Blake 已提交
12490
        case VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL:
12491 12492
            found_internal = true;

12493 12494 12495 12496 12497 12498 12499 12500 12501 12502 12503 12504 12505
            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 已提交
12506 12507 12508
                (dom_disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_SHEEPDOG ||
                 dom_disk->protocol == VIR_DOMAIN_DISK_PROTOCOL_RBD)) {
                break;
12509
            }
12510 12511
            if (vm->def->disks[i]->format > 0 &&
                vm->def->disks[i]->format != VIR_STORAGE_FILE_QCOW2) {
12512 12513 12514 12515
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("internal snapshot for disk %s unsupported "
                                 "for storage type %s"),
                               disk->name,
12516 12517
                               virStorageFileFormatTypeToString(
                                   vm->def->disks[i]->format));
12518 12519 12520 12521
                goto cleanup;
            }
            break;

E
Eric Blake 已提交
12522
        case VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL:
12523 12524 12525 12526
            if (!disk->format) {
                disk->format = VIR_STORAGE_FILE_QCOW2;
            } else if (disk->format != VIR_STORAGE_FILE_QCOW2 &&
                       disk->format != VIR_STORAGE_FILE_QED) {
12527 12528 12529
                virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                               _("external snapshot format for disk %s "
                                 "is unsupported: %s"),
12530 12531
                               disk->name,
                               virStorageFileFormatTypeToString(disk->format));
12532 12533
                goto cleanup;
            }
12534 12535 12536

            if (qemuDomainSnapshotPrepareDiskExternal(conn, dom_disk, disk,
                                                      active, reuse) < 0)
12537
                goto cleanup;
12538

12539
            external++;
12540 12541
            break;

E
Eric Blake 已提交
12542
        case VIR_DOMAIN_SNAPSHOT_LOCATION_NONE:
12543 12544
            break;

E
Eric Blake 已提交
12545
        case VIR_DOMAIN_SNAPSHOT_LOCATION_DEFAULT:
12546
        default:
12547 12548
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("unexpected code path"));
12549 12550 12551 12552
            goto cleanup;
        }
    }

12553 12554 12555
    /* internal snapshot requires a disk image to store the memory image to */
    if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL &&
        !found_internal) {
12556
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
12557
                       _("internal checkpoints require at least "
12558
                         "one disk to be selected for snapshot"));
12559 12560
        goto cleanup;
    }
12561

12562 12563 12564 12565 12566 12567 12568 12569 12570 12571 12572 12573 12574
    /* 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",
12575 12576
                       _("mixing internal and external targets for a snapshot "
                         "is not yet supported"));
12577 12578 12579 12580 12581 12582 12583
        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 已提交
12584
    if (def->state != VIR_DOMAIN_DISK_SNAPSHOT && active) {
12585
        if (external == 1 ||
12586
            virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
12587 12588
            *flags |= VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC;
        } else if (atomic && external > 1) {
12589 12590 12591
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                           _("atomic live snapshot of multiple disks "
                             "is unsupported"));
12592 12593 12594
            goto cleanup;
        }
    }
12595 12596 12597 12598 12599 12600 12601 12602 12603

    ret = 0;

cleanup:
    return ret;
}

/* The domain is expected to hold monitor lock.  */
static int
12604
qemuDomainSnapshotCreateSingleDiskActive(virQEMUDriverPtr driver,
12605
                                         virDomainObjPtr vm,
12606
                                         virDomainSnapshotDiskDefPtr snap,
12607
                                         virDomainDiskDefPtr disk,
12608
                                         virDomainDiskDefPtr persistDisk,
12609
                                         virJSONValuePtr actions,
12610 12611
                                         bool reuse,
                                         enum qemuDomainAsyncJob asyncJob)
12612 12613 12614 12615
{
    qemuDomainObjPrivatePtr priv = vm->privateData;
    char *device = NULL;
    char *source = NULL;
12616 12617
    int format = snap->format;
    const char *formatStr = NULL;
12618
    char *persistSource = NULL;
12619
    int ret = -1;
12620 12621
    int fd = -1;
    bool need_unlink = false;
12622

E
Eric Blake 已提交
12623
    if (snap->snapshot != VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
12624 12625
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("unexpected code path"));
12626 12627 12628 12629
        return -1;
    }

    if (virAsprintf(&device, "drive-%s", disk->info.alias) < 0 ||
12630
        (persistDisk && VIR_STRDUP(persistSource, source) < 0))
12631 12632
        goto cleanup;

12633
    /* XXX Here, we know we are about to alter disk->backingChain if
12634 12635 12636 12637
     * 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.  */
12638 12639
    virStorageFileFreeMetadata(disk->backingChain);
    disk->backingChain = NULL;
12640

12641 12642 12643 12644 12645 12646 12647 12648 12649 12650 12651 12652 12653 12654 12655 12656 12657 12658 12659 12660 12661 12662 12663 12664 12665 12666 12667 12668 12669 12670
    switch (snap->type) {
    case VIR_DOMAIN_DISK_TYPE_BLOCK:
        reuse = true;
        /* fallthrough */
    case VIR_DOMAIN_DISK_TYPE_FILE:
        if (VIR_STRDUP(source, snap->file) < 0)
            goto cleanup;

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

    default:
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED,
                       _("snapshots are not supported on '%s' volumes"),
                       virDomainDiskTypeToString(snap->type));
12671 12672 12673 12674
        goto cleanup;
    }

    /* create the actual snapshot */
12675 12676
    if (snap->format)
        formatStr = virStorageFileFormatTypeToString(snap->format);
12677 12678 12679 12680 12681 12682 12683 12684

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

12685
    ret = qemuMonitorDiskSnapshot(priv->mon, actions, device, source,
12686
                                  formatStr, reuse);
12687 12688 12689 12690 12691 12692 12693 12694 12695
    if (!actions) {
        qemuDomainObjExitMonitor(driver, vm);
        if (!virDomainObjIsActive(vm)) {
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                           _("domain crashed while taking the snapshot"));
            ret = -1;
        }
    }

12696 12697 12698 12699 12700
    virDomainAuditDisk(vm, disk->src, source, "snapshot", ret >= 0);
    if (ret < 0)
        goto cleanup;

    /* Update vm in place to match changes.  */
12701
    need_unlink = false;
12702 12703 12704
    VIR_FREE(disk->src);
    disk->src = source;
    source = NULL;
12705
    disk->format = format;
12706
    disk->type = snap->type;
12707 12708 12709 12710
    if (persistDisk) {
        VIR_FREE(persistDisk->src);
        persistDisk->src = persistSource;
        persistSource = NULL;
12711
        persistDisk->format = format;
12712
        persistDisk->type = snap->type;
12713
    }
12714 12715

cleanup:
12716 12717
    if (need_unlink && unlink(source))
        VIR_WARN("unable to unlink just-created %s", source);
12718 12719
    VIR_FREE(device);
    VIR_FREE(source);
12720
    VIR_FREE(persistSource);
12721 12722 12723
    return ret;
}

12724 12725 12726 12727
/* The domain is expected to hold monitor lock.  This is the
 * counterpart to qemuDomainSnapshotCreateSingleDiskActive, called
 * only on a failed transaction. */
static void
12728
qemuDomainSnapshotUndoSingleDiskActive(virQEMUDriverPtr driver,
12729 12730 12731 12732 12733 12734 12735 12736 12737 12738
                                       virDomainObjPtr vm,
                                       virDomainDiskDefPtr origdisk,
                                       virDomainDiskDefPtr disk,
                                       virDomainDiskDefPtr persistDisk,
                                       bool need_unlink)
{
    char *source = NULL;
    char *persistSource = NULL;
    struct stat st;

12739 12740
    if (VIR_STRDUP(source, origdisk->src) < 0 ||
        (persistDisk && VIR_STRDUP(persistSource, source) < 0))
12741 12742
        goto cleanup;

12743
    qemuDomainPrepareDiskChainElement(driver, vm, disk, disk->src,
12744
                                      VIR_DISK_CHAIN_NO_ACCESS);
12745
    if (need_unlink && stat(disk->src, &st) == 0 &&
12746
        S_ISREG(st.st_mode) && unlink(disk->src) < 0)
12747 12748 12749 12750 12751 12752
        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;
12753
    disk->format = origdisk->format;
12754
    disk->type = origdisk->type;
12755 12756 12757 12758
    if (persistDisk) {
        VIR_FREE(persistDisk->src);
        persistDisk->src = persistSource;
        persistSource = NULL;
12759
        persistDisk->format = origdisk->format;
12760
        persistDisk->type = origdisk->type;
12761 12762 12763 12764 12765 12766 12767
    }

cleanup:
    VIR_FREE(source);
    VIR_FREE(persistSource);
}

12768 12769
/* The domain is expected to be locked and active. */
static int
12770
qemuDomainSnapshotCreateDiskActive(virQEMUDriverPtr driver,
12771
                                   virDomainObjPtr vm,
12772
                                   virDomainSnapshotObjPtr snap,
12773 12774
                                   unsigned int flags,
                                   enum qemuDomainAsyncJob asyncJob)
12775
{
12776 12777
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virJSONValuePtr actions = NULL;
12778
    int ret = -1;
12779
    size_t i;
12780
    bool persist = false;
12781
    bool reuse = (flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT) != 0;
12782
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
12783

12784
    if (!virDomainObjIsActive(vm)) {
12785 12786
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
12787
        goto cleanup;
12788 12789
    }

12790
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
12791
        if (!(actions = virJSONValueNewArray()))
12792
            goto cleanup;
12793
    } else if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DISK_SNAPSHOT)) {
12794 12795 12796 12797
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("live disk snapshot not supported with this "
                         "QEMU binary"));
        goto cleanup;
12798
    }
12799 12800

    /* No way to roll back if first disk succeeds but later disks
12801
     * fail, unless we have transaction support.
E
Eric Blake 已提交
12802
     * Based on earlier qemuDomainSnapshotPrepare, all
12803 12804 12805
     * 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++) {
12806 12807
        virDomainDiskDefPtr persistDisk = NULL;

E
Eric Blake 已提交
12808
        if (snap->def->disks[i].snapshot == VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
12809
            continue;
12810 12811 12812 12813
        if (vm->newDef) {
            int indx = virDomainDiskIndexByName(vm->newDef,
                                                vm->def->disks[i]->dst,
                                                false);
12814
            if (indx >= 0)
12815 12816
                persistDisk = vm->newDef->disks[indx];
        }
12817

12818
        ret = qemuDomainSnapshotCreateSingleDiskActive(driver, vm,
12819
                                                       &snap->def->disks[i],
12820
                                                       vm->def->disks[i],
12821
                                                       persistDisk, actions,
12822
                                                       reuse, asyncJob);
12823 12824 12825
        if (ret < 0)
            break;
    }
12826
    if (actions) {
12827 12828 12829 12830 12831 12832 12833 12834 12835 12836 12837 12838 12839 12840 12841
        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 已提交
12842
        virJSONValueFree(actions);
12843

12844 12845 12846
        if (ret < 0) {
            /* Transaction failed; undo the changes to vm.  */
            bool need_unlink = !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT);
12847
            while (i-- > 0) {
12848 12849
                virDomainDiskDefPtr persistDisk = NULL;

E
Eric Blake 已提交
12850 12851
                if (snap->def->disks[i].snapshot ==
                    VIR_DOMAIN_SNAPSHOT_LOCATION_NONE)
12852 12853 12854 12855 12856
                    continue;
                if (vm->newDef) {
                    int indx = virDomainDiskIndexByName(vm->newDef,
                                                        vm->def->disks[i]->dst,
                                                        false);
12857
                    if (indx >= 0) {
12858
                        persistDisk = vm->newDef->disks[indx];
12859 12860 12861
                        persist = true;
                    }

12862 12863
                }

12864
                qemuDomainSnapshotUndoSingleDiskActive(driver, vm,
12865 12866 12867 12868 12869 12870 12871
                                                       snap->def->dom->disks[i],
                                                       vm->def->disks[i],
                                                       persistDisk,
                                                       need_unlink);
            }
        }
    }
12872 12873 12874

cleanup:

12875
    if (ret == 0 || !virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION)) {
12876
        if (virDomainSaveStatus(driver->xmlopt, cfg->stateDir, vm) < 0 ||
12877
            (persist && virDomainSaveConfig(cfg->configDir, vm->newDef) < 0))
12878 12879
            ret = -1;
    }
12880
    virObjectUnref(cfg);
12881 12882 12883 12884 12885 12886 12887

    return ret;
}


static int
qemuDomainSnapshotCreateActiveExternal(virConnectPtr conn,
12888
                                       virQEMUDriverPtr driver,
12889 12890 12891 12892 12893 12894 12895 12896 12897 12898
                                       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;
12899
    bool memory_unlink = false;
12900
    bool atomic = !!(flags & VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC);
12901
    bool transaction = virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_TRANSACTION);
12902
    int thaw = 0; /* 1 if freeze succeeded, -1 if freeze failed */
12903
    bool pmsuspended = false;
12904 12905
    virQEMUDriverConfigPtr cfg = NULL;
    int compressed = QEMU_SAVE_FORMAT_RAW;
12906

P
Peter Krempa 已提交
12907
    if (qemuDomainObjBeginAsyncJob(driver, vm, QEMU_ASYNC_JOB_SNAPSHOT) < 0)
12908 12909
        goto cleanup;

12910 12911 12912 12913 12914
    /* 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) {
12915
        if (qemuDomainSnapshotFSFreeze(vm) < 0) {
12916 12917 12918 12919 12920 12921 12922 12923
            /* helper reported the error */
            thaw = -1;
            goto endjob;
        } else {
            thaw = 1;
        }
    }

12924 12925 12926 12927 12928
    /* 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) {
12929 12930 12931 12932 12933 12934 12935 12936 12937 12938 12939 12940 12941 12942 12943 12944 12945 12946 12947 12948 12949 12950 12951 12952 12953 12954 12955 12956 12957
        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) {
12958
        /* check if migration is possible */
12959
        if (!qemuMigrationIsAllowed(driver, vm, vm->def, false, false))
12960 12961
            goto endjob;

12962 12963 12964 12965 12966
        /* 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));

12967 12968 12969 12970 12971 12972 12973 12974 12975 12976 12977 12978 12979 12980 12981 12982 12983
        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;
            }
        }

12984
        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)))
12985 12986 12987
            goto endjob;

        if ((ret = qemuDomainSaveMemory(driver, vm, snap->def->file,
12988
                                        xml, compressed, resume, 0,
12989 12990 12991
                                        QEMU_ASYNC_JOB_SNAPSHOT)) < 0)
            goto endjob;

12992 12993 12994
        /* the memory image was created, remove it on errors */
        memory_unlink = true;

12995 12996 12997 12998 12999 13000 13001 13002 13003 13004 13005 13006 13007 13008 13009 13010
        /* 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 */
13011
    if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT) {
13012
        virObjectEventPtr event;
13013

13014
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_STOPPED,
13015
                                         VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT);
13016
        qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
13017 13018 13019
        virDomainAuditStop(vm, "from-snapshot");
        /* We already filtered the _HALT flag for persistent domains
         * only, so this end job never drops the last reference.  */
13020
        ignore_value(qemuDomainObjEndAsyncJob(driver, vm));
13021
        resume = false;
E
Eric Blake 已提交
13022
        thaw = 0;
13023 13024 13025
        vm = NULL;
        if (event)
            qemuDomainEventQueue(driver, event);
13026 13027 13028 13029
    } 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.  */
13030
        virObjectEventPtr event;
13031 13032 13033

        virDomainObjSetState(vm, VIR_DOMAIN_PAUSED,
                             VIR_DOMAIN_PAUSED_FROM_SNAPSHOT);
13034
        event = virDomainEventLifecycleNewFromObj(vm, VIR_DOMAIN_EVENT_SUSPENDED,
13035 13036 13037
                                         VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT);
        if (event)
            qemuDomainEventQueue(driver, event);
13038 13039
    }

13040
    ret = 0;
13041 13042

endjob:
13043 13044 13045
    if (resume && vm && virDomainObjIsActive(vm) &&
        qemuProcessStartCPUs(driver, vm, conn,
                             VIR_DOMAIN_RUNNING_UNPAUSED,
13046
                             QEMU_ASYNC_JOB_SNAPSHOT) < 0) {
13047
        virObjectEventPtr event = NULL;
13048
        event = virDomainEventLifecycleNewFromObj(vm,
13049 13050 13051 13052 13053 13054 13055 13056
                                         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"));
        }
13057

13058 13059
        ret = -1;
        goto cleanup;
13060
    }
E
Eric Blake 已提交
13061
    if (vm && thaw != 0 &&
13062
        qemuDomainSnapshotFSThaw(vm, thaw > 0) < 0) {
E
Eric Blake 已提交
13063 13064 13065 13066
        /* helper reported the error, if it was needed */
        if (thaw > 0)
            ret = -1;
    }
13067
    if (vm && !qemuDomainObjEndAsyncJob(driver, vm)) {
13068
        /* Only possible if a transient vm quit while our locks were down,
13069 13070
         * in which case we don't want to save snapshot metadata.
         */
13071 13072
        *vmptr = NULL;
        ret = -1;
13073 13074
    }

13075 13076
cleanup:
    VIR_FREE(xml);
13077
    virObjectUnref(cfg);
13078 13079
    if (memory_unlink && ret < 0)
        unlink(snap->def->file);
13080

13081 13082 13083
    return ret;
}

13084

13085 13086 13087 13088
static virDomainSnapshotPtr
qemuDomainSnapshotCreateXML(virDomainPtr domain,
                            const char *xmlDesc,
                            unsigned int flags)
C
Chris Lalancette 已提交
13089
{
13090
    virConnectPtr conn = domain->conn;
13091
    virQEMUDriverPtr driver = domain->conn->privateData;
C
Chris Lalancette 已提交
13092
    virDomainObjPtr vm = NULL;
13093
    char *xml = NULL;
C
Chris Lalancette 已提交
13094 13095
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;
13096
    virDomainSnapshotDefPtr def = NULL;
13097
    bool update_current = true;
13098
    bool redefine = flags & VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE;
13099
    unsigned int parse_flags = VIR_DOMAIN_SNAPSHOT_PARSE_DISKS;
13100
    virDomainSnapshotObjPtr other = NULL;
13101 13102
    int align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL;
    int align_match = true;
13103
    virQEMUDriverConfigPtr cfg = NULL;
13104
    virCapsPtr caps = NULL;
C
Chris Lalancette 已提交
13105

13106 13107
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_CREATE_REDEFINE |
                  VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT |
13108
                  VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA |
13109
                  VIR_DOMAIN_SNAPSHOT_CREATE_HALT |
13110
                  VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY |
13111
                  VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT |
13112
                  VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE |
13113 13114
                  VIR_DOMAIN_SNAPSHOT_CREATE_ATOMIC |
                  VIR_DOMAIN_SNAPSHOT_CREATE_LIVE, NULL);
13115 13116 13117

    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE) &&
        !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY)) {
13118 13119
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("quiesce requires disk-only"));
13120 13121
        return NULL;
    }
13122

13123
    if ((redefine && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_CURRENT)) ||
13124 13125
        (flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA))
        update_current = false;
13126
    if (redefine)
13127
        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_REDEFINE;
13128

13129
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
13130 13131
        goto cleanup;

13132 13133
    cfg = virQEMUDriverGetConfig(driver);

13134
    if (virDomainSnapshotCreateXMLEnsureACL(domain->conn, vm->def, flags) < 0)
13135 13136
        goto cleanup;

13137 13138 13139
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

13140
    if (qemuProcessAutoDestroyActive(driver, vm)) {
13141 13142
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is marked for auto destroy"));
13143 13144
        goto cleanup;
    }
E
Eric Blake 已提交
13145 13146 13147 13148 13149 13150
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
        goto cleanup;
    }

13151
    if (!vm->persistent && (flags & VIR_DOMAIN_SNAPSHOT_CREATE_HALT)) {
13152 13153
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("cannot halt after transient domain snapshot"));
13154 13155
        goto cleanup;
    }
13156 13157 13158
    if ((flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) ||
        !virDomainObjIsActive(vm))
        parse_flags |= VIR_DOMAIN_SNAPSHOT_PARSE_OFFLINE;
13159

13160
    if (!(def = virDomainSnapshotDefParseString(xmlDesc, caps, driver->xmlopt,
13161 13162
                                                QEMU_EXPECTED_VIRT_TYPES,
                                                parse_flags)))
C
Chris Lalancette 已提交
13163 13164
        goto cleanup;

13165 13166 13167 13168 13169 13170 13171 13172 13173 13174 13175 13176 13177 13178 13179 13180 13181 13182
    /* 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;
        }
13183 13184
    }

13185 13186 13187 13188
    /* 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 ||
13189
         redefine)) {
13190 13191 13192 13193 13194 13195
        virReportError(VIR_ERR_OPERATION_UNSUPPORTED, "%s",
                       _("live snapshot creation is supported only "
                         "with external checkpoints"));
        goto cleanup;
    }

13196
    if (redefine) {
13197 13198
        if (!virDomainSnapshotRedefinePrep(domain, vm, &def, &snap,
                                           &update_current, flags) < 0)
13199 13200 13201 13202
            goto cleanup;
    } else {
        /* Easiest way to clone inactive portion of vm->def is via
         * conversion in and back out of xml.  */
13203
        if (!(xml = qemuDomainDefFormatLive(driver, vm->def, true, true)) ||
13204
            !(def->dom = virDomainDefParseString(xml, caps, driver->xmlopt,
13205 13206 13207 13208
                                                 QEMU_EXPECTED_VIRT_TYPES,
                                                 VIR_DOMAIN_XML_INACTIVE)))
            goto cleanup;

13209
        if (flags & VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY) {
13210 13211
            align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
            align_match = false;
13212 13213 13214 13215
            if (virDomainObjIsActive(vm))
                def->state = VIR_DOMAIN_DISK_SNAPSHOT;
            else
                def->state = VIR_DOMAIN_SHUTOFF;
13216
            def->memory = VIR_DOMAIN_SNAPSHOT_LOCATION_NONE;
13217 13218 13219 13220
        } else if (def->memory == VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL) {
            def->state = virDomainObjGetState(vm, NULL);
            align_location = VIR_DOMAIN_SNAPSHOT_LOCATION_EXTERNAL;
            align_match = false;
13221 13222
        } else {
            def->state = virDomainObjGetState(vm, NULL);
13223 13224 13225
            def->memory = (def->state == VIR_DOMAIN_SHUTOFF ?
                           VIR_DOMAIN_SNAPSHOT_LOCATION_NONE :
                           VIR_DOMAIN_SNAPSHOT_LOCATION_INTERNAL);
13226
        }
E
Eric Blake 已提交
13227 13228
        if (virDomainSnapshotAlignDisks(def, align_location,
                                        align_match) < 0 ||
13229
            qemuDomainSnapshotPrepare(conn, vm, def, &flags) < 0)
E
Eric Blake 已提交
13230
            goto cleanup;
13231 13232
    }

13233 13234 13235 13236 13237 13238
    if (!snap) {
        if (!(snap = virDomainSnapshotAssignDef(vm->snapshots, def)))
            goto cleanup;

        def = NULL;
    }
C
Chris Lalancette 已提交
13239

13240 13241
    if (update_current)
        snap->def->current = true;
13242
    if (vm->current_snapshot) {
13243
        if (!redefine &&
13244
            VIR_STRDUP(snap->def->parent, vm->current_snapshot->def->name) < 0)
13245 13246
                goto cleanup;
        if (update_current) {
13247 13248
            vm->current_snapshot->def->current = false;
            if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
13249
                                                cfg->snapshotDir) < 0)
13250 13251 13252
                goto cleanup;
            vm->current_snapshot = NULL;
        }
13253
    }
13254

C
Chris Lalancette 已提交
13255
    /* actually do the snapshot */
13256
    if (redefine) {
13257
        /* XXX Should we validate that the redefined snapshot even
13258 13259
         * makes sense, such as checking that qemu-img recognizes the
         * snapshot name in at least one of the domain's disks?  */
13260 13261 13262 13263 13264 13265 13266 13267 13268 13269 13270 13271 13272
    } 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 已提交
13273
    } else {
13274 13275 13276 13277 13278 13279 13280 13281 13282 13283 13284 13285 13286
        /* 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 已提交
13287 13288
    }

13289
    /* If we fail after this point, there's not a whole lot we can
C
Chris Lalancette 已提交
13290 13291 13292 13293 13294 13295
     * 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:
13296
    if (vm) {
13297
        if (snapshot && !(flags & VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA)) {
13298
            if (qemuDomainSnapshotWriteMetadata(vm, snap,
13299
                                                cfg->snapshotDir) < 0) {
13300 13301 13302 13303 13304 13305 13306 13307
                /* 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);
13308 13309 13310
            } else {
                if (update_current)
                    vm->current_snapshot = snap;
13311
                other = virDomainSnapshotFindByName(vm->snapshots,
13312 13313 13314 13315 13316
                                                    snap->def->parent);
                snap->parent = other;
                other->nchildren++;
                snap->sibling = other->first_child;
                other->first_child = snap;
13317
            }
13318
        } else if (snap) {
13319
            virDomainSnapshotObjListRemove(vm->snapshots, snap);
13320
        }
13321
        virObjectUnlock(vm);
13322 13323
    }
    virDomainSnapshotDefFree(def);
13324
    VIR_FREE(xml);
13325
    virObjectUnref(caps);
13326
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
13327 13328 13329 13330 13331
    return snapshot;
}

static int qemuDomainSnapshotListNames(virDomainPtr domain, char **names,
                                       int nameslen,
13332
                                       unsigned int flags)
C
Chris Lalancette 已提交
13333 13334 13335 13336
{
    virDomainObjPtr vm = NULL;
    int n = -1;

13337
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
13338
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
13339

13340
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
13341 13342
        goto cleanup;

13343 13344 13345
    if (virDomainSnapshotListNamesEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

13346
    n = virDomainSnapshotObjListGetNames(vm->snapshots, NULL, names, nameslen,
13347
                                         flags);
C
Chris Lalancette 已提交
13348 13349 13350

cleanup:
    if (vm)
13351
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
13352 13353 13354 13355
    return n;
}

static int qemuDomainSnapshotNum(virDomainPtr domain,
13356
                                 unsigned int flags)
C
Chris Lalancette 已提交
13357 13358 13359 13360
{
    virDomainObjPtr vm = NULL;
    int n = -1;

13361
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_LIST_ROOTS |
13362
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
13363

13364
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
13365 13366
        goto cleanup;

13367 13368 13369
    if (virDomainSnapshotNumEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

13370
    n = virDomainSnapshotObjListNum(vm->snapshots, NULL, flags);
C
Chris Lalancette 已提交
13371 13372 13373

cleanup:
    if (vm)
13374
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
13375 13376 13377
    return n;
}

13378 13379 13380 13381 13382 13383 13384 13385 13386 13387
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);

13388
    if (!(vm = qemuDomObjFromDomain(domain)))
13389 13390
        goto cleanup;

13391 13392 13393
    if (virDomainListAllSnapshotsEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

13394
    n = virDomainListSnapshots(vm->snapshots, NULL, domain, snaps, flags);
13395 13396 13397

cleanup:
    if (vm)
13398
        virObjectUnlock(vm);
13399 13400 13401
    return n;
}

13402 13403 13404 13405 13406 13407 13408 13409 13410 13411 13412
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 |
13413
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
13414

13415
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
13416 13417
        goto cleanup;

13418 13419 13420
    if (virDomainSnapshotListChildrenNamesEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13421
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
13422 13423
        goto cleanup;

13424
    n = virDomainSnapshotObjListGetNames(vm->snapshots, snap, names, nameslen,
13425
                                         flags);
13426 13427 13428

cleanup:
    if (vm)
13429
        virObjectUnlock(vm);
13430 13431 13432 13433 13434 13435 13436 13437 13438 13439 13440 13441
    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 |
13442
                  VIR_DOMAIN_SNAPSHOT_FILTERS_ALL, -1);
13443

13444
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
13445 13446
        goto cleanup;

13447 13448 13449
    if (virDomainSnapshotNumChildrenEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13450
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
13451 13452
        goto cleanup;

13453
    n = virDomainSnapshotObjListNum(vm->snapshots, snap, flags);
13454 13455 13456

cleanup:
    if (vm)
13457
        virObjectUnlock(vm);
13458 13459 13460
    return n;
}

13461 13462 13463 13464 13465 13466 13467 13468 13469 13470 13471 13472
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);

13473
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
13474 13475
        goto cleanup;

13476 13477 13478
    if (virDomainSnapshotListAllChildrenEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13479
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
13480 13481
        goto cleanup;

13482
    n = virDomainListSnapshots(vm->snapshots, snap, snapshot->domain, snaps,
13483 13484 13485 13486
                               flags);

cleanup:
    if (vm)
13487
        virObjectUnlock(vm);
13488 13489 13490
    return n;
}

C
Chris Lalancette 已提交
13491 13492
static virDomainSnapshotPtr qemuDomainSnapshotLookupByName(virDomainPtr domain,
                                                           const char *name,
13493
                                                           unsigned int flags)
C
Chris Lalancette 已提交
13494 13495 13496 13497 13498
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr snapshot = NULL;

13499 13500
    virCheckFlags(0, NULL);

13501
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
13502 13503
        goto cleanup;

13504 13505 13506
    if (virDomainSnapshotLookupByNameEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

13507
    if (!(snap = qemuSnapObjFromName(vm, name)))
C
Chris Lalancette 已提交
13508 13509 13510 13511 13512 13513
        goto cleanup;

    snapshot = virGetDomainSnapshot(domain, snap->def->name);

cleanup:
    if (vm)
13514
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
13515 13516 13517 13518
    return snapshot;
}

static int qemuDomainHasCurrentSnapshot(virDomainPtr domain,
13519
                                        unsigned int flags)
C
Chris Lalancette 已提交
13520 13521 13522 13523
{
    virDomainObjPtr vm;
    int ret = -1;

13524 13525
    virCheckFlags(0, -1);

13526
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
13527 13528
        goto cleanup;

13529 13530 13531
    if (virDomainHasCurrentSnapshotEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

C
Chris Lalancette 已提交
13532 13533 13534 13535
    ret = (vm->current_snapshot != NULL);

cleanup:
    if (vm)
13536
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
13537 13538 13539
    return ret;
}

13540 13541 13542 13543 13544 13545 13546 13547 13548 13549
static virDomainSnapshotPtr
qemuDomainSnapshotGetParent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm;
    virDomainSnapshotObjPtr snap = NULL;
    virDomainSnapshotPtr parent = NULL;

    virCheckFlags(0, NULL);

13550
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
13551 13552
        goto cleanup;

13553 13554 13555
    if (virDomainSnapshotGetParentEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13556
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
13557 13558 13559
        goto cleanup;

    if (!snap->def->parent) {
13560 13561 13562
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT,
                       _("snapshot '%s' does not have a parent"),
                       snap->def->name);
13563 13564 13565 13566 13567 13568 13569
        goto cleanup;
    }

    parent = virGetDomainSnapshot(snapshot->domain, snap->def->parent);

cleanup:
    if (vm)
13570
        virObjectUnlock(vm);
13571 13572 13573
    return parent;
}

C
Chris Lalancette 已提交
13574
static virDomainSnapshotPtr qemuDomainSnapshotCurrent(virDomainPtr domain,
13575
                                                      unsigned int flags)
C
Chris Lalancette 已提交
13576 13577 13578 13579
{
    virDomainObjPtr vm;
    virDomainSnapshotPtr snapshot = NULL;

13580 13581
    virCheckFlags(0, NULL);

13582
    if (!(vm = qemuDomObjFromDomain(domain)))
C
Chris Lalancette 已提交
13583 13584
        goto cleanup;

13585 13586 13587
    if (virDomainSnapshotCurrentEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

C
Chris Lalancette 已提交
13588
    if (!vm->current_snapshot) {
13589 13590
        virReportError(VIR_ERR_NO_DOMAIN_SNAPSHOT, "%s",
                       _("the domain does not have a current snapshot"));
C
Chris Lalancette 已提交
13591 13592 13593 13594 13595 13596 13597
        goto cleanup;
    }

    snapshot = virGetDomainSnapshot(domain, vm->current_snapshot->def->name);

cleanup:
    if (vm)
13598
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
13599 13600 13601
    return snapshot;
}

13602 13603
static char *qemuDomainSnapshotGetXMLDesc(virDomainSnapshotPtr snapshot,
                                          unsigned int flags)
C
Chris Lalancette 已提交
13604 13605 13606 13607 13608 13609
{
    virDomainObjPtr vm = NULL;
    char *xml = NULL;
    virDomainSnapshotObjPtr snap = NULL;
    char uuidstr[VIR_UUID_STRING_BUFLEN];

13610
    virCheckFlags(VIR_DOMAIN_XML_SECURE, NULL);
13611

13612
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
C
Chris Lalancette 已提交
13613 13614
        goto cleanup;

13615 13616 13617
    if (virDomainSnapshotGetXMLDescEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13618
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
13619
        goto cleanup;
13620 13621

    virUUIDFormat(snapshot->domain->uuid, uuidstr);
C
Chris Lalancette 已提交
13622

13623
    xml = virDomainSnapshotDefFormat(uuidstr, snap->def, flags, 0);
C
Chris Lalancette 已提交
13624 13625 13626

cleanup:
    if (vm)
13627
        virObjectUnlock(vm);
C
Chris Lalancette 已提交
13628 13629 13630
    return xml;
}

13631 13632 13633 13634 13635 13636 13637 13638 13639 13640
static int
qemuDomainSnapshotIsCurrent(virDomainSnapshotPtr snapshot,
                            unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

13641
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
13642 13643
        goto cleanup;

13644 13645 13646
    if (virDomainSnapshotIsCurrentEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13647
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
13648 13649 13650 13651 13652 13653 13654
        goto cleanup;

    ret = (vm->current_snapshot &&
           STREQ(snapshot->name, vm->current_snapshot->def->name));

cleanup:
    if (vm)
13655
        virObjectUnlock(vm);
13656 13657 13658 13659 13660 13661 13662 13663 13664 13665 13666 13667 13668 13669
    return ret;
}


static int
qemuDomainSnapshotHasMetadata(virDomainSnapshotPtr snapshot,
                              unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;

    virCheckFlags(0, -1);

13670
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
13671 13672
        goto cleanup;

13673 13674 13675
    if (virDomainSnapshotHasMetadataEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13676
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
13677 13678 13679 13680 13681 13682 13683 13684 13685
        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)
13686
        virObjectUnlock(vm);
13687 13688 13689
    return ret;
}

13690 13691
/* The domain is expected to be locked and inactive. */
static int
13692
qemuDomainSnapshotRevertInactive(virQEMUDriverPtr driver,
E
Eric Blake 已提交
13693
                                 virDomainObjPtr vm,
13694 13695 13696
                                 virDomainSnapshotObjPtr snap)
{
    /* Try all disks, but report failure if we skipped any.  */
E
Eric Blake 已提交
13697
    int ret = qemuDomainSnapshotForEachQcow2(driver, vm, snap, "-a", true);
13698 13699 13700
    return ret > 0 ? -1 : ret;
}

C
Chris Lalancette 已提交
13701
static int qemuDomainRevertToSnapshot(virDomainSnapshotPtr snapshot,
13702
                                      unsigned int flags)
C
Chris Lalancette 已提交
13703
{
13704
    virQEMUDriverPtr driver = snapshot->domain->conn->privateData;
C
Chris Lalancette 已提交
13705 13706 13707
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
13708 13709
    virObjectEventPtr event = NULL;
    virObjectEventPtr event2 = NULL;
13710
    int detail;
C
Chris Lalancette 已提交
13711 13712
    qemuDomainObjPrivatePtr priv;
    int rc;
13713
    virDomainDefPtr config = NULL;
13714
    virQEMUDriverConfigPtr cfg = NULL;
13715
    virCapsPtr caps = NULL;
C
Chris Lalancette 已提交
13716

13717
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING |
13718 13719
                  VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED |
                  VIR_DOMAIN_SNAPSHOT_REVERT_FORCE, -1);
13720

13721 13722 13723 13724 13725 13726 13727 13728 13729 13730
    /* 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
13731 13732
     * Also, several transitions occur even if we fail partway through,
     * and use of FORCE can cause multiple transitions.
13733 13734
     */

13735 13736
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
        return -1;
13737 13738 13739

    cfg = virQEMUDriverGetConfig(driver);

13740 13741 13742
    if (virDomainRevertToSnapshotEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

13743 13744 13745
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

E
Eric Blake 已提交
13746 13747 13748 13749 13750
    if (virDomainHasDiskMirror(vm)) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE, "%s",
                       _("domain has active block copy job"));
        goto cleanup;
    }
C
Chris Lalancette 已提交
13751

13752
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
13753 13754
        goto cleanup;

13755 13756 13757 13758 13759
    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) {
13760 13761 13762
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("transient domain needs to request run or pause "
                         "to revert to inactive snapshot"));
13763 13764
        goto cleanup;
    }
13765
    if (snap->def->state == VIR_DOMAIN_DISK_SNAPSHOT) {
13766 13767 13768
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("revert to external disk snapshot not supported "
                         "yet"));
13769 13770
        goto cleanup;
    }
13771 13772
    if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
        if (!snap->def->dom) {
13773 13774 13775
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY,
                           _("snapshot '%s' lacks domain '%s' rollback info"),
                           snap->def->name, vm->def->name);
13776 13777 13778 13779 13780 13781 13782
            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))) {
13783 13784
            virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                           _("must respawn qemu to start inactive snapshot"));
13785 13786 13787 13788
            goto cleanup;
        }
    }

13789

13790 13791 13792
    if (vm->current_snapshot) {
        vm->current_snapshot->def->current = false;
        if (qemuDomainSnapshotWriteMetadata(vm, vm->current_snapshot,
13793
                                            cfg->snapshotDir) < 0)
13794 13795 13796 13797 13798 13799
            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?  */
    }

13800
    /* Prepare to copy the snapshot inactive xml as the config of this
13801
     * domain.
13802 13803 13804
     *
     * XXX Should domain snapshots track live xml rather
     * than inactive xml?  */
13805
    snap->def->current = true;
13806
    if (snap->def->dom) {
13807
        config = virDomainDefCopy(snap->def->dom, caps, driver->xmlopt, true);
13808 13809 13810
        if (!config)
            goto cleanup;
    }
C
Chris Lalancette 已提交
13811

13812
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
C
Chris Lalancette 已提交
13813 13814 13815 13816
        goto cleanup;

    if (snap->def->state == VIR_DOMAIN_RUNNING
        || snap->def->state == VIR_DOMAIN_PAUSED) {
13817 13818 13819 13820 13821 13822 13823 13824 13825
        /* 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 已提交
13826
        if (virDomainObjIsActive(vm)) {
13827
            /* Transitions 5, 6, 8, 9 */
13828 13829
            /* Check for ABI compatibility. We need to do this check against
             * the migratable XML or it will always fail otherwise */
13830
            if (config && !qemuDomainDefCheckABIStability(driver, vm->def, config)) {
13831 13832 13833 13834 13835
                virErrorPtr err = virGetLastError();

                if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_FORCE)) {
                    /* Re-spawn error using correct category. */
                    if (err->code == VIR_ERR_CONFIG_UNSUPPORTED)
13836 13837
                        virReportError(VIR_ERR_SNAPSHOT_REVERT_RISKY, "%s",
                                       err->str2);
13838 13839 13840
                    goto endjob;
                }
                virResetError(err);
13841 13842
                qemuProcessStop(driver, vm,
                                VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
13843 13844
                virDomainAuditStop(vm, "from-snapshot");
                detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
13845
                event = virDomainEventLifecycleNewFromObj(vm,
13846 13847 13848 13849 13850
                                                 VIR_DOMAIN_EVENT_STOPPED,
                                                 detail);
                if (event)
                    qemuDomainEventQueue(driver, event);
                goto load;
13851 13852
            }

C
Chris Lalancette 已提交
13853
            priv = vm->privateData;
13854 13855 13856 13857 13858 13859 13860 13861 13862 13863 13864
            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;
13865
                event = virDomainEventLifecycleNewFromObj(vm,
13866 13867 13868
                                                 VIR_DOMAIN_EVENT_SUSPENDED,
                                                 detail);
                if (!virDomainObjIsActive(vm)) {
13869 13870
                    virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                                   _("guest unexpectedly quit"));
13871 13872 13873
                    goto endjob;
                }
            }
13874
            qemuDomainObjEnterMonitor(driver, vm);
C
Chris Lalancette 已提交
13875
            rc = qemuMonitorLoadSnapshot(priv->mon, snap->def->name);
13876
            qemuDomainObjExitMonitor(driver, vm);
13877 13878 13879
            if (rc < 0) {
                /* XXX resume domain if it was running before the
                 * failed loadvm attempt? */
13880
                goto endjob;
13881
            }
13882
            if (config)
13883
                virDomainObjAssignDef(vm, config, false, NULL);
E
Eric Blake 已提交
13884
        } else {
13885
            /* Transitions 2, 3 */
13886
        load:
13887
            was_stopped = true;
13888
            if (config)
13889
                virDomainObjAssignDef(vm, config, false, NULL);
13890

13891 13892 13893 13894
            rc = qemuProcessStart(snapshot->domain->conn,
                                  driver, vm, NULL, -1, NULL, snap,
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  VIR_QEMU_PROCESS_START_PAUSED);
13895
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
13896
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
13897
            event = virDomainEventLifecycleNewFromObj(vm,
13898 13899
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
C
Chris Lalancette 已提交
13900
            if (rc < 0)
13901
                goto endjob;
C
Chris Lalancette 已提交
13902 13903
        }

13904
        /* Touch up domain state.  */
13905 13906 13907
        if (!(flags & VIR_DOMAIN_SNAPSHOT_REVERT_RUNNING) &&
            (snap->def->state == VIR_DOMAIN_PAUSED ||
             (flags & VIR_DOMAIN_SNAPSHOT_REVERT_PAUSED))) {
13908 13909 13910 13911 13912 13913
            /* 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;
13914
                event2 = virDomainEventLifecycleNewFromObj(vm,
13915 13916 13917 13918 13919 13920
                                                  VIR_DOMAIN_EVENT_SUSPENDED,
                                                  detail);
            } /* else transition 6 and 9 use event as-is */
        } else {
            /* Transitions 2, 5, 8 */
            if (!virDomainObjIsActive(vm)) {
13921 13922
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("guest unexpectedly quit"));
13923 13924 13925 13926 13927
                goto endjob;
            }
            rc = qemuProcessStartCPUs(driver, vm, snapshot->domain->conn,
                                      VIR_DOMAIN_RUNNING_FROM_SNAPSHOT,
                                      QEMU_ASYNC_JOB_NONE);
H
Hu Tao 已提交
13928
            if (rc < 0)
13929
                goto endjob;
C
Cédric Bosdonnat 已提交
13930
            virObjectUnref(event);
13931 13932 13933 13934
            event = NULL;
            if (was_stopped) {
                /* Transition 2 */
                detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
13935
                event = virDomainEventLifecycleNewFromObj(vm,
13936 13937 13938 13939 13940
                                                 VIR_DOMAIN_EVENT_STARTED,
                                                 detail);
            } else if (was_running) {
                /* Transition 8 */
                detail = VIR_DOMAIN_EVENT_RESUMED;
13941
                event = virDomainEventLifecycleNewFromObj(vm,
13942 13943 13944
                                                 VIR_DOMAIN_EVENT_RESUMED,
                                                 detail);
            }
C
Chris Lalancette 已提交
13945
        }
E
Eric Blake 已提交
13946
    } else {
13947
        /* Transitions 1, 4, 7 */
13948 13949 13950
        /* 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 已提交
13951 13952 13953
         */

        if (virDomainObjIsActive(vm)) {
13954
            /* Transitions 4, 7 */
13955
            qemuProcessStop(driver, vm, VIR_DOMAIN_SHUTOFF_FROM_SNAPSHOT, 0);
13956
            virDomainAuditStop(vm, "from-snapshot");
13957
            detail = VIR_DOMAIN_EVENT_STOPPED_FROM_SNAPSHOT;
13958
            event = virDomainEventLifecycleNewFromObj(vm,
C
Chris Lalancette 已提交
13959
                                             VIR_DOMAIN_EVENT_STOPPED,
13960
                                             detail);
13961 13962
        }

E
Eric Blake 已提交
13963
        if (qemuDomainSnapshotRevertInactive(driver, vm, snap) < 0) {
13964
            if (!vm->persistent) {
E
Eric Blake 已提交
13965
                if (qemuDomainObjEndJob(driver, vm))
13966
                    qemuDomainRemoveInactive(driver, vm);
13967
                vm = NULL;
13968
                goto cleanup;
13969
            }
13970
            goto endjob;
C
Chris Lalancette 已提交
13971
        }
13972
        if (config)
13973
            virDomainObjAssignDef(vm, config, false, NULL);
13974

13975 13976 13977 13978
        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;
13979 13980 13981
            unsigned int start_flags = 0;

            start_flags |= paused ? VIR_QEMU_PROCESS_START_PAUSED : 0;
13982 13983 13984

            if (event)
                qemuDomainEventQueue(driver, event);
13985 13986 13987 13988
            rc = qemuProcessStart(snapshot->domain->conn,
                                  driver, vm, NULL, -1, NULL, NULL,
                                  VIR_NETDEV_VPORT_PROFILE_OP_CREATE,
                                  start_flags);
13989 13990 13991
            virDomainAuditStart(vm, "from-snapshot", rc >= 0);
            if (rc < 0) {
                if (!vm->persistent) {
E
Eric Blake 已提交
13992
                    if (qemuDomainObjEndJob(driver, vm))
13993
                        qemuDomainRemoveInactive(driver, vm);
13994 13995 13996 13997 13998 13999
                    vm = NULL;
                    goto cleanup;
                }
                goto endjob;
            }
            detail = VIR_DOMAIN_EVENT_STARTED_FROM_SNAPSHOT;
14000
            event = virDomainEventLifecycleNewFromObj(vm,
14001 14002 14003 14004
                                             VIR_DOMAIN_EVENT_STARTED,
                                             detail);
            if (paused) {
                detail = VIR_DOMAIN_EVENT_SUSPENDED_FROM_SNAPSHOT;
14005
                event2 = virDomainEventLifecycleNewFromObj(vm,
14006 14007 14008 14009
                                                  VIR_DOMAIN_EVENT_SUSPENDED,
                                                  detail);
            }
        }
C
Chris Lalancette 已提交
14010 14011 14012 14013
    }

    ret = 0;

14014
endjob:
E
Eric Blake 已提交
14015
    if (vm && !qemuDomainObjEndJob(driver, vm))
C
Chris Lalancette 已提交
14016 14017
        vm = NULL;

14018
cleanup:
14019 14020
    if (vm && ret == 0) {
        if (qemuDomainSnapshotWriteMetadata(vm, snap,
14021
                                            cfg->snapshotDir) < 0)
14022 14023 14024 14025 14026 14027
            ret = -1;
        else
            vm->current_snapshot = snap;
    } else if (snap) {
        snap->def->current = false;
    }
14028
    if (event) {
C
Chris Lalancette 已提交
14029
        qemuDomainEventQueue(driver, event);
14030 14031 14032
        if (event2)
            qemuDomainEventQueue(driver, event2);
    }
C
Chris Lalancette 已提交
14033
    if (vm)
14034
        virObjectUnlock(vm);
14035
    virObjectUnref(caps);
14036
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
14037 14038 14039 14040

    return ret;
}

14041 14042 14043 14044

typedef struct _virQEMUSnapReparent virQEMUSnapReparent;
typedef virQEMUSnapReparent *virQEMUSnapReparentPtr;
struct _virQEMUSnapReparent {
14045
    virQEMUDriverConfigPtr cfg;
14046
    virDomainSnapshotObjPtr parent;
14047 14048
    virDomainObjPtr vm;
    int err;
14049
    virDomainSnapshotObjPtr last;
14050 14051 14052 14053
};

static void
qemuDomainSnapshotReparentChildren(void *payload,
14054
                                   const void *name ATTRIBUTE_UNUSED,
14055 14056 14057
                                   void *data)
{
    virDomainSnapshotObjPtr snap = payload;
14058
    virQEMUSnapReparentPtr rep = data;
14059 14060 14061 14062 14063

    if (rep->err < 0) {
        return;
    }

14064
    VIR_FREE(snap->def->parent);
14065
    snap->parent = rep->parent;
14066

14067 14068 14069 14070
    if (rep->parent->def &&
        VIR_STRDUP(snap->def->parent, rep->parent->def->name) < 0) {
        rep->err = -1;
        return;
14071
    }
14072

14073 14074 14075
    if (!snap->sibling)
        rep->last = snap;

14076
    rep->err = qemuDomainSnapshotWriteMetadata(rep->vm, snap,
14077
                                               rep->cfg->snapshotDir);
14078 14079
}

14080

C
Chris Lalancette 已提交
14081 14082 14083
static int qemuDomainSnapshotDelete(virDomainSnapshotPtr snapshot,
                                    unsigned int flags)
{
14084
    virQEMUDriverPtr driver = snapshot->domain->conn->privateData;
C
Chris Lalancette 已提交
14085 14086 14087
    virDomainObjPtr vm = NULL;
    int ret = -1;
    virDomainSnapshotObjPtr snap = NULL;
14088 14089
    virQEMUSnapRemove rem;
    virQEMUSnapReparent rep;
14090
    bool metadata_only = !!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY);
14091
    int external = 0;
14092
    virQEMUDriverConfigPtr cfg = NULL;
C
Chris Lalancette 已提交
14093

14094
    virCheckFlags(VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
14095 14096
                  VIR_DOMAIN_SNAPSHOT_DELETE_METADATA_ONLY |
                  VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY, -1);
14097

14098 14099
    if (!(vm = qemuDomObjFromSnapshot(snapshot)))
        return -1;
C
Chris Lalancette 已提交
14100

14101
    cfg = virQEMUDriverGetConfig(driver);
14102 14103 14104 14105

    if (virDomainSnapshotDeleteEnsureACL(snapshot->domain->conn, vm->def) < 0)
        goto cleanup;

14106
    if (!(snap = qemuSnapObjFromSnapshot(vm, snapshot)))
C
Chris Lalancette 已提交
14107 14108
        goto cleanup;

14109
    if (!metadata_only) {
14110
        if (!(flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) &&
14111
            virDomainSnapshotIsExternal(snap))
14112 14113
            external++;
        if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN)
E
Eric Blake 已提交
14114
            virDomainSnapshotForEachDescendant(snap,
14115 14116 14117
                                               qemuDomainSnapshotCountExternal,
                                               &external);
        if (external) {
14118 14119 14120
            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                           _("deletion of %d external disk snapshots not "
                             "supported yet"), external);
14121 14122 14123 14124
            goto cleanup;
        }
    }

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

14128 14129
    if (flags & (VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN |
                 VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY)) {
C
Chris Lalancette 已提交
14130 14131
        rem.driver = driver;
        rem.vm = vm;
14132
        rem.metadata_only = metadata_only;
C
Chris Lalancette 已提交
14133
        rem.err = 0;
14134
        rem.current = false;
E
Eric Blake 已提交
14135
        virDomainSnapshotForEachDescendant(snap,
E
Eric Blake 已提交
14136
                                           qemuDomainSnapshotDiscardAll,
14137
                                           &rem);
C
Chris Lalancette 已提交
14138
        if (rem.err < 0)
14139
            goto endjob;
14140 14141 14142 14143
        if (rem.current) {
            if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
                snap->def->current = true;
                if (qemuDomainSnapshotWriteMetadata(vm, snap,
14144
                                                    cfg->snapshotDir) < 0) {
14145 14146 14147
                    virReportError(VIR_ERR_INTERNAL_ERROR,
                                   _("failed to set snapshot '%s' as current"),
                                   snap->def->name);
14148 14149 14150 14151
                    snap->def->current = false;
                    goto endjob;
                }
            }
14152
            vm->current_snapshot = snap;
14153
        }
14154
    } else if (snap->nchildren) {
14155
        rep.cfg = cfg;
14156
        rep.parent = snap->parent;
14157 14158
        rep.vm = vm;
        rep.err = 0;
14159
        rep.last = NULL;
E
Eric Blake 已提交
14160
        virDomainSnapshotForEachChild(snap,
14161 14162
                                      qemuDomainSnapshotReparentChildren,
                                      &rep);
14163 14164
        if (rep.err < 0)
            goto endjob;
14165
        /* Can't modify siblings during ForEachChild, so do it now.  */
14166 14167 14168
        snap->parent->nchildren += snap->nchildren;
        rep.last->sibling = snap->parent->first_child;
        snap->parent->first_child = snap->first_child;
C
Chris Lalancette 已提交
14169 14170
    }

14171 14172 14173
    if (flags & VIR_DOMAIN_SNAPSHOT_DELETE_CHILDREN_ONLY) {
        snap->nchildren = 0;
        snap->first_child = NULL;
14174
        ret = 0;
14175
    } else {
14176
        virDomainSnapshotDropParent(snap);
14177
        ret = qemuDomainSnapshotDiscard(driver, vm, snap, true, metadata_only);
14178
    }
C
Chris Lalancette 已提交
14179

14180
endjob:
E
Eric Blake 已提交
14181
    if (!qemuDomainObjEndJob(driver, vm))
14182 14183
        vm = NULL;

C
Chris Lalancette 已提交
14184 14185
cleanup:
    if (vm)
14186
        virObjectUnlock(vm);
14187
    virObjectUnref(cfg);
C
Chris Lalancette 已提交
14188 14189
    return ret;
}
14190

14191 14192
static int qemuDomainQemuMonitorCommand(virDomainPtr domain, const char *cmd,
                                        char **result, unsigned int flags)
14193
{
14194
    virQEMUDriverPtr driver = domain->conn->privateData;
14195 14196 14197
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
14198
    bool hmp;
14199

14200
    virCheckFlags(VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP, -1);
14201

14202
    if (!(vm = qemuDomObjFromDomain(domain)))
14203 14204
        goto cleanup;

14205 14206 14207
    if (virDomainQemuMonitorCommandEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

14208
    if (!virDomainObjIsActive(vm)) {
14209 14210
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
14211
        goto cleanup;
14212
    }
14213

14214
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
14215 14216 14217
        goto cleanup;

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

14223 14224
    priv = vm->privateData;

14225
    qemuDomainObjTaint(driver, vm, VIR_DOMAIN_TAINT_CUSTOM_MONITOR, -1);
14226

14227 14228
    hmp = !!(flags & VIR_DOMAIN_QEMU_MONITOR_COMMAND_HMP);

14229
    qemuDomainObjEnterMonitor(driver, vm);
14230
    ret = qemuMonitorArbitraryCommand(priv->mon, cmd, result, hmp);
14231
    qemuDomainObjExitMonitor(driver, vm);
14232 14233

endjob:
E
Eric Blake 已提交
14234
    if (!qemuDomainObjEndJob(driver, vm)) {
14235 14236 14237 14238 14239
        vm = NULL;
    }

cleanup:
    if (vm)
14240
        virObjectUnlock(vm);
14241 14242 14243
    return ret;
}

14244

14245 14246 14247
static virDomainPtr qemuDomainQemuAttach(virConnectPtr conn,
                                         unsigned int pid_value,
                                         unsigned int flags)
14248
{
14249
    virQEMUDriverPtr driver = conn->privateData;
14250 14251 14252 14253 14254
    virDomainObjPtr vm = NULL;
    virDomainDefPtr def = NULL;
    virDomainPtr dom = NULL;
    virDomainChrSourceDefPtr monConfig = NULL;
    bool monJSON = false;
14255
    pid_t pid = pid_value;
14256
    char *pidfile = NULL;
14257
    virQEMUCapsPtr qemuCaps = NULL;
14258
    virCapsPtr caps = NULL;
14259 14260 14261

    virCheckFlags(0, NULL);

14262 14263 14264
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

14265
    if (!(def = qemuParseCommandLinePid(caps, driver->xmlopt, pid,
14266 14267 14268
                                        &pidfile, &monConfig, &monJSON)))
        goto cleanup;

14269 14270 14271
    if (virDomainQemuAttachEnsureACL(conn, def) < 0)
        goto cleanup;

14272
    if (!monConfig) {
14273 14274
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("No monitor connection for pid %u"), pid_value);
14275 14276 14277
        goto cleanup;
    }
    if (monConfig->type != VIR_DOMAIN_CHR_TYPE_UNIX) {
14278 14279 14280 14281 14282
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Cannot connect to monitor connection of type '%s' "
                         "for pid %u"),
                       virDomainChrTypeToString(monConfig->type),
                       pid_value);
14283 14284 14285 14286
        goto cleanup;
    }

    if (!(def->name) &&
14287
        virAsprintf(&def->name, "attach-pid-%u", pid_value) < 0)
14288 14289
        goto cleanup;

14290
    if (!(qemuCaps = virQEMUCapsCacheLookup(driver->qemuCapsCache, def->emulator)))
14291 14292
        goto cleanup;

14293
    if (qemuCanonicalizeMachine(def, qemuCaps) < 0)
14294 14295
        goto cleanup;

14296
    if (qemuDomainAssignAddresses(def, qemuCaps, NULL) < 0)
14297 14298
        goto cleanup;

14299
    if (!(vm = virDomainObjListAdd(driver->domains, def,
14300
                                   driver->xmlopt,
14301 14302 14303
                                   VIR_DOMAIN_OBJ_LIST_ADD_LIVE |
                                   VIR_DOMAIN_OBJ_LIST_ADD_CHECK_LIVE,
                                   NULL)))
14304 14305 14306 14307
        goto cleanup;

    def = NULL;

E
Eric Blake 已提交
14308 14309 14310
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0) {
        qemuDomainRemoveInactive(driver, vm);
        vm = NULL;
14311
        goto cleanup;
E
Eric Blake 已提交
14312
    }
14313 14314 14315

    if (qemuProcessAttach(conn, driver, vm, pid,
                          pidfile, monConfig, monJSON) < 0) {
E
Eric Blake 已提交
14316
        if (qemuDomainObjEndJob(driver, vm))
E
Eric Blake 已提交
14317 14318
            qemuDomainRemoveInactive(driver, vm);
        vm = NULL;
14319
        monConfig = NULL;
E
Eric Blake 已提交
14320
        goto cleanup;
14321 14322 14323 14324 14325
    }

    monConfig = NULL;

    dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
E
Eric Blake 已提交
14326 14327
    if (dom)
        dom->id = vm->def->id;
14328

E
Eric Blake 已提交
14329
    if (!qemuDomainObjEndJob(driver, vm))
14330 14331 14332 14333 14334 14335
        vm = NULL;

cleanup:
    virDomainDefFree(def);
    virDomainChrSourceDefFree(monConfig);
    if (vm)
14336
        virObjectUnlock(vm);
14337
    VIR_FREE(pidfile);
14338
    virObjectUnref(caps);
E
Eric Blake 已提交
14339
    virObjectUnref(qemuCaps);
14340 14341 14342 14343
    return dom;
}


14344 14345
static int
qemuDomainOpenConsole(virDomainPtr dom,
14346
                      const char *dev_name,
14347 14348 14349 14350 14351
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
14352
    size_t i;
14353
    virDomainChrDefPtr chr = NULL;
14354
    qemuDomainObjPrivatePtr priv;
14355

14356 14357
    virCheckFlags(VIR_DOMAIN_CONSOLE_SAFE |
                  VIR_DOMAIN_CONSOLE_FORCE, -1);
14358

14359
    if (!(vm = qemuDomObjFromDomain(dom)))
14360 14361
        goto cleanup;

14362 14363 14364
    if (virDomainOpenConsoleEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

14365
    if (!virDomainObjIsActive(vm)) {
14366 14367
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
14368 14369 14370
        goto cleanup;
    }

14371 14372
    priv = vm->privateData;

14373
    if (dev_name) {
14374
        for (i = 0; !chr && i < vm->def->nconsoles; i++) {
14375 14376 14377 14378
            if (vm->def->consoles[i]->info.alias &&
                STREQ(dev_name, vm->def->consoles[i]->info.alias))
                chr = vm->def->consoles[i];
        }
14379
        for (i = 0; !chr && i < vm->def->nserials; i++) {
14380
            if (STREQ(dev_name, vm->def->serials[i]->info.alias))
14381 14382
                chr = vm->def->serials[i];
        }
14383
        for (i = 0; !chr && i < vm->def->nparallels; i++) {
14384
            if (STREQ(dev_name, vm->def->parallels[i]->info.alias))
14385 14386 14387
                chr = vm->def->parallels[i];
        }
    } else {
14388 14389
        if (vm->def->nconsoles)
            chr = vm->def->consoles[0];
14390 14391 14392 14393 14394
        else if (vm->def->nserials)
            chr = vm->def->serials[0];
    }

    if (!chr) {
14395 14396 14397
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("cannot find character device %s"),
                       NULLSTR(dev_name));
14398 14399 14400
        goto cleanup;
    }

14401
    if (chr->source.type != VIR_DOMAIN_CHR_TYPE_PTY) {
14402 14403 14404
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("character device %s is not using a PTY"),
                       NULLSTR(dev_name));
14405 14406 14407
        goto cleanup;
    }

14408
    /* handle mutually exclusive access to console devices */
14409
    ret = virChrdevOpen(priv->devs,
14410
                        &chr->source,
14411 14412
                        st,
                        (flags & VIR_DOMAIN_CONSOLE_FORCE) != 0);
14413 14414

    if (ret == 1) {
14415 14416
        virReportError(VIR_ERR_OPERATION_FAILED, "%s",
                       _("Active console session exists for this domain"));
14417 14418
        ret = -1;
    }
14419 14420 14421

cleanup:
    if (vm)
14422
        virObjectUnlock(vm);
14423 14424 14425
    return ret;
}

14426 14427 14428 14429 14430 14431 14432 14433
static int
qemuDomainOpenChannel(virDomainPtr dom,
                      const char *name,
                      virStreamPtr st,
                      unsigned int flags)
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
14434
    size_t i;
14435 14436 14437 14438 14439 14440 14441 14442
    virDomainChrDefPtr chr = NULL;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(VIR_DOMAIN_CHANNEL_FORCE, -1);

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

14443 14444 14445
    if (virDomainOpenChannelEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

14446 14447 14448 14449 14450 14451 14452 14453 14454
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto cleanup;
    }

    priv = vm->privateData;

    if (name) {
14455
        for (i = 0; !chr && i < vm->def->nchannels; i++) {
14456 14457 14458 14459 14460 14461 14462 14463 14464 14465 14466 14467 14468 14469 14470 14471 14472 14473 14474 14475 14476 14477 14478 14479 14480 14481 14482 14483 14484 14485 14486 14487 14488 14489 14490 14491 14492 14493 14494 14495 14496
            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)
14497
        virObjectUnlock(vm);
14498 14499 14500
    return ret;
}

E
Eric Blake 已提交
14501
static char *
14502
qemuDiskPathToAlias(virDomainObjPtr vm, const char *path, int *idxret)
E
Eric Blake 已提交
14503
{
14504
    int idx;
14505
    char *ret = NULL;
14506
    virDomainDiskDefPtr disk;
14507

14508 14509
    idx = virDomainDiskIndexByName(vm->def, path, true);
    if (idx < 0)
14510
        goto cleanup;
14511

14512 14513 14514
    disk = vm->def->disks[idx];
    if (idxret)
        *idxret = idx;
14515

14516
    if (disk->src) {
14517
        if (virAsprintf(&ret, "drive-%s", disk->info.alias) < 0)
14518
            return NULL;
14519 14520
    }

14521
cleanup:
14522
    if (!ret) {
14523 14524
        virReportError(VIR_ERR_INVALID_ARG,
                       "%s", _("No device found for specified path"));
14525 14526 14527 14528
    }
    return ret;
}

14529 14530 14531 14532
/* 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 已提交
14533
qemuDomainBlockPivot(virConnectPtr conn,
14534
                     virQEMUDriverPtr driver, virDomainObjPtr vm,
14535 14536
                     const char *device, virDomainDiskDefPtr disk)
{
14537
    int ret = -1, rc;
14538 14539 14540
    qemuDomainObjPrivatePtr priv = vm->privateData;
    virDomainBlockJobInfo info;
    const char *format = virStorageFileFormatTypeToString(disk->mirrorFormat);
E
Eric Blake 已提交
14541
    bool resume = false;
14542 14543 14544
    char *oldsrc = NULL;
    int oldformat;
    virStorageFileMetadataPtr oldchain = NULL;
14545
    virQEMUDriverConfigPtr cfg = virQEMUDriverGetConfig(driver);
14546 14547 14548

    /* Probe the status, if needed.  */
    if (!disk->mirroring) {
14549
        qemuDomainObjEnterMonitor(driver, vm);
14550
        rc = qemuMonitorBlockJob(priv->mon, device, NULL, 0, &info,
14551
                                  BLOCK_JOB_INFO, true);
14552
        qemuDomainObjExitMonitor(driver, vm);
14553
        if (rc < 0)
14554 14555 14556 14557 14558 14559
            goto cleanup;
        if (!virDomainObjIsActive(vm)) {
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                           _("domain is not running"));
            goto cleanup;
        }
14560
        if (rc == 1 && info.cur == info.end &&
14561 14562 14563 14564 14565 14566 14567 14568 14569 14570 14571
            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 已提交
14572 14573 14574 14575 14576 14577 14578 14579 14580 14581 14582 14583 14584 14585 14586 14587 14588 14589 14590 14591 14592 14593 14594
    /* 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;
        }
    }

14595 14596 14597 14598 14599 14600 14601 14602 14603 14604 14605 14606 14607 14608 14609 14610 14611 14612 14613
    /* 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;
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0) {
        disk->src = oldsrc;
        disk->format = oldformat;
        disk->backingChain = oldchain;
        goto cleanup;
    }
    if (disk->mirrorFormat && disk->mirrorFormat != VIR_STORAGE_FILE_RAW &&
14614
        (virDomainLockDiskAttach(driver->lockManager, cfg->uri,
14615
                                 vm, disk) < 0 ||
14616
         qemuSetupDiskCgroup(vm, disk) < 0 ||
14617 14618 14619 14620 14621 14622 14623 14624
         virSecurityManagerSetImageLabel(driver->securityManager, vm->def,
                                         disk) < 0)) {
        disk->src = oldsrc;
        disk->format = oldformat;
        disk->backingChain = oldchain;
        goto cleanup;
    }

14625
    /* Attempt the pivot.  */
14626
    qemuDomainObjEnterMonitor(driver, vm);
14627
    ret = qemuMonitorDrivePivot(priv->mon, device, disk->mirror, format);
14628
    qemuDomainObjExitMonitor(driver, vm);
14629 14630 14631 14632 14633 14634 14635 14636 14637

    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.  */
14638 14639
        VIR_FREE(oldsrc);
        virStorageFileFreeMetadata(oldchain);
14640 14641 14642 14643 14644 14645 14646 14647 14648 14649
        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.  */
14650 14651 14652 14653
        disk->src = oldsrc;
        disk->format = oldformat;
        virStorageFileFreeMetadata(disk->backingChain);
        disk->backingChain = oldchain;
14654 14655
        VIR_FREE(disk->mirror);
    }
14656 14657
    disk->mirrorFormat = VIR_STORAGE_FILE_NONE;
    disk->mirroring = false;
14658 14659

cleanup:
E
Eric Blake 已提交
14660 14661 14662
    if (resume && virDomainObjIsActive(vm) &&
        qemuProcessStartCPUs(driver, vm, conn,
                             VIR_DOMAIN_RUNNING_UNPAUSED,
14663
                             QEMU_ASYNC_JOB_NONE) < 0) {
14664
        virObjectEventPtr event = NULL;
14665
        event = virDomainEventLifecycleNewFromObj(vm,
14666 14667 14668 14669 14670 14671 14672 14673
                                         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 已提交
14674
    }
14675
    virObjectUnref(cfg);
14676 14677 14678
    return ret;
}

14679
static int
14680 14681 14682
qemuDomainBlockJobImpl(virDomainObjPtr vm,
                       virConnectPtr conn,
                       const char *path, const char *base,
14683
                       unsigned long bandwidth, virDomainBlockJobInfoPtr info,
14684
                       int mode, unsigned int flags)
14685
{
14686
    virQEMUDriverPtr driver = conn->privateData;
14687
    qemuDomainObjPrivatePtr priv;
E
Eric Blake 已提交
14688
    char *device = NULL;
14689
    int ret = -1;
14690
    bool async = false;
14691
    virObjectEventPtr event = NULL;
14692 14693
    int idx;
    virDomainDiskDefPtr disk;
14694

14695
    if (!virDomainObjIsActive(vm)) {
14696 14697
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
14698 14699 14700
        goto cleanup;
    }

14701
    priv = vm->privateData;
14702
    if (virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC)) {
14703
        async = true;
14704
    } else if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_SYNC)) {
14705 14706
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block jobs not supported with this QEMU binary"));
14707 14708
        goto cleanup;
    } else if (base) {
14709 14710 14711
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("partial block pull not supported with this "
                         "QEMU binary"));
14712
        goto cleanup;
14713
    } else if (mode == BLOCK_JOB_PULL && bandwidth) {
14714 14715 14716
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("setting bandwidth at start of block pull not "
                         "supported with this QEMU binary"));
14717
        goto cleanup;
14718
    }
14719

14720 14721 14722 14723 14724 14725 14726 14727 14728
    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;
    }

14729 14730
    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device)
14731
        goto endjob;
14732
    disk = vm->def->disks[idx];
14733

E
Eric Blake 已提交
14734 14735 14736 14737
    if (mode == BLOCK_JOB_PULL && disk->mirror) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
                       _("disk '%s' already in active block copy job"),
                       disk->dst);
14738
        goto endjob;
E
Eric Blake 已提交
14739
    }
14740 14741 14742 14743 14744 14745
    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);
14746 14747 14748
        goto endjob;
    }

14749 14750
    if (disk->mirror && mode == BLOCK_JOB_ABORT &&
        (flags & VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT)) {
14751
        ret = qemuDomainBlockPivot(conn, driver, vm, device, disk);
14752 14753 14754
        goto endjob;
    }

14755
    qemuDomainObjEnterMonitor(driver, vm);
14756
    /* XXX - libvirt should really be tracking the backing file chain
14757 14758
     * itself, and validating that base is on the chain, rather than
     * relying on qemu to do this.  */
14759 14760
    ret = qemuMonitorBlockJob(priv->mon, device, base, bandwidth, info, mode,
                              async);
14761
    qemuDomainObjExitMonitor(driver, vm);
14762 14763 14764
    if (ret < 0)
        goto endjob;

14765 14766 14767 14768 14769 14770
    /* 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;

14771 14772 14773 14774 14775 14776 14777 14778 14779
    /* 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;
    }

14780 14781 14782 14783 14784 14785 14786 14787 14788 14789 14790 14791 14792 14793 14794 14795 14796 14797 14798
    /* 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;

14799
                qemuDomainObjEnterMonitor(driver, vm);
14800 14801
                ret = qemuMonitorBlockJob(priv->mon, device, NULL, 0, &dummy,
                                          BLOCK_JOB_INFO, async);
14802
                qemuDomainObjExitMonitor(driver, vm);
14803 14804 14805 14806

                if (ret <= 0)
                    break;

14807
                virObjectUnlock(vm);
14808 14809 14810

                nanosleep(&ts, NULL);

14811
                virObjectLock(vm);
14812 14813

                if (!virDomainObjIsActive(vm)) {
14814 14815
                    virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                                   _("domain is not running"));
14816 14817 14818 14819 14820 14821
                    ret = -1;
                    break;
                }
            }
        }
    }
14822 14823

endjob:
E
Eric Blake 已提交
14824
    if (!qemuDomainObjEndJob(driver, vm)) {
14825 14826 14827 14828 14829 14830 14831
        vm = NULL;
        goto cleanup;
    }

cleanup:
    VIR_FREE(device);
    if (vm)
14832
        virObjectUnlock(vm);
14833 14834
    if (event)
        qemuDomainEventQueue(driver, event);
14835 14836 14837 14838 14839 14840
    return ret;
}

static int
qemuDomainBlockJobAbort(virDomainPtr dom, const char *path, unsigned int flags)
{
14841 14842
    virDomainObjPtr vm;

14843 14844
    virCheckFlags(VIR_DOMAIN_BLOCK_JOB_ABORT_ASYNC |
                  VIR_DOMAIN_BLOCK_JOB_ABORT_PIVOT, -1);
14845 14846 14847 14848 14849 14850 14851 14852 14853 14854

    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,
14855
                                  flags);
14856 14857 14858 14859 14860 14861
}

static int
qemuDomainGetBlockJobInfo(virDomainPtr dom, const char *path,
                           virDomainBlockJobInfoPtr info, unsigned int flags)
{
14862
    virDomainObjPtr vm;
14863
    virCheckFlags(0, -1);
14864 14865 14866 14867 14868 14869 14870 14871 14872 14873

    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,
14874
                                  flags);
14875 14876 14877 14878 14879 14880
}

static int
qemuDomainBlockJobSetSpeed(virDomainPtr dom, const char *path,
                           unsigned long bandwidth, unsigned int flags)
{
14881
    virDomainObjPtr vm;
14882
    virCheckFlags(0, -1);
14883 14884 14885 14886 14887 14888 14889 14890 14891 14892

    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,
14893
                                  BLOCK_JOB_SPEED, flags);
14894 14895
}

14896
static int
14897 14898 14899
qemuDomainBlockCopy(virDomainObjPtr vm,
                    virConnectPtr conn,
                    const char *path,
14900 14901 14902
                    const char *dest, const char *format,
                    unsigned long bandwidth, unsigned int flags)
{
14903
    virQEMUDriverPtr driver = conn->privateData;
14904 14905
    qemuDomainObjPrivatePtr priv;
    char *device = NULL;
14906
    virDomainDiskDefPtr disk = NULL;
14907 14908
    int ret = -1;
    int idx;
14909
    struct stat st;
14910 14911
    bool need_unlink = false;
    char *mirror = NULL;
14912
    virQEMUDriverConfigPtr cfg = NULL;
14913 14914

    /* Preliminaries: find the disk we are editing, sanity checks */
14915 14916
    virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
                  VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT, -1);
14917 14918

    priv = vm->privateData;
14919
    cfg = virQEMUDriverGetConfig(driver);
14920

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

14924 14925 14926
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
14927
        goto endjob;
14928 14929 14930 14931
    }

    device = qemuDiskPathToAlias(vm, path, &idx);
    if (!device) {
14932
        goto endjob;
14933 14934 14935 14936 14937 14938
    }
    disk = vm->def->disks[idx];
    if (disk->mirror) {
        virReportError(VIR_ERR_BLOCK_COPY_ACTIVE,
                       _("disk '%s' already in active block copy job"),
                       disk->dst);
14939
        goto endjob;
14940 14941
    }

14942 14943
    if (!(virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_DRIVE_MIRROR) &&
          virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCKJOB_ASYNC))) {
14944 14945
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
                       _("block copy is not supported with this QEMU binary"));
14946
        goto endjob;
14947 14948 14949 14950 14951 14952 14953 14954 14955 14956
    }
    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;
    }
14957

14958 14959 14960 14961 14962 14963 14964 14965 14966 14967 14968 14969 14970 14971
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
        goto endjob;

    if ((flags & VIR_DOMAIN_BLOCK_REBASE_SHALLOW) &&
        STREQ_NULLABLE(format, "raw") &&
        disk->backingChain->backingStore) {
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("disk '%s' has backing file, so raw shallow copy "
                         "is not possible"),
                       disk->dst);
        goto endjob;
    }

    /* Prepare the destination file.  */
14972 14973 14974 14975 14976 14977 14978 14979 14980 14981 14982 14983 14984 14985 14986 14987 14988 14989 14990 14991
    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;
    }

14992
    if (!(flags & VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT)) {
14993
        int fd = qemuOpenFile(driver, vm, dest, O_WRONLY | O_TRUNC | O_CREAT,
14994 14995 14996 14997 14998
                              &need_unlink, NULL);
        if (fd < 0)
            goto endjob;
        VIR_FORCE_CLOSE(fd);
        if (!format)
14999
            disk->mirrorFormat = disk->format;
15000
    } else if (format) {
15001 15002 15003 15004 15005 15006
        disk->mirrorFormat = virStorageFileFormatTypeFromString(format);
        if (disk->mirrorFormat <= 0) {
            virReportError(VIR_ERR_INVALID_ARG, _("unrecognized format '%s'"),
                           format);
            goto endjob;
        }
15007 15008 15009 15010 15011
    } 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.  */
15012 15013
        disk->mirrorFormat = virStorageFileProbeFormat(dest, cfg->user,
                                                       cfg->group);
15014 15015 15016
    }
    if (!format && disk->mirrorFormat > 0)
        format = virStorageFileFormatTypeToString(disk->mirrorFormat);
15017
    if (VIR_STRDUP(mirror, dest) < 0)
15018 15019
        goto endjob;

15020
    if (qemuDomainPrepareDiskChainElement(driver, vm, disk, dest,
15021
                                          VIR_DISK_CHAIN_READ_WRITE) < 0) {
15022
        qemuDomainPrepareDiskChainElement(driver, vm, disk, dest,
15023 15024 15025 15026
                                          VIR_DISK_CHAIN_NO_ACCESS);
        goto endjob;
    }

15027 15028 15029 15030
    /* Actually start the mirroring */
    qemuDomainObjEnterMonitor(driver, vm);
    ret = qemuMonitorDriveMirror(priv->mon, device, dest, format, bandwidth,
                                 flags);
15031
    virDomainAuditDisk(vm, NULL, dest, "mirror", ret >= 0);
15032
    qemuDomainObjExitMonitor(driver, vm);
15033
    if (ret < 0) {
15034
        qemuDomainPrepareDiskChainElement(driver, vm, disk, dest,
15035 15036 15037 15038 15039 15040 15041 15042
                                          VIR_DISK_CHAIN_NO_ACCESS);
        goto endjob;
    }

    /* Update vm in place to match changes.  */
    need_unlink = false;
    disk->mirror = mirror;
    mirror = NULL;
15043 15044

endjob:
15045 15046
    if (need_unlink && unlink(dest))
        VIR_WARN("unable to unlink just-created %s", dest);
15047
    if (ret < 0 && disk)
15048
        disk->mirrorFormat = VIR_STORAGE_FILE_NONE;
15049
    VIR_FREE(mirror);
E
Eric Blake 已提交
15050
    if (!qemuDomainObjEndJob(driver, vm))
15051 15052 15053 15054 15055
        vm = NULL;

cleanup:
    VIR_FREE(device);
    if (vm)
15056
        virObjectUnlock(vm);
15057
    virObjectUnref(cfg);
15058 15059 15060
    return ret;
}

15061
static int
15062 15063
qemuDomainBlockRebase(virDomainPtr dom, const char *path, const char *base,
                      unsigned long bandwidth, unsigned int flags)
15064
{
15065 15066
    virDomainObjPtr vm;

15067
    virCheckFlags(VIR_DOMAIN_BLOCK_REBASE_SHALLOW |
15068
                  VIR_DOMAIN_BLOCK_REBASE_REUSE_EXT |
15069 15070 15071
                  VIR_DOMAIN_BLOCK_REBASE_COPY |
                  VIR_DOMAIN_BLOCK_REBASE_COPY_RAW, -1);

15072 15073 15074 15075 15076 15077 15078 15079
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;

    if (virDomainBlockRebaseEnsureACL(dom->conn, vm->def) < 0) {
        virObjectUnlock(vm);
        return -1;
    }

15080 15081 15082 15083 15084 15085
    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);
15086
        return qemuDomainBlockCopy(vm, dom->conn, path, base, format, bandwidth, flags);
15087 15088
    }

15089
    return qemuDomainBlockJobImpl(vm, dom->conn, path, base, bandwidth, NULL,
15090
                                  BLOCK_JOB_PULL, flags);
15091
}
15092

15093 15094 15095 15096
static int
qemuDomainBlockPull(virDomainPtr dom, const char *path, unsigned long bandwidth,
                    unsigned int flags)
{
15097
    virDomainObjPtr vm;
15098
    virCheckFlags(0, -1);
15099 15100 15101 15102 15103 15104 15105 15106 15107 15108

    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,
15109
                                  BLOCK_JOB_PULL, flags);
15110 15111
}

15112 15113 15114 15115 15116 15117

static int
qemuDomainBlockCommit(virDomainPtr dom, const char *path, const char *base,
                      const char *top, unsigned long bandwidth,
                      unsigned int flags)
{
15118
    virQEMUDriverPtr driver = dom->conn->privateData;
15119 15120 15121 15122 15123
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm = NULL;
    char *device = NULL;
    int ret = -1;
    int idx;
E
Eric Blake 已提交
15124
    virDomainDiskDefPtr disk = NULL;
15125 15126 15127 15128
    const char *top_canon = NULL;
    virStorageFileMetadataPtr top_meta = NULL;
    const char *top_parent = NULL;
    const char *base_canon = NULL;
E
Eric Blake 已提交
15129
    bool clean_access = false;
15130

15131
    virCheckFlags(VIR_DOMAIN_BLOCK_COMMIT_SHALLOW, -1);
15132 15133 15134 15135 15136

    if (!(vm = qemuDomObjFromDomain(dom)))
        goto cleanup;
    priv = vm->privateData;

15137 15138 15139
    if (virDomainBlockCommitEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

15140 15141 15142 15143 15144 15145 15146 15147
    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;
    }
15148
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_BLOCK_COMMIT)) {
15149 15150 15151 15152 15153 15154 15155 15156 15157 15158 15159 15160 15161 15162 15163 15164
        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;
    }
15165 15166
    if (qemuDomainDetermineDiskChain(driver, disk, false) < 0)
        goto endjob;
15167

15168 15169 15170 15171 15172 15173 15174 15175 15176 15177 15178 15179 15180 15181 15182 15183 15184 15185 15186 15187 15188 15189 15190 15191 15192 15193 15194 15195 15196 15197 15198 15199 15200 15201 15202 15203 15204 15205 15206
    if (!top) {
        top_canon = disk->src;
        top_meta = disk->backingChain;
    } else if (!(top_canon = virStorageFileChainLookup(disk->backingChain,
                                                       disk->src,
                                                       top, &top_meta,
                                                       &top_parent))) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("could not find top '%s' in chain for '%s'"),
                       top, path);
        goto endjob;
    }
    if (!top_meta || !top_meta->backingStore) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("top '%s' in chain for '%s' has no backing file"),
                       top, path);
        goto endjob;
    }
    if (!base && (flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW)) {
        base_canon = top_meta->backingStore;
    } else if (!(base_canon = virStorageFileChainLookup(top_meta, top_canon,
                                                        base, NULL, NULL))) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("could not find base '%s' below '%s' in chain "
                         "for '%s'"),
                       base ? base : "(default)", top_canon, path);
        goto endjob;
    }
    /* Note that this code exploits the fact that
     * virStorageFileChainLookup guarantees a simple pointer
     * comparison will work, rather than needing full-blown STREQ.  */
    if ((flags & VIR_DOMAIN_BLOCK_COMMIT_SHALLOW) &&
        base_canon != top_meta->backingStore) {
        virReportError(VIR_ERR_INVALID_ARG,
                       _("base '%s' is not immediately below '%s' in chain "
                         "for '%s'"),
                       base, top_canon, path);
        goto endjob;
    }
15207

15208 15209 15210 15211 15212 15213 15214
    /* 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 已提交
15215
    clean_access = true;
15216
    if (qemuDomainPrepareDiskChainElement(driver, vm, disk, base_canon,
15217 15218
                                          VIR_DISK_CHAIN_READ_WRITE) < 0 ||
        (top_parent && top_parent != disk->src &&
15219
         qemuDomainPrepareDiskChainElement(driver, vm, disk,
15220 15221 15222 15223 15224
                                           top_parent,
                                           VIR_DISK_CHAIN_READ_WRITE) < 0))
        goto endjob;

    /* Start the commit operation.  */
15225
    qemuDomainObjEnterMonitor(driver, vm);
15226 15227
    ret = qemuMonitorBlockCommit(priv->mon, device, top_canon, base_canon,
                                 bandwidth);
15228 15229 15230
    qemuDomainObjExitMonitor(driver, vm);

endjob:
E
Eric Blake 已提交
15231
    if (ret < 0 && clean_access) {
15232
        /* Revert access to read-only, if possible.  */
15233
        qemuDomainPrepareDiskChainElement(driver, vm, disk, base_canon,
15234 15235
                                          VIR_DISK_CHAIN_READ_ONLY);
        if (top_parent && top_parent != disk->src)
15236
            qemuDomainPrepareDiskChainElement(driver, vm, disk,
15237 15238 15239
                                              top_parent,
                                              VIR_DISK_CHAIN_READ_ONLY);
    }
E
Eric Blake 已提交
15240
    if (!qemuDomainObjEndJob(driver, vm))
15241 15242 15243 15244 15245
        vm = NULL;

cleanup:
    VIR_FREE(device);
    if (vm)
15246
        virObjectUnlock(vm);
15247 15248 15249
    return ret;
}

15250 15251 15252 15253 15254 15255
static int
qemuDomainOpenGraphics(virDomainPtr dom,
                       unsigned int idx,
                       int fd,
                       unsigned int flags)
{
15256
    virQEMUDriverPtr driver = dom->conn->privateData;
15257 15258 15259 15260 15261 15262 15263
    virDomainObjPtr vm = NULL;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;
    const char *protocol;

    virCheckFlags(VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH, -1);

15264 15265
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
15266

15267 15268 15269
    if (virDomainOpenGraphicsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

15270
    if (!virDomainObjIsActive(vm)) {
15271 15272
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
15273 15274 15275 15276 15277 15278
        goto cleanup;
    }

    priv = vm->privateData;

    if (idx >= vm->def->ngraphics) {
15279 15280
        virReportError(VIR_ERR_INTERNAL_ERROR,
                       _("No graphics backend with index %d"), idx);
15281 15282 15283 15284 15285 15286 15287 15288 15289 15290
        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:
15291 15292 15293
        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
                       _("Can only open VNC or SPICE graphics backends, not %s"),
                       virDomainGraphicsTypeToString(vm->def->graphics[idx]->type));
15294 15295 15296
        goto cleanup;
    }

15297 15298 15299 15300
    if (virSecurityManagerSetImageFDLabel(driver->securityManager, vm->def,
                                          fd) < 0)
        goto cleanup;

15301
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
15302
        goto cleanup;
15303
    qemuDomainObjEnterMonitor(driver, vm);
15304 15305
    ret = qemuMonitorOpenGraphics(priv->mon, protocol, fd, "graphicsfd",
                                  (flags & VIR_DOMAIN_OPEN_GRAPHICS_SKIPAUTH) != 0);
15306
    qemuDomainObjExitMonitor(driver, vm);
E
Eric Blake 已提交
15307
    if (!qemuDomainObjEndJob(driver, vm))
15308 15309 15310 15311
        vm = NULL;

cleanup:
    if (vm)
15312
        virObjectUnlock(vm);
15313 15314 15315
    return ret;
}

15316 15317 15318 15319 15320 15321 15322
static int
qemuDomainSetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int nparams,
                         unsigned int flags)
{
15323
    virQEMUDriverPtr driver = dom->conn->privateData;
15324 15325 15326 15327
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virDomainDefPtr persistentDef = NULL;
    virDomainBlockIoTuneInfo info;
E
Eric Blake 已提交
15328
    virDomainBlockIoTuneInfo *oldinfo;
15329
    char *device = NULL;
15330
    int ret = -1;
15331
    size_t i;
15332
    int idx = -1;
E
Eric Blake 已提交
15333 15334
    bool set_bytes = false;
    bool set_iops = false;
15335
    virQEMUDriverConfigPtr cfg = NULL;
15336
    virCapsPtr caps = NULL;
15337 15338 15339

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);
15340 15341 15342 15343 15344 15345 15346 15347 15348 15349 15350 15351 15352 15353
    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)
15354
        return -1;
15355 15356 15357

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

15358 15359 15360
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;

15361 15362 15363
    if (virDomainSetBlockIoTuneEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

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

15367
    priv = vm->privateData;
15368 15369
    cfg = virQEMUDriverGetConfig(driver);

15370
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
15371
        goto endjob;
15372

15373 15374
    if (!(device = qemuDiskPathToAlias(vm, disk, &idx)))
        goto endjob;
15375

15376
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
15377
                                        &persistentDef) < 0)
15378 15379 15380 15381 15382
        goto endjob;

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

15383 15384 15385 15386 15387 15388 15389
        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;
        }

15390 15391
        if (STREQ(param->field, VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC)) {
            info.total_bytes_sec = param->value.ul;
E
Eric Blake 已提交
15392
            set_bytes = true;
15393 15394 15395
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC)) {
            info.read_bytes_sec = param->value.ul;
E
Eric Blake 已提交
15396
            set_bytes = true;
15397 15398 15399
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC)) {
            info.write_bytes_sec = param->value.ul;
E
Eric Blake 已提交
15400
            set_bytes = true;
15401 15402 15403
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC)) {
            info.total_iops_sec = param->value.ul;
E
Eric Blake 已提交
15404
            set_iops = true;
15405 15406 15407
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC)) {
            info.read_iops_sec = param->value.ul;
E
Eric Blake 已提交
15408
            set_iops = true;
15409 15410 15411
        } else if (STREQ(param->field,
                         VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC)) {
            info.write_iops_sec = param->value.ul;
E
Eric Blake 已提交
15412
            set_iops = true;
15413 15414 15415 15416 15417
        }
    }

    if ((info.total_bytes_sec && info.read_bytes_sec) ||
        (info.total_bytes_sec && info.write_bytes_sec)) {
15418 15419
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("total and read/write of bytes_sec cannot be set at the same time"));
15420 15421 15422 15423 15424
        goto endjob;
    }

    if ((info.total_iops_sec && info.read_iops_sec) ||
        (info.total_iops_sec && info.write_iops_sec)) {
15425 15426
        virReportError(VIR_ERR_INVALID_ARG, "%s",
                       _("total and read/write of iops_sec cannot be set at the same time"));
15427 15428 15429 15430
        goto endjob;
    }

    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
15431 15432 15433 15434 15435 15436 15437
        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 已提交
15438 15439 15440 15441 15442 15443 15444 15445 15446 15447 15448 15449 15450 15451
        /* 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;
        }
15452
        qemuDomainObjEnterMonitor(driver, vm);
15453
        ret = qemuMonitorSetBlockIoThrottle(priv->mon, device, &info);
15454
        qemuDomainObjExitMonitor(driver, vm);
L
Lei Li 已提交
15455 15456
        if (ret < 0)
            goto endjob;
15457
        vm->def->disks[idx]->blkdeviotune = info;
15458 15459 15460
    }

    if (flags & VIR_DOMAIN_AFFECT_CONFIG) {
15461
        sa_assert(persistentDef);
E
Eric Blake 已提交
15462 15463 15464 15465 15466 15467 15468 15469 15470 15471 15472
        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;
        }
15473
        persistentDef->disks[idx]->blkdeviotune = info;
15474
        ret = virDomainSaveConfig(cfg->configDir, persistentDef);
15475
        if (ret < 0) {
15476
            virReportError(VIR_ERR_OPERATION_INVALID, "%s",
15477 15478 15479 15480 15481 15482
                           _("Write to config file failed"));
            goto endjob;
        }
    }

endjob:
15483
    if (!qemuDomainObjEndJob(driver, vm))
15484 15485 15486 15487 15488
        vm = NULL;

cleanup:
    VIR_FREE(device);
    if (vm)
15489
        virObjectUnlock(vm);
15490
    virObjectUnref(caps);
15491
    virObjectUnref(cfg);
15492 15493 15494 15495 15496 15497 15498 15499 15500 15501
    return ret;
}

static int
qemuDomainGetBlockIoTune(virDomainPtr dom,
                         const char *disk,
                         virTypedParameterPtr params,
                         int *nparams,
                         unsigned int flags)
{
15502
    virQEMUDriverPtr driver = dom->conn->privateData;
15503 15504 15505 15506
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virDomainDefPtr persistentDef = NULL;
    virDomainBlockIoTuneInfo reply;
15507
    char *device = NULL;
15508
    int ret = -1;
15509
    size_t i;
15510
    virCapsPtr caps = NULL;
15511 15512 15513 15514 15515 15516 15517 15518

    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;

15519 15520
    if (!(vm = qemuDomObjFromDomain(dom)))
        return -1;
15521

15522 15523 15524
    if (virDomainGetBlockIoTuneEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

15525 15526 15527
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

15528 15529 15530 15531 15532 15533 15534
    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;
    }

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

15538
    if (virDomainLiveConfigHelperMethod(caps, driver->xmlopt, vm, &flags,
15539
                                        &persistentDef) < 0)
15540 15541
        goto endjob;

15542 15543 15544 15545 15546
    device = qemuDiskPathToAlias(vm, disk, NULL);
    if (!device) {
        goto endjob;
    }

15547 15548
    if (flags & VIR_DOMAIN_AFFECT_LIVE) {
        priv = vm->privateData;
15549
        qemuDomainObjEnterMonitor(driver, vm);
15550
        ret = qemuMonitorGetBlockIoThrottle(priv->mon, device, &reply);
15551
        qemuDomainObjExitMonitor(driver, vm);
15552 15553 15554 15555 15556 15557 15558 15559 15560 15561 15562 15563 15564 15565
        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];

15566
        switch (i) {
15567
        case 0:
15568 15569 15570 15571
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_bytes_sec) < 0)
15572 15573 15574
                goto endjob;
            break;
        case 1:
15575 15576 15577 15578
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_bytes_sec) < 0)
15579 15580 15581
                goto endjob;
            break;
        case 2:
15582 15583 15584 15585
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_BYTES_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_bytes_sec) < 0)
15586 15587 15588
                goto endjob;
            break;
        case 3:
15589 15590 15591 15592
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_TOTAL_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.total_iops_sec) < 0)
15593 15594 15595
                goto endjob;
            break;
        case 4:
15596 15597 15598 15599
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_READ_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.read_iops_sec) < 0)
15600 15601 15602
                goto endjob;
            break;
        case 5:
15603 15604 15605 15606
            if (virTypedParameterAssign(param,
                                        VIR_DOMAIN_BLOCK_IOTUNE_WRITE_IOPS_SEC,
                                        VIR_TYPED_PARAM_ULLONG,
                                        reply.write_iops_sec) < 0)
15607 15608 15609 15610 15611 15612 15613 15614 15615 15616 15617 15618
                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 已提交
15619
    if (!qemuDomainObjEndJob(driver, vm))
15620 15621 15622 15623 15624
        vm = NULL;

cleanup:
    VIR_FREE(device);
    if (vm)
15625
        virObjectUnlock(vm);
15626
    virObjectUnref(caps);
15627 15628
    return ret;
}
15629

15630 15631 15632 15633 15634 15635
static int
qemuDomainGetDiskErrors(virDomainPtr dom,
                        virDomainDiskErrorPtr errors,
                        unsigned int nerrors,
                        unsigned int flags)
{
15636
    virQEMUDriverPtr driver = dom->conn->privateData;
15637 15638 15639 15640
    virDomainObjPtr vm = NULL;
    qemuDomainObjPrivatePtr priv;
    virHashTablePtr table = NULL;
    int ret = -1;
15641
    size_t i;
15642 15643 15644 15645
    int n = 0;

    virCheckFlags(0, -1);

15646
    if (!(vm = qemuDomObjFromDomain(dom)))
15647 15648 15649 15650
        goto cleanup;

    priv = vm->privateData;

15651 15652 15653
    if (virDomainGetDiskErrorsEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

15654 15655 15656 15657
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_QUERY) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
15658 15659
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
15660 15661 15662 15663 15664 15665 15666 15667 15668 15669 15670 15671 15672 15673 15674 15675 15676 15677 15678 15679 15680 15681 15682
        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;

15683
            if (VIR_STRDUP(errors[n].disk, disk->dst) < 0)
15684 15685 15686 15687 15688 15689 15690 15691 15692
                goto endjob;
            errors[n].error = info->io_status;
            n++;
        }
    }

    ret = n;

endjob:
E
Eric Blake 已提交
15693
    if (!qemuDomainObjEndJob(driver, vm))
15694 15695 15696 15697
        vm = NULL;

cleanup:
    if (vm)
15698
        virObjectUnlock(vm);
15699 15700 15701 15702 15703 15704 15705 15706
    virHashFree(table);
    if (ret < 0) {
        for (i = 0; i < n; i++)
            VIR_FREE(errors[i].disk);
    }
    return ret;
}

15707 15708 15709 15710
static int
qemuDomainSetMetadata(virDomainPtr dom,
                      int type,
                      const char *metadata,
15711 15712
                      const char *key,
                      const char *uri,
15713 15714
                      unsigned int flags)
{
15715
    virQEMUDriverPtr driver = dom->conn->privateData;
15716
    virDomainObjPtr vm;
15717
    virQEMUDriverConfigPtr cfg = NULL;
15718
    virCapsPtr caps = NULL;
15719
    int ret = -1;
15720 15721 15722 15723

    virCheckFlags(VIR_DOMAIN_AFFECT_LIVE |
                  VIR_DOMAIN_AFFECT_CONFIG, -1);

15724
    if (!(vm = qemuDomObjFromDomain(dom)))
15725
        return -1;
15726

15727 15728
    cfg = virQEMUDriverGetConfig(driver);

15729 15730 15731
    if (virDomainSetMetadataEnsureACL(dom->conn, vm->def, flags) < 0)
        goto cleanup;

15732 15733 15734
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

15735 15736
    ret = virDomainObjSetMetadata(vm, type, metadata, key, uri, caps,
                                  driver->xmlopt, cfg->configDir, flags);
15737 15738

cleanup:
15739
    virObjectUnlock(vm);
15740
    virObjectUnref(caps);
15741
    virObjectUnref(cfg);
15742 15743 15744 15745 15746 15747
    return ret;
}

static char *
qemuDomainGetMetadata(virDomainPtr dom,
                      int type,
15748
                      const char *uri,
15749 15750
                      unsigned int flags)
{
15751
    virQEMUDriverPtr driver = dom->conn->privateData;
15752
    virCapsPtr caps = NULL;
15753 15754 15755
    virDomainObjPtr vm;
    char *ret = NULL;

15756
    if (!(vm = qemuDomObjFromDomain(dom)))
15757
        return NULL;
15758

15759 15760 15761
    if (virDomainGetMetadataEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

15762 15763 15764
    if (!(caps = virQEMUDriverGetCapabilities(driver, false)))
        goto cleanup;

15765
    ret = virDomainObjGetMetadata(vm, type, uri, caps, driver->xmlopt, flags);
15766 15767

cleanup:
15768
    virObjectUnlock(vm);
15769
    virObjectUnref(caps);
15770 15771 15772
    return ret;
}

15773 15774
/* qemuDomainGetCPUStats() with start_cpu == -1 */
static int
15775
qemuDomainGetTotalcpuStats(virDomainObjPtr vm,
15776 15777 15778 15779 15780
                           virTypedParameterPtr params,
                           int nparams)
{
    unsigned long long cpu_time;
    int ret;
15781
    qemuDomainObjPrivatePtr priv = vm->privateData;
15782 15783

    if (nparams == 0) /* return supported number of params */
E
Eric Blake 已提交
15784
        return QEMU_NB_TOTAL_CPU_STAT_PARAM;
15785
    /* entry 0 is cputime */
15786
    ret = virCgroupGetCpuacctUsage(priv->cgroup, &cpu_time);
15787 15788 15789 15790 15791
    if (ret < 0) {
        virReportSystemError(-ret, "%s", _("unable to get cpu account"));
        return -1;
    }

E
Eric Blake 已提交
15792 15793 15794 15795 15796 15797 15798 15799
    if (virTypedParameterAssign(&params[0], VIR_DOMAIN_CPU_STATS_CPUTIME,
                                VIR_TYPED_PARAM_ULLONG, cpu_time) < 0)
        return -1;

    if (nparams > 1) {
        unsigned long long user;
        unsigned long long sys;

15800
        ret = virCgroupGetCpuacctStat(priv->cgroup, &user, &sys);
E
Eric Blake 已提交
15801 15802 15803 15804 15805 15806 15807 15808 15809 15810 15811 15812 15813 15814 15815 15816 15817 15818 15819 15820
        if (ret < 0) {
            virReportSystemError(-ret, "%s", _("unable to get cpu account"));
            return -1;
        }

        if (virTypedParameterAssign(&params[1],
                                    VIR_DOMAIN_CPU_STATS_USERTIME,
                                    VIR_TYPED_PARAM_ULLONG, user) < 0)
            return -1;
        if (nparams > 2 &&
            virTypedParameterAssign(&params[2],
                                    VIR_DOMAIN_CPU_STATS_SYSTEMTIME,
                                    VIR_TYPED_PARAM_ULLONG, sys) < 0)
            return -1;

        if (nparams > QEMU_NB_TOTAL_CPU_STAT_PARAM)
            nparams = QEMU_NB_TOTAL_CPU_STAT_PARAM;
    }

    return nparams;
15821 15822
}

15823 15824 15825 15826 15827 15828 15829 15830 15831 15832 15833 15834 15835 15836 15837
/* 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
15838
getSumVcpuPercpuStats(virDomainObjPtr vm,
15839 15840 15841 15842
                      unsigned long long *sum_cpu_time,
                      unsigned int num)
{
    int ret = -1;
15843
    size_t i;
15844
    char *buf = NULL;
15845
    qemuDomainObjPrivatePtr priv = vm->privateData;
15846 15847
    virCgroupPtr group_vcpu = NULL;

15848
    for (i = 0; i < priv->nvcpupids; i++) {
15849 15850
        char *pos;
        unsigned long long tmp;
15851
        size_t j;
15852

15853
        if (virCgroupNewVcpu(priv->cgroup, i, false, &group_vcpu) < 0)
15854 15855
            goto cleanup;

15856
        if (virCgroupGetCpuacctPercpuUsage(group_vcpu, &buf) < 0)
15857 15858 15859 15860 15861
            goto cleanup;

        pos = buf;
        for (j = 0; j < num; j++) {
            if (virStrToLong_ull(pos, &pos, 10, &tmp) < 0) {
15862 15863
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("cpuacct parse error"));
15864 15865 15866 15867 15868 15869 15870 15871 15872 15873 15874 15875 15876 15877 15878 15879
                goto cleanup;
            }
            sum_cpu_time[j] += tmp;
        }

        virCgroupFree(&group_vcpu);
        VIR_FREE(buf);
    }

    ret = 0;
cleanup:
    virCgroupFree(&group_vcpu);
    VIR_FREE(buf);
    return ret;
}

15880
static int
15881
qemuDomainGetPercpuStats(virDomainObjPtr vm,
15882 15883 15884 15885 15886 15887
                         virTypedParameterPtr params,
                         unsigned int nparams,
                         int start_cpu,
                         unsigned int ncpus)
{
    int rv = -1;
15888 15889
    size_t i;
    int id, max_id;
15890 15891
    char *pos;
    char *buf = NULL;
15892 15893 15894 15895
    unsigned long long *sum_cpu_time = NULL;
    unsigned long long *sum_cpu_pos;
    unsigned int n = 0;
    qemuDomainObjPrivatePtr priv = vm->privateData;
15896 15897
    virTypedParameterPtr ent;
    int param_idx;
15898
    unsigned long long cpu_time;
15899 15900 15901

    /* return the number of supported params */
    if (nparams == 0 && ncpus != 0)
15902
        return QEMU_NB_PER_CPU_STAT_PARAM;
15903

15904 15905 15906
    /* To parse account file, we need to know how many cpus are present.  */
    max_id = nodeGetCPUCount();
    if (max_id < 0)
15907 15908 15909
        return rv;

    if (ncpus == 0) { /* returns max cpu ID */
15910
        rv = max_id;
15911 15912 15913 15914
        goto cleanup;
    }

    if (start_cpu > max_id) {
15915 15916 15917
        virReportError(VIR_ERR_INVALID_ARG,
                       _("start_cpu %d larger than maximum of %d"),
                       start_cpu, max_id);
15918 15919 15920 15921
        goto cleanup;
    }

    /* we get percpu cputime accounting info. */
15922
    if (virCgroupGetCpuacctPercpuUsage(priv->cgroup, &buf))
15923 15924 15925
        goto cleanup;
    pos = buf;

15926 15927 15928
    /* return percpu cputime in index 0 */
    param_idx = 0;

15929
    /* number of cpus to compute */
15930 15931 15932
    if (start_cpu >= max_id - ncpus)
        id = max_id - 1;
    else
15933
        id = start_cpu + ncpus - 1;
15934

15935
    for (i = 0; i <= id; i++) {
15936
        if (virStrToLong_ull(pos, &pos, 10, &cpu_time) < 0) {
15937
            virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
15938
                           _("cpuacct parse error"));
15939
            goto cleanup;
15940 15941
        } else {
            n++;
15942 15943 15944
        }
        if (i < start_cpu)
            continue;
15945
        ent = &params[(i - start_cpu) * nparams + param_idx];
E
Eric Blake 已提交
15946 15947 15948
        if (virTypedParameterAssign(ent, VIR_DOMAIN_CPU_STATS_CPUTIME,
                                    VIR_TYPED_PARAM_ULLONG, cpu_time) < 0)
            goto cleanup;
15949
    }
15950 15951 15952 15953 15954 15955 15956

    /* return percpu vcputime in index 1 */
    if (++param_idx >= nparams) {
        rv = nparams;
        goto cleanup;
    }

15957
    if (VIR_ALLOC_N(sum_cpu_time, n) < 0)
15958
        goto cleanup;
15959
    if (getSumVcpuPercpuStats(vm, sum_cpu_time, n) < 0)
15960 15961 15962
        goto cleanup;

    sum_cpu_pos = sum_cpu_time;
15963
    for (i = 0; i <= id; i++) {
15964
        cpu_time = *(sum_cpu_pos++);
15965 15966 15967 15968 15969 15970 15971 15972 15973 15974
        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;
    }

15975 15976
    rv = param_idx + 1;
cleanup:
15977
    VIR_FREE(sum_cpu_time);
15978 15979 15980 15981 15982 15983 15984
    VIR_FREE(buf);
    return rv;
}


static int
qemuDomainGetCPUStats(virDomainPtr domain,
15985 15986 15987 15988 15989
                      virTypedParameterPtr params,
                      unsigned int nparams,
                      int start_cpu,
                      unsigned int ncpus,
                      unsigned int flags)
15990 15991 15992 15993
{
    virDomainObjPtr vm = NULL;
    int ret = -1;
    bool isActive;
15994
    qemuDomainObjPrivatePtr priv;
15995 15996 15997

    virCheckFlags(VIR_TYPED_PARAM_STRING_OKAY, -1);

15998 15999
    if (!(vm = qemuDomObjFromDomain(domain)))
        return -1;
16000

16001 16002
    priv = vm->privateData;

16003 16004 16005
    if (virDomainGetCPUStatsEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

16006 16007
    isActive = virDomainObjIsActive(vm);
    if (!isActive) {
16008 16009
        virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                       _("domain is not running"));
16010 16011 16012
        goto cleanup;
    }

16013
    if (!virCgroupHasController(priv->cgroup, VIR_CGROUP_CONTROLLER_CPUACCT)) {
16014 16015
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("cgroup CPUACCT controller is not mounted"));
16016 16017 16018 16019
        goto cleanup;
    }

    if (start_cpu == -1)
16020
        ret = qemuDomainGetTotalcpuStats(vm, params, nparams);
16021
    else
16022
        ret = qemuDomainGetPercpuStats(vm, params, nparams,
16023 16024 16025
                                       start_cpu, ncpus);
cleanup:
    if (vm)
16026
        virObjectUnlock(vm);
16027 16028 16029
    return ret;
}

16030 16031 16032 16033 16034 16035
static int
qemuDomainPMSuspendForDuration(virDomainPtr dom,
                               unsigned int target,
                               unsigned long long duration,
                               unsigned int flags)
{
16036
    virQEMUDriverPtr driver = dom->conn->privateData;
16037 16038 16039 16040 16041 16042 16043
    qemuDomainObjPrivatePtr priv;
    virDomainObjPtr vm;
    int ret = -1;

    virCheckFlags(0, -1);

    if (duration) {
16044 16045
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Duration not supported. Use 0 for now"));
16046 16047 16048 16049 16050 16051
        return -1;
    }

    if (!(target == VIR_NODE_SUSPEND_TARGET_MEM ||
          target == VIR_NODE_SUSPEND_TARGET_DISK ||
          target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
16052 16053 16054
        virReportError(VIR_ERR_INVALID_ARG,
                       _("Unknown suspend target: %u"),
                       target);
16055 16056 16057
        return -1;
    }

16058
    if (!(vm = qemuDomObjFromDomain(dom)))
16059 16060 16061 16062
        goto cleanup;

    priv = vm->privateData;

16063 16064 16065
    if (virDomainPMSuspendForDurationEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

16066
    if (!virDomainObjIsActive(vm)) {
16067 16068
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
16069 16070 16071
        goto cleanup;
    }

16072
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_WAKEUP) &&
16073 16074
        (target == VIR_NODE_SUSPEND_TARGET_MEM ||
         target == VIR_NODE_SUSPEND_TARGET_HYBRID)) {
16075 16076 16077
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("Unable to suspend domain due to "
                         "missing system_wakeup monitor command"));
O
Osier Yang 已提交
16078
        goto cleanup;
16079 16080
    }

16081 16082 16083 16084 16085 16086 16087 16088 16089 16090 16091 16092 16093 16094 16095 16096 16097
    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;
        }
    }

16098
    if (priv->agentError) {
16099 16100 16101
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                       _("QEMU guest agent is not "
                         "available due to an error"));
16102 16103 16104 16105
        goto cleanup;
    }

    if (!priv->agent) {
16106 16107
        virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s",
                       _("QEMU guest agent is not configured"));
16108 16109 16110 16111 16112 16113 16114
        goto cleanup;
    }

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

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

16120
    qemuDomainObjEnterAgent(vm);
16121
    ret = qemuAgentSuspend(priv->agent, target);
16122
    qemuDomainObjExitAgent(vm);
16123 16124

endjob:
E
Eric Blake 已提交
16125
    if (!qemuDomainObjEndJob(driver, vm))
16126 16127 16128 16129
        vm = NULL;

cleanup:
    if (vm)
16130
        virObjectUnlock(vm);
16131 16132 16133
    return ret;
}

16134 16135 16136 16137
static int
qemuDomainPMWakeup(virDomainPtr dom,
                   unsigned int flags)
{
16138
    virQEMUDriverPtr driver = dom->conn->privateData;
16139 16140 16141 16142 16143 16144
    virDomainObjPtr vm;
    int ret = -1;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, -1);

16145
    if (!(vm = qemuDomObjFromDomain(dom)))
16146 16147
        goto cleanup;

16148 16149 16150
    if (virDomainPMWakeupEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

16151 16152 16153 16154
    if (qemuDomainObjBeginJob(driver, vm, QEMU_JOB_MODIFY) < 0)
        goto cleanup;

    if (!virDomainObjIsActive(vm)) {
16155 16156
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
16157 16158 16159 16160 16161
        goto endjob;
    }

    priv = vm->privateData;

16162
    if (!virQEMUCapsGet(priv->qemuCaps, QEMU_CAPS_WAKEUP)) {
16163 16164 16165
       virReportError(VIR_ERR_OPERATION_INVALID, "%s",
                      _("Unable to wake up domain due to "
                        "missing system_wakeup monitor command"));
16166 16167 16168 16169 16170 16171 16172 16173
       goto endjob;
    }

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

endjob:
E
Eric Blake 已提交
16174
    if (!qemuDomainObjEndJob(driver, vm))
16175 16176 16177 16178
        vm = NULL;

cleanup:
    if (vm)
16179
        virObjectUnlock(vm);
16180 16181 16182
    return ret;
}

16183
static int
16184 16185 16186
qemuConnectListAllDomains(virConnectPtr conn,
                          virDomainPtr **domains,
                          unsigned int flags)
16187
{
16188
    virQEMUDriverPtr driver = conn->privateData;
16189 16190
    int ret = -1;

O
Osier Yang 已提交
16191
    virCheckFlags(VIR_CONNECT_LIST_DOMAINS_FILTERS_ALL, -1);
16192

16193 16194 16195
    if (virConnectListAllDomainsEnsureACL(conn) < 0)
        goto cleanup;

16196 16197
    ret = virDomainObjListExport(driver->domains, conn, domains,
                                 virConnectListAllDomainsCheckACL, flags);
16198

16199
cleanup:
16200 16201 16202
    return ret;
}

M
MATSUDA Daiki 已提交
16203
static char *
16204 16205 16206 16207
qemuDomainQemuAgentCommand(virDomainPtr domain,
                           const char *cmd,
                           int timeout,
                           unsigned int flags)
M
MATSUDA Daiki 已提交
16208
{
16209
    virQEMUDriverPtr driver = domain->conn->privateData;
M
MATSUDA Daiki 已提交
16210 16211 16212 16213 16214 16215 16216
    virDomainObjPtr vm;
    int ret = -1;
    char *result = NULL;
    qemuDomainObjPrivatePtr priv;

    virCheckFlags(0, NULL);

16217
    if (!(vm = qemuDomObjFromDomain(domain)))
M
MATSUDA Daiki 已提交
16218 16219 16220 16221
        goto cleanup;

    priv = vm->privateData;

16222 16223 16224
    if (virDomainQemuAgentCommandEnsureACL(domain->conn, vm->def) < 0)
        goto cleanup;

M
MATSUDA Daiki 已提交
16225 16226 16227 16228 16229 16230 16231
    if (!virDomainObjIsActive(vm)) {
        virReportError(VIR_ERR_OPERATION_INVALID,
                       "%s", _("domain is not running"));
        goto cleanup;
    }

    if (priv->agentError) {
16232 16233 16234
        virReportError(VIR_ERR_AGENT_UNRESPONSIVE, "%s",
                       _("QEMU guest agent is not "
                         "available due to an error"));
M
MATSUDA Daiki 已提交
16235 16236 16237 16238 16239 16240 16241 16242 16243 16244 16245 16246 16247 16248 16249 16250 16251 16252
        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;
    }

16253
    qemuDomainObjEnterAgent(vm);
M
MATSUDA Daiki 已提交
16254
    ret = qemuAgentArbitraryCommand(priv->agent, cmd, &result, timeout);
16255
    qemuDomainObjExitAgent(vm);
16256 16257
    if (ret < 0)
        VIR_FREE(result);
M
MATSUDA Daiki 已提交
16258 16259

endjob:
E
Eric Blake 已提交
16260
    if (!qemuDomainObjEndJob(driver, vm))
M
MATSUDA Daiki 已提交
16261 16262 16263 16264
        vm = NULL;

cleanup:
    if (vm)
16265
        virObjectUnlock(vm);
M
MATSUDA Daiki 已提交
16266 16267 16268
    return result;
}

M
Michal Privoznik 已提交
16269 16270 16271 16272 16273 16274
static int
qemuDomainFSTrim(virDomainPtr dom,
                 const char *mountPoint,
                 unsigned long long minimum,
                 unsigned int flags)
{
16275
    virQEMUDriverPtr driver = dom->conn->privateData;
M
Michal Privoznik 已提交
16276 16277 16278 16279 16280 16281 16282 16283 16284 16285 16286 16287 16288 16289 16290 16291 16292 16293
    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;

16294 16295 16296
    if (virDomainFSTrimEnsureACL(dom->conn, vm->def) < 0)
        goto cleanup;

M
Michal Privoznik 已提交
16297 16298 16299 16300 16301 16302 16303 16304 16305 16306 16307 16308 16309 16310 16311 16312 16313 16314 16315 16316 16317 16318 16319 16320 16321 16322 16323 16324
    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;
    }

16325
    qemuDomainObjEnterAgent(vm);
M
Michal Privoznik 已提交
16326
    ret = qemuAgentFSTrim(priv->agent, minimum);
16327
    qemuDomainObjExitAgent(vm);
M
Michal Privoznik 已提交
16328 16329

endjob:
E
Eric Blake 已提交
16330
    if (!qemuDomainObjEndJob(driver, vm))
M
Michal Privoznik 已提交
16331 16332 16333 16334
        vm = NULL;

cleanup:
    if (vm)
16335
        virObjectUnlock(vm);
M
Michal Privoznik 已提交
16336 16337 16338
    return ret;
}

16339 16340

static int
16341
qemuNodeGetInfo(virConnectPtr conn,
16342 16343
                virNodeInfoPtr nodeinfo)
{
16344 16345 16346
    if (virNodeGetInfoEnsureACL(conn) < 0)
        return -1;

16347 16348 16349 16350 16351
    return nodeGetInfo(nodeinfo);
}


static int
16352
qemuNodeGetCPUStats(virConnectPtr conn,
16353 16354 16355 16356 16357
                    int cpuNum,
                    virNodeCPUStatsPtr params,
                    int *nparams,
                    unsigned int flags)
{
16358 16359 16360
    if (virNodeGetCPUStatsEnsureACL(conn) < 0)
        return -1;

16361 16362 16363 16364 16365
    return nodeGetCPUStats(cpuNum, params, nparams, flags);
}


static int
16366
qemuNodeGetMemoryStats(virConnectPtr conn,
16367 16368 16369 16370 16371
                       int cellNum,
                       virNodeMemoryStatsPtr params,
                       int *nparams,
                       unsigned int flags)
{
16372 16373 16374
    if (virNodeGetMemoryStatsEnsureACL(conn) < 0)
        return -1;

16375 16376 16377 16378 16379
    return nodeGetMemoryStats(cellNum, params, nparams, flags);
}


static int
16380
qemuNodeGetCellsFreeMemory(virConnectPtr conn,
16381 16382 16383 16384
                           unsigned long long *freeMems,
                           int startCell,
                           int maxCells)
{
16385 16386 16387
    if (virNodeGetCellsFreeMemoryEnsureACL(conn) < 0)
        return -1;

16388 16389 16390 16391 16392
    return nodeGetCellsFreeMemory(freeMems, startCell, maxCells);
}


static unsigned long long
16393
qemuNodeGetFreeMemory(virConnectPtr conn)
16394
{
16395 16396 16397
    if (virNodeGetFreeMemoryEnsureACL(conn) < 0)
        return 0;

16398 16399 16400 16401 16402
    return nodeGetFreeMemory();
}


static int
16403
qemuNodeGetMemoryParameters(virConnectPtr conn,
16404 16405 16406 16407
                            virTypedParameterPtr params,
                            int *nparams,
                            unsigned int flags)
{
16408 16409 16410
    if (virNodeGetMemoryParametersEnsureACL(conn) < 0)
        return -1;

16411 16412 16413 16414 16415
    return nodeGetMemoryParameters(params, nparams, flags);
}


static int
16416
qemuNodeSetMemoryParameters(virConnectPtr conn,
16417 16418 16419 16420
                            virTypedParameterPtr params,
                            int nparams,
                            unsigned int flags)
{
16421 16422 16423
    if (virNodeSetMemoryParametersEnsureACL(conn) < 0)
        return -1;

16424 16425 16426 16427 16428
    return nodeSetMemoryParameters(params, nparams, flags);
}


static int
16429
qemuNodeGetCPUMap(virConnectPtr conn,
16430 16431 16432 16433
                  unsigned char **cpumap,
                  unsigned int *online,
                  unsigned int flags)
{
16434 16435 16436
    if (virNodeGetCPUMapEnsureACL(conn) < 0)
        return -1;

16437 16438 16439
    return nodeGetCPUMap(cpumap, online, flags);
}

16440 16441

static int
16442
qemuNodeSuspendForDuration(virConnectPtr conn,
16443 16444 16445 16446
                           unsigned int target,
                           unsigned long long duration,
                           unsigned int flags)
{
16447 16448 16449
    if (virNodeSuspendForDurationEnsureACL(conn) < 0)
        return -1;

16450 16451 16452
    return nodeSuspendForDuration(target, duration, flags);
}

16453 16454 16455 16456 16457 16458 16459 16460 16461 16462 16463 16464 16465
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);
}

16466

16467
static virDriver qemuDriver = {
16468
    .no = VIR_DRV_QEMU,
16469
    .name = QEMU_DRIVER_NAME,
16470 16471 16472 16473 16474
    .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 */
16475
    .connectGetHostname = qemuConnectGetHostname, /* 0.3.3 */
16476 16477
    .connectGetSysinfo = qemuConnectGetSysinfo, /* 0.8.8 */
    .connectGetMaxVcpus = qemuConnectGetMaxVcpus, /* 0.2.1 */
16478
    .nodeGetInfo = qemuNodeGetInfo, /* 0.2.0 */
16479 16480 16481 16482 16483
    .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 */
16484 16485 16486 16487 16488
    .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 */
16489
    .domainShutdown = qemuDomainShutdown, /* 0.2.0 */
16490
    .domainShutdownFlags = qemuDomainShutdownFlags, /* 0.9.10 */
16491
    .domainReboot = qemuDomainReboot, /* 0.9.3 */
16492
    .domainReset = qemuDomainReset, /* 0.9.7 */
16493 16494
    .domainDestroy = qemuDomainDestroy, /* 0.2.0 */
    .domainDestroyFlags = qemuDomainDestroyFlags, /* 0.9.4 */
16495
    .domainGetOSType = qemuDomainGetOSType, /* 0.2.2 */
16496
    .domainGetMaxMemory = qemuDomainGetMaxMemory, /* 0.4.2 */
16497 16498 16499
    .domainSetMaxMemory = qemuDomainSetMaxMemory, /* 0.4.2 */
    .domainSetMemory = qemuDomainSetMemory, /* 0.4.2 */
    .domainSetMemoryFlags = qemuDomainSetMemoryFlags, /* 0.9.0 */
16500 16501
    .domainSetMemoryParameters = qemuDomainSetMemoryParameters, /* 0.8.5 */
    .domainGetMemoryParameters = qemuDomainGetMemoryParameters, /* 0.8.5 */
16502
    .domainSetMemoryStatsPeriod = qemuDomainSetMemoryStatsPeriod, /* 1.1.1 */
16503 16504
    .domainSetBlkioParameters = qemuDomainSetBlkioParameters, /* 0.9.0 */
    .domainGetBlkioParameters = qemuDomainGetBlkioParameters, /* 0.9.0 */
16505
    .domainGetInfo = qemuDomainGetInfo, /* 0.2.0 */
16506
    .domainGetState = qemuDomainGetState, /* 0.9.2 */
16507
    .domainGetControlInfo = qemuDomainGetControlInfo, /* 0.9.3 */
16508 16509
    .domainSave = qemuDomainSave, /* 0.2.0 */
    .domainSaveFlags = qemuDomainSaveFlags, /* 0.9.4 */
16510
    .domainRestore = qemuDomainRestore, /* 0.2.0 */
16511
    .domainRestoreFlags = qemuDomainRestoreFlags, /* 0.9.4 */
16512 16513
    .domainSaveImageGetXMLDesc = qemuDomainSaveImageGetXMLDesc, /* 0.9.4 */
    .domainSaveImageDefineXML = qemuDomainSaveImageDefineXML, /* 0.9.4 */
16514
    .domainCoreDump = qemuDomainCoreDump, /* 0.7.0 */
16515
    .domainScreenshot = qemuDomainScreenshot, /* 0.9.2 */
16516 16517
    .domainSetVcpus = qemuDomainSetVcpus, /* 0.4.4 */
    .domainSetVcpusFlags = qemuDomainSetVcpusFlags, /* 0.8.5 */
16518 16519 16520 16521 16522 16523 16524 16525 16526
    .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 已提交
16527
    .domainGetSecurityLabelList = qemuDomainGetSecurityLabelList, /* 0.10.0 */
16528
    .nodeGetSecurityModel = qemuNodeGetSecurityModel, /* 0.6.1 */
16529
    .domainGetXMLDesc = qemuDomainGetXMLDesc, /* 0.2.0 */
16530 16531 16532 16533 16534 16535 16536
    .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 */
16537
    .domainUndefine = qemuDomainUndefine, /* 0.2.0 */
16538
    .domainUndefineFlags = qemuDomainUndefineFlags, /* 0.9.4 */
16539 16540 16541 16542 16543
    .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 */
16544 16545
    .domainGetAutostart = qemuDomainGetAutostart, /* 0.2.1 */
    .domainSetAutostart = qemuDomainSetAutostart, /* 0.2.1 */
16546 16547 16548 16549 16550
    .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 */
16551
    .domainMigratePerform = qemuDomainMigratePerform, /* 0.5.0 */
16552
    .domainBlockResize = qemuDomainBlockResize, /* 0.9.8 */
16553 16554
    .domainBlockStats = qemuDomainBlockStats, /* 0.4.1 */
    .domainBlockStatsFlags = qemuDomainBlockStatsFlags, /* 0.9.5 */
16555 16556 16557 16558
    .domainInterfaceStats = qemuDomainInterfaceStats, /* 0.4.1 */
    .domainMemoryStats = qemuDomainMemoryStats, /* 0.7.5 */
    .domainBlockPeek = qemuDomainBlockPeek, /* 0.4.4 */
    .domainMemoryPeek = qemuDomainMemoryPeek, /* 0.4.4 */
16559
    .domainGetBlockInfo = qemuDomainGetBlockInfo, /* 0.8.1 */
16560 16561 16562 16563
    .nodeGetCPUStats = qemuNodeGetCPUStats, /* 0.9.3 */
    .nodeGetMemoryStats = qemuNodeGetMemoryStats, /* 0.9.3 */
    .nodeGetCellsFreeMemory = qemuNodeGetCellsFreeMemory, /* 0.4.4 */
    .nodeGetFreeMemory = qemuNodeGetFreeMemory, /* 0.4.4 */
16564 16565
    .connectDomainEventRegister = qemuConnectDomainEventRegister, /* 0.5.0 */
    .connectDomainEventDeregister = qemuConnectDomainEventDeregister, /* 0.5.0 */
16566 16567 16568
    .domainMigratePrepare2 = qemuDomainMigratePrepare2, /* 0.5.0 */
    .domainMigrateFinish2 = qemuDomainMigrateFinish2, /* 0.5.0 */
    .nodeDeviceDettach = qemuNodeDeviceDettach, /* 0.6.1 */
16569
    .nodeDeviceDetachFlags = qemuNodeDeviceDetachFlags, /* 1.0.5 */
16570 16571 16572
    .nodeDeviceReAttach = qemuNodeDeviceReAttach, /* 0.6.1 */
    .nodeDeviceReset = qemuNodeDeviceReset, /* 0.6.1 */
    .domainMigratePrepareTunnel = qemuDomainMigratePrepareTunnel, /* 0.7.2 */
16573 16574
    .connectIsEncrypted = qemuConnectIsEncrypted, /* 0.7.3 */
    .connectIsSecure = qemuConnectIsSecure, /* 0.7.3 */
16575 16576 16577
    .domainIsActive = qemuDomainIsActive, /* 0.7.3 */
    .domainIsPersistent = qemuDomainIsPersistent, /* 0.7.3 */
    .domainIsUpdated = qemuDomainIsUpdated, /* 0.8.6 */
16578 16579
    .connectCompareCPU = qemuConnectCompareCPU, /* 0.7.5 */
    .connectBaselineCPU = qemuConnectBaselineCPU, /* 0.7.7 */
16580
    .domainGetJobInfo = qemuDomainGetJobInfo, /* 0.7.7 */
16581
    .domainGetJobStats = qemuDomainGetJobStats, /* 1.0.3 */
16582 16583
    .domainAbortJob = qemuDomainAbortJob, /* 0.7.7 */
    .domainMigrateSetMaxDowntime = qemuDomainMigrateSetMaxDowntime, /* 0.8.0 */
16584 16585
    .domainMigrateGetCompressionCache = qemuDomainMigrateGetCompressionCache, /* 1.0.3 */
    .domainMigrateSetCompressionCache = qemuDomainMigrateSetCompressionCache, /* 1.0.3 */
16586
    .domainMigrateSetMaxSpeed = qemuDomainMigrateSetMaxSpeed, /* 0.9.0 */
16587
    .domainMigrateGetMaxSpeed = qemuDomainMigrateGetMaxSpeed, /* 0.9.5 */
16588 16589
    .connectDomainEventRegisterAny = qemuConnectDomainEventRegisterAny, /* 0.8.0 */
    .connectDomainEventDeregisterAny = qemuConnectDomainEventDeregisterAny, /* 0.8.0 */
16590 16591 16592 16593 16594 16595 16596
    .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 */
16597
    .domainListAllSnapshots = qemuDomainListAllSnapshots, /* 0.9.13 */
16598 16599
    .domainSnapshotNumChildren = qemuDomainSnapshotNumChildren, /* 0.9.7 */
    .domainSnapshotListChildrenNames = qemuDomainSnapshotListChildrenNames, /* 0.9.7 */
16600
    .domainSnapshotListAllChildren = qemuDomainSnapshotListAllChildren, /* 0.9.13 */
16601 16602
    .domainSnapshotLookupByName = qemuDomainSnapshotLookupByName, /* 0.8.0 */
    .domainHasCurrentSnapshot = qemuDomainHasCurrentSnapshot, /* 0.8.0 */
16603
    .domainSnapshotGetParent = qemuDomainSnapshotGetParent, /* 0.9.7 */
16604
    .domainSnapshotCurrent = qemuDomainSnapshotCurrent, /* 0.8.0 */
16605 16606
    .domainSnapshotIsCurrent = qemuDomainSnapshotIsCurrent, /* 0.9.13 */
    .domainSnapshotHasMetadata = qemuDomainSnapshotHasMetadata, /* 0.9.13 */
16607 16608
    .domainRevertToSnapshot = qemuDomainRevertToSnapshot, /* 0.8.0 */
    .domainSnapshotDelete = qemuDomainSnapshotDelete, /* 0.8.0 */
16609 16610 16611
    .domainQemuMonitorCommand = qemuDomainQemuMonitorCommand, /* 0.8.3 */
    .domainQemuAttach = qemuDomainQemuAttach, /* 0.9.4 */
    .domainQemuAgentCommand = qemuDomainQemuAgentCommand, /* 0.10.0 */
16612
    .domainOpenConsole = qemuDomainOpenConsole, /* 0.8.6 */
16613
    .domainOpenGraphics = qemuDomainOpenGraphics, /* 0.9.7 */
16614
    .domainInjectNMI = qemuDomainInjectNMI, /* 0.9.2 */
16615 16616 16617 16618 16619 16620
    .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 */
16621
    .domainSendKey = qemuDomainSendKey, /* 0.9.4 */
16622 16623 16624 16625
    .domainBlockJobAbort = qemuDomainBlockJobAbort, /* 0.9.4 */
    .domainGetBlockJobInfo = qemuDomainGetBlockJobInfo, /* 0.9.4 */
    .domainBlockJobSetSpeed = qemuDomainBlockJobSetSpeed, /* 0.9.4 */
    .domainBlockPull = qemuDomainBlockPull, /* 0.9.4 */
16626
    .domainBlockRebase = qemuDomainBlockRebase, /* 0.9.10 */
16627
    .domainBlockCommit = qemuDomainBlockCommit, /* 1.0.0 */
16628
    .connectIsAlive = qemuConnectIsAlive, /* 0.9.8 */
16629
    .nodeSuspendForDuration = qemuNodeSuspendForDuration, /* 0.9.8 */
16630 16631
    .domainSetBlockIoTune = qemuDomainSetBlockIoTune, /* 0.9.8 */
    .domainGetBlockIoTune = qemuDomainGetBlockIoTune, /* 0.9.8 */
16632 16633
    .domainSetNumaParameters = qemuDomainSetNumaParameters, /* 0.9.9 */
    .domainGetNumaParameters = qemuDomainGetNumaParameters, /* 0.9.9 */
16634 16635
    .domainGetInterfaceParameters = qemuDomainGetInterfaceParameters, /* 0.9.9 */
    .domainSetInterfaceParameters = qemuDomainSetInterfaceParameters, /* 0.9.9 */
16636
    .domainGetDiskErrors = qemuDomainGetDiskErrors, /* 0.9.10 */
16637 16638
    .domainSetMetadata = qemuDomainSetMetadata, /* 0.9.10 */
    .domainGetMetadata = qemuDomainGetMetadata, /* 0.9.10 */
16639
    .domainPMSuspendForDuration = qemuDomainPMSuspendForDuration, /* 0.9.11 */
16640
    .domainPMWakeup = qemuDomainPMWakeup, /* 0.9.11 */
16641
    .domainGetCPUStats = qemuDomainGetCPUStats, /* 0.9.11 */
16642 16643 16644
    .nodeGetMemoryParameters = qemuNodeGetMemoryParameters, /* 0.10.2 */
    .nodeSetMemoryParameters = qemuNodeSetMemoryParameters, /* 0.10.2 */
    .nodeGetCPUMap = qemuNodeGetCPUMap, /* 1.0.0 */
M
Michal Privoznik 已提交
16645
    .domainFSTrim = qemuDomainFSTrim, /* 1.0.1 */
16646
    .domainOpenChannel = qemuDomainOpenChannel, /* 1.0.2 */
16647 16648 16649 16650 16651 16652
    .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 */
16653
    .connectGetCPUModelNames = qemuConnectGetCPUModelNames, /* 1.1.3 */
16654 16655 16656
};


16657
static virStateDriver qemuStateDriver = {
16658
    .name = "QEMU",
16659
    .stateInitialize = qemuStateInitialize,
16660
    .stateAutoStart = qemuStateAutoStart,
16661 16662 16663
    .stateCleanup = qemuStateCleanup,
    .stateReload = qemuStateReload,
    .stateStop = qemuStateStop,
16664
};
16665

16666
int qemuRegister(void) {
16667 16668 16669 16670
    virRegisterDriver(&qemuDriver);
    virRegisterStateDriver(&qemuStateDriver);
    return 0;
}